deps: update v8 to 4.3.61.21
authorChris Dickinson <christopher.s.dickinson@gmail.com>
Tue, 5 May 2015 20:48:55 +0000 (13:48 -0700)
committerRod Vagg <rod@vagg.org>
Tue, 4 Aug 2015 18:56:09 +0000 (11:56 -0700)
* @indutny's SealHandleScope patch (484bebc38319fc7c622478037922ad73b2edcbf9)
  has been cherry picked onto the top of V8 to make it compile.
* There's some test breakage in contextify.
* This was merged at the request of the TC.

PR-URL: https://github.com/iojs/io.js/pull/1632

822 files changed:
deps/v8/.gitignore
deps/v8/AUTHORS
deps/v8/BUILD.gn
deps/v8/ChangeLog
deps/v8/DEPS
deps/v8/Makefile
deps/v8/Makefile.android
deps/v8/PRESUBMIT.py
deps/v8/README.md
deps/v8/build/android.gypi
deps/v8/build/detect_v8_host_arch.py
deps/v8/build/features.gypi
deps/v8/build/get_landmines.py
deps/v8/build/gyp_environment.py [new file with mode: 0644]
deps/v8/build/gyp_v8
deps/v8/build/landmine_utils.py
deps/v8/build/landmines.py
deps/v8/build/standalone.gypi
deps/v8/build/toolchain.gypi
deps/v8/include/v8-debug.h
deps/v8/include/v8-profiler.h
deps/v8/include/v8-util.h
deps/v8/include/v8-version.h
deps/v8/include/v8.h
deps/v8/include/v8config.h
deps/v8/src/DEPS
deps/v8/src/accessors.cc
deps/v8/src/api-natives.cc
deps/v8/src/api.cc
deps/v8/src/api.h
deps/v8/src/arm/assembler-arm-inl.h
deps/v8/src/arm/assembler-arm.cc
deps/v8/src/arm/assembler-arm.h
deps/v8/src/arm/builtins-arm.cc
deps/v8/src/arm/code-stubs-arm.cc
deps/v8/src/arm/cpu-arm.cc
deps/v8/src/arm/debug-arm.cc
deps/v8/src/arm/deoptimizer-arm.cc
deps/v8/src/arm/disasm-arm.cc
deps/v8/src/arm/frames-arm.h
deps/v8/src/arm/full-codegen-arm.cc
deps/v8/src/arm/interface-descriptors-arm.cc
deps/v8/src/arm/lithium-arm.cc
deps/v8/src/arm/lithium-arm.h
deps/v8/src/arm/lithium-codegen-arm.cc
deps/v8/src/arm/macro-assembler-arm.cc
deps/v8/src/arm/macro-assembler-arm.h
deps/v8/src/arm/simulator-arm.cc
deps/v8/src/arm64/assembler-arm64-inl.h
deps/v8/src/arm64/assembler-arm64.cc
deps/v8/src/arm64/assembler-arm64.h
deps/v8/src/arm64/builtins-arm64.cc
deps/v8/src/arm64/code-stubs-arm64.cc
deps/v8/src/arm64/debug-arm64.cc
deps/v8/src/arm64/deoptimizer-arm64.cc
deps/v8/src/arm64/frames-arm64.h
deps/v8/src/arm64/full-codegen-arm64.cc
deps/v8/src/arm64/instructions-arm64.cc
deps/v8/src/arm64/instructions-arm64.h
deps/v8/src/arm64/interface-descriptors-arm64.cc
deps/v8/src/arm64/lithium-arm64.cc
deps/v8/src/arm64/lithium-arm64.h
deps/v8/src/arm64/lithium-codegen-arm64.cc
deps/v8/src/arm64/lithium-codegen-arm64.h
deps/v8/src/arm64/macro-assembler-arm64.cc
deps/v8/src/arm64/macro-assembler-arm64.h
deps/v8/src/array.js
deps/v8/src/arraybuffer.js
deps/v8/src/assembler.cc
deps/v8/src/assembler.h
deps/v8/src/ast-numbering.cc
deps/v8/src/ast-value-factory.h
deps/v8/src/ast.cc
deps/v8/src/ast.h
deps/v8/src/background-parsing-task.cc
deps/v8/src/background-parsing-task.h
deps/v8/src/bailout-reason.h
deps/v8/src/base/bits.h
deps/v8/src/base/cpu.cc
deps/v8/src/base/logging.cc
deps/v8/src/base/platform/platform-freebsd.cc
deps/v8/src/base/platform/platform-posix.cc
deps/v8/src/base/platform/platform-win32.cc
deps/v8/src/base/platform/platform.h
deps/v8/src/bootstrapper.cc
deps/v8/src/builtins.cc
deps/v8/src/builtins.h
deps/v8/src/char-predicates-inl.h
deps/v8/src/char-predicates.h
deps/v8/src/code-factory.cc
deps/v8/src/code-factory.h
deps/v8/src/code-stubs-hydrogen.cc
deps/v8/src/code-stubs.cc
deps/v8/src/code-stubs.h
deps/v8/src/codegen.cc
deps/v8/src/collection.js
deps/v8/src/compilation-cache.cc
deps/v8/src/compiler.cc
deps/v8/src/compiler.h
deps/v8/src/compiler/access-builder.cc
deps/v8/src/compiler/access-builder.h
deps/v8/src/compiler/all-nodes.cc
deps/v8/src/compiler/all-nodes.h
deps/v8/src/compiler/arm/code-generator-arm.cc
deps/v8/src/compiler/arm/instruction-codes-arm.h
deps/v8/src/compiler/arm/instruction-selector-arm.cc
deps/v8/src/compiler/arm/linkage-arm.cc
deps/v8/src/compiler/arm64/code-generator-arm64.cc
deps/v8/src/compiler/arm64/instruction-codes-arm64.h
deps/v8/src/compiler/arm64/instruction-selector-arm64.cc
deps/v8/src/compiler/arm64/linkage-arm64.cc
deps/v8/src/compiler/ast-graph-builder.cc
deps/v8/src/compiler/ast-graph-builder.h
deps/v8/src/compiler/ast-loop-assignment-analyzer.cc
deps/v8/src/compiler/basic-block-instrumentor.cc
deps/v8/src/compiler/change-lowering.cc
deps/v8/src/compiler/change-lowering.h
deps/v8/src/compiler/code-generator-impl.h
deps/v8/src/compiler/code-generator.cc
deps/v8/src/compiler/code-generator.h
deps/v8/src/compiler/common-operator-reducer.cc
deps/v8/src/compiler/common-operator-reducer.h
deps/v8/src/compiler/common-operator.cc
deps/v8/src/compiler/common-operator.h
deps/v8/src/compiler/control-builders.cc
deps/v8/src/compiler/control-builders.h
deps/v8/src/compiler/control-equivalence.h
deps/v8/src/compiler/control-flow-optimizer.cc
deps/v8/src/compiler/control-flow-optimizer.h
deps/v8/src/compiler/control-reducer.cc
deps/v8/src/compiler/generic-algorithm.h [deleted file]
deps/v8/src/compiler/graph-inl.h [deleted file]
deps/v8/src/compiler/graph-visualizer.cc
deps/v8/src/compiler/ia32/code-generator-ia32.cc
deps/v8/src/compiler/ia32/instruction-codes-ia32.h
deps/v8/src/compiler/ia32/instruction-selector-ia32.cc
deps/v8/src/compiler/ia32/linkage-ia32.cc
deps/v8/src/compiler/instruction-codes.h
deps/v8/src/compiler/instruction-selector-impl.h
deps/v8/src/compiler/instruction-selector.cc
deps/v8/src/compiler/instruction-selector.h
deps/v8/src/compiler/instruction.cc
deps/v8/src/compiler/instruction.h
deps/v8/src/compiler/js-builtin-reducer.cc
deps/v8/src/compiler/js-builtin-reducer.h
deps/v8/src/compiler/js-generic-lowering.cc
deps/v8/src/compiler/js-generic-lowering.h
deps/v8/src/compiler/js-graph.cc
deps/v8/src/compiler/js-inlining.cc
deps/v8/src/compiler/js-inlining.h
deps/v8/src/compiler/js-intrinsic-lowering.cc
deps/v8/src/compiler/js-intrinsic-lowering.h
deps/v8/src/compiler/js-operator.cc
deps/v8/src/compiler/js-operator.h
deps/v8/src/compiler/js-type-feedback.cc [new file with mode: 0644]
deps/v8/src/compiler/js-type-feedback.h [new file with mode: 0644]
deps/v8/src/compiler/js-typed-lowering.cc
deps/v8/src/compiler/js-typed-lowering.h
deps/v8/src/compiler/jump-threading.cc
deps/v8/src/compiler/jump-threading.h
deps/v8/src/compiler/linkage-impl.h
deps/v8/src/compiler/linkage.cc
deps/v8/src/compiler/linkage.h
deps/v8/src/compiler/liveness-analyzer.cc [new file with mode: 0644]
deps/v8/src/compiler/liveness-analyzer.h [new file with mode: 0644]
deps/v8/src/compiler/machine-operator-reducer.cc
deps/v8/src/compiler/machine-operator-reducer.h
deps/v8/src/compiler/machine-operator.cc
deps/v8/src/compiler/machine-operator.h
deps/v8/src/compiler/mips/code-generator-mips.cc
deps/v8/src/compiler/mips/instruction-codes-mips.h
deps/v8/src/compiler/mips/instruction-selector-mips.cc
deps/v8/src/compiler/mips/linkage-mips.cc
deps/v8/src/compiler/mips64/code-generator-mips64.cc
deps/v8/src/compiler/mips64/instruction-codes-mips64.h
deps/v8/src/compiler/mips64/instruction-selector-mips64.cc
deps/v8/src/compiler/mips64/linkage-mips64.cc
deps/v8/src/compiler/move-optimizer.cc
deps/v8/src/compiler/move-optimizer.h
deps/v8/src/compiler/node-matchers.cc [new file with mode: 0644]
deps/v8/src/compiler/node-matchers.h
deps/v8/src/compiler/node-properties.cc
deps/v8/src/compiler/node-properties.h
deps/v8/src/compiler/node.cc
deps/v8/src/compiler/node.h
deps/v8/src/compiler/opcodes.h
deps/v8/src/compiler/operator-properties.cc
deps/v8/src/compiler/operator-properties.h
deps/v8/src/compiler/operator.h
deps/v8/src/compiler/osr.cc
deps/v8/src/compiler/pipeline.cc
deps/v8/src/compiler/ppc/OWNERS [new file with mode: 0644]
deps/v8/src/compiler/ppc/code-generator-ppc.cc
deps/v8/src/compiler/ppc/instruction-codes-ppc.h
deps/v8/src/compiler/ppc/instruction-selector-ppc.cc
deps/v8/src/compiler/ppc/linkage-ppc.cc
deps/v8/src/compiler/raw-machine-assembler.h
deps/v8/src/compiler/register-allocator-verifier.cc
deps/v8/src/compiler/register-allocator-verifier.h
deps/v8/src/compiler/register-allocator.cc
deps/v8/src/compiler/register-allocator.h
deps/v8/src/compiler/schedule.cc
deps/v8/src/compiler/schedule.h
deps/v8/src/compiler/scheduler.cc
deps/v8/src/compiler/simplified-lowering.cc
deps/v8/src/compiler/simplified-operator-reducer.cc
deps/v8/src/compiler/simplified-operator-reducer.h
deps/v8/src/compiler/simplified-operator.cc
deps/v8/src/compiler/simplified-operator.h
deps/v8/src/compiler/state-values-utils.cc [new file with mode: 0644]
deps/v8/src/compiler/state-values-utils.h [new file with mode: 0644]
deps/v8/src/compiler/typer.cc
deps/v8/src/compiler/typer.h
deps/v8/src/compiler/verifier.cc
deps/v8/src/compiler/x64/code-generator-x64.cc
deps/v8/src/compiler/x64/instruction-codes-x64.h
deps/v8/src/compiler/x64/instruction-selector-x64.cc
deps/v8/src/compiler/x64/linkage-x64.cc
deps/v8/src/contexts.cc
deps/v8/src/contexts.h
deps/v8/src/conversions.cc
deps/v8/src/conversions.h
deps/v8/src/counters.h
deps/v8/src/cpu-profiler-inl.h
deps/v8/src/cpu-profiler.cc
deps/v8/src/cpu-profiler.h
deps/v8/src/d8.cc
deps/v8/src/date.js
deps/v8/src/debug-debugger.js
deps/v8/src/debug.cc
deps/v8/src/debug.h
deps/v8/src/deoptimizer.cc
deps/v8/src/deoptimizer.h
deps/v8/src/disassembler.cc
deps/v8/src/elements.cc
deps/v8/src/execution.cc
deps/v8/src/execution.h
deps/v8/src/extensions/statistics-extension.cc
deps/v8/src/factory.cc
deps/v8/src/factory.h
deps/v8/src/flag-definitions.h
deps/v8/src/flags.cc
deps/v8/src/flags.h
deps/v8/src/frames-inl.h
deps/v8/src/frames.cc
deps/v8/src/frames.h
deps/v8/src/full-codegen.cc
deps/v8/src/full-codegen.h
deps/v8/src/gdb-jit.cc
deps/v8/src/gdb-jit.h
deps/v8/src/global-handles.cc
deps/v8/src/global-handles.h
deps/v8/src/globals.h
deps/v8/src/harmony-array.js
deps/v8/src/harmony-reflect.js [new file with mode: 0644]
deps/v8/src/harmony-string.js [deleted file]
deps/v8/src/harmony-tostring.js
deps/v8/src/heap-profiler.cc
deps/v8/src/heap-profiler.h
deps/v8/src/heap-snapshot-generator.cc
deps/v8/src/heap-snapshot-generator.h
deps/v8/src/heap/gc-idle-time-handler.cc
deps/v8/src/heap/gc-idle-time-handler.h
deps/v8/src/heap/heap-inl.h
deps/v8/src/heap/heap.cc
deps/v8/src/heap/heap.h
deps/v8/src/heap/incremental-marking.cc
deps/v8/src/heap/incremental-marking.h
deps/v8/src/heap/mark-compact.cc
deps/v8/src/heap/mark-compact.h
deps/v8/src/heap/objects-visiting-inl.h
deps/v8/src/heap/objects-visiting.cc
deps/v8/src/heap/objects-visiting.h
deps/v8/src/heap/spaces.cc
deps/v8/src/heap/spaces.h
deps/v8/src/heap/store-buffer-inl.h
deps/v8/src/heap/store-buffer.cc
deps/v8/src/heap/store-buffer.h
deps/v8/src/hydrogen-bce.cc
deps/v8/src/hydrogen-gvn.cc
deps/v8/src/hydrogen-gvn.h
deps/v8/src/hydrogen-instructions.cc
deps/v8/src/hydrogen-instructions.h
deps/v8/src/hydrogen-representation-changes.cc
deps/v8/src/hydrogen.cc
deps/v8/src/hydrogen.h
deps/v8/src/i18n.cc
deps/v8/src/i18n.js
deps/v8/src/ia32/assembler-ia32-inl.h
deps/v8/src/ia32/assembler-ia32.cc
deps/v8/src/ia32/assembler-ia32.h
deps/v8/src/ia32/builtins-ia32.cc
deps/v8/src/ia32/code-stubs-ia32.cc
deps/v8/src/ia32/debug-ia32.cc
deps/v8/src/ia32/deoptimizer-ia32.cc
deps/v8/src/ia32/disasm-ia32.cc
deps/v8/src/ia32/frames-ia32.h
deps/v8/src/ia32/full-codegen-ia32.cc
deps/v8/src/ia32/interface-descriptors-ia32.cc
deps/v8/src/ia32/lithium-codegen-ia32.cc
deps/v8/src/ia32/lithium-ia32.cc
deps/v8/src/ia32/lithium-ia32.h
deps/v8/src/ia32/macro-assembler-ia32.cc
deps/v8/src/ia32/macro-assembler-ia32.h
deps/v8/src/ic/arm/handler-compiler-arm.cc
deps/v8/src/ic/arm64/handler-compiler-arm64.cc
deps/v8/src/ic/handler-compiler.cc
deps/v8/src/ic/ia32/handler-compiler-ia32.cc
deps/v8/src/ic/ic-compiler.cc
deps/v8/src/ic/ic-compiler.h
deps/v8/src/ic/ic-state.cc
deps/v8/src/ic/ic-state.h
deps/v8/src/ic/ic.cc
deps/v8/src/ic/ic.h
deps/v8/src/ic/mips/handler-compiler-mips.cc
deps/v8/src/ic/mips64/handler-compiler-mips64.cc
deps/v8/src/ic/mips64/ic-mips64.cc
deps/v8/src/ic/ppc/OWNERS [new file with mode: 0644]
deps/v8/src/ic/ppc/handler-compiler-ppc.cc
deps/v8/src/ic/ppc/ic-compiler-ppc.cc
deps/v8/src/ic/stub-cache.cc
deps/v8/src/ic/x64/handler-compiler-x64.cc
deps/v8/src/ic/x87/handler-compiler-x87.cc
deps/v8/src/interface-descriptors.h
deps/v8/src/isolate.cc
deps/v8/src/isolate.h
deps/v8/src/json-parser.h
deps/v8/src/json-stringifier.h
deps/v8/src/json.js
deps/v8/src/jsregexp.cc
deps/v8/src/layout-descriptor-inl.h
deps/v8/src/layout-descriptor.cc
deps/v8/src/layout-descriptor.h
deps/v8/src/lithium-codegen.cc
deps/v8/src/lithium-codegen.h
deps/v8/src/lithium.cc
deps/v8/src/liveedit.cc
deps/v8/src/log.cc
deps/v8/src/log.h
deps/v8/src/lookup-inl.h
deps/v8/src/lookup.cc
deps/v8/src/lookup.h
deps/v8/src/macros.py
deps/v8/src/math.js
deps/v8/src/messages.js
deps/v8/src/mips/assembler-mips-inl.h
deps/v8/src/mips/assembler-mips.cc
deps/v8/src/mips/assembler-mips.h
deps/v8/src/mips/builtins-mips.cc
deps/v8/src/mips/code-stubs-mips.cc
deps/v8/src/mips/debug-mips.cc
deps/v8/src/mips/deoptimizer-mips.cc
deps/v8/src/mips/frames-mips.h
deps/v8/src/mips/full-codegen-mips.cc
deps/v8/src/mips/interface-descriptors-mips.cc
deps/v8/src/mips/lithium-codegen-mips.cc
deps/v8/src/mips/lithium-mips.cc
deps/v8/src/mips/lithium-mips.h
deps/v8/src/mips/macro-assembler-mips.cc
deps/v8/src/mips/macro-assembler-mips.h
deps/v8/src/mips/simulator-mips.cc
deps/v8/src/mips64/assembler-mips64-inl.h
deps/v8/src/mips64/assembler-mips64.cc
deps/v8/src/mips64/assembler-mips64.h
deps/v8/src/mips64/builtins-mips64.cc
deps/v8/src/mips64/code-stubs-mips64.cc
deps/v8/src/mips64/debug-mips64.cc
deps/v8/src/mips64/deoptimizer-mips64.cc
deps/v8/src/mips64/frames-mips64.h
deps/v8/src/mips64/full-codegen-mips64.cc
deps/v8/src/mips64/interface-descriptors-mips64.cc
deps/v8/src/mips64/lithium-codegen-mips64.cc
deps/v8/src/mips64/lithium-mips64.cc
deps/v8/src/mips64/lithium-mips64.h
deps/v8/src/mips64/macro-assembler-mips64.cc
deps/v8/src/mips64/macro-assembler-mips64.h
deps/v8/src/mips64/simulator-mips64.cc
deps/v8/src/mirror-debugger.js
deps/v8/src/modules.cc
deps/v8/src/modules.h
deps/v8/src/object-observe.js
deps/v8/src/objects-debug.cc
deps/v8/src/objects-inl.h
deps/v8/src/objects-printer.cc
deps/v8/src/objects.cc
deps/v8/src/objects.h
deps/v8/src/optimizing-compiler-thread.cc
deps/v8/src/optimizing-compiler-thread.h
deps/v8/src/parser.cc
deps/v8/src/parser.h
deps/v8/src/pending-compilation-error-handler.cc [new file with mode: 0644]
deps/v8/src/pending-compilation-error-handler.h [new file with mode: 0644]
deps/v8/src/ppc/OWNERS [new file with mode: 0644]
deps/v8/src/ppc/assembler-ppc-inl.h
deps/v8/src/ppc/assembler-ppc.cc
deps/v8/src/ppc/assembler-ppc.h
deps/v8/src/ppc/builtins-ppc.cc
deps/v8/src/ppc/code-stubs-ppc.cc
deps/v8/src/ppc/codegen-ppc.cc
deps/v8/src/ppc/debug-ppc.cc
deps/v8/src/ppc/deoptimizer-ppc.cc
deps/v8/src/ppc/disasm-ppc.cc
deps/v8/src/ppc/frames-ppc.cc
deps/v8/src/ppc/frames-ppc.h
deps/v8/src/ppc/full-codegen-ppc.cc
deps/v8/src/ppc/interface-descriptors-ppc.cc
deps/v8/src/ppc/lithium-codegen-ppc.cc
deps/v8/src/ppc/lithium-ppc.cc
deps/v8/src/ppc/lithium-ppc.h
deps/v8/src/ppc/macro-assembler-ppc.cc
deps/v8/src/ppc/macro-assembler-ppc.h
deps/v8/src/ppc/simulator-ppc.cc
deps/v8/src/preparse-data-format.h
deps/v8/src/preparse-data.cc
deps/v8/src/preparse-data.h
deps/v8/src/preparser.cc
deps/v8/src/preparser.h
deps/v8/src/prettyprinter.cc
deps/v8/src/profile-generator-inl.h
deps/v8/src/profile-generator.cc
deps/v8/src/profile-generator.h
deps/v8/src/promise.js
deps/v8/src/property-details.h
deps/v8/src/property.h
deps/v8/src/regexp.js
deps/v8/src/rewriter.cc
deps/v8/src/rewriter.h
deps/v8/src/runtime.js
deps/v8/src/runtime/runtime-array.cc
deps/v8/src/runtime/runtime-classes.cc
deps/v8/src/runtime/runtime-compiler.cc
deps/v8/src/runtime/runtime-date.cc
deps/v8/src/runtime/runtime-debug.cc
deps/v8/src/runtime/runtime-function.cc
deps/v8/src/runtime/runtime-generator.cc
deps/v8/src/runtime/runtime-internal.cc
deps/v8/src/runtime/runtime-literals.cc
deps/v8/src/runtime/runtime-liveedit.cc
deps/v8/src/runtime/runtime-maths.cc
deps/v8/src/runtime/runtime-numbers.cc
deps/v8/src/runtime/runtime-object.cc
deps/v8/src/runtime/runtime-proxy.cc
deps/v8/src/runtime/runtime-regexp.cc
deps/v8/src/runtime/runtime-scopes.cc
deps/v8/src/runtime/runtime-strings.cc
deps/v8/src/runtime/runtime-test.cc
deps/v8/src/runtime/runtime-typedarray.cc
deps/v8/src/runtime/runtime.cc
deps/v8/src/runtime/runtime.h
deps/v8/src/scanner.cc
deps/v8/src/scanner.h
deps/v8/src/scopeinfo.cc
deps/v8/src/scopes.cc
deps/v8/src/scopes.h
deps/v8/src/snapshot/DEPS [new file with mode: 0644]
deps/v8/src/snapshot/mksnapshot.cc [moved from deps/v8/src/mksnapshot.cc with 89% similarity]
deps/v8/src/snapshot/natives-external.cc [moved from deps/v8/src/natives-external.cc with 84% similarity]
deps/v8/src/snapshot/natives.h [moved from deps/v8/src/natives.h with 96% similarity]
deps/v8/src/snapshot/serialize.cc [moved from deps/v8/src/serialize.cc with 82% similarity]
deps/v8/src/snapshot/serialize.h [moved from deps/v8/src/serialize.h with 78% similarity]
deps/v8/src/snapshot/snapshot-common.cc [moved from deps/v8/src/snapshot-common.cc with 79% similarity]
deps/v8/src/snapshot/snapshot-empty.cc [moved from deps/v8/src/snapshot-empty.cc with 83% similarity]
deps/v8/src/snapshot/snapshot-external.cc [moved from deps/v8/src/snapshot-external.cc with 84% similarity]
deps/v8/src/snapshot/snapshot-source-sink.cc [moved from deps/v8/src/snapshot-source-sink.cc with 79% similarity]
deps/v8/src/snapshot/snapshot-source-sink.h [moved from deps/v8/src/snapshot-source-sink.h with 87% similarity]
deps/v8/src/snapshot/snapshot.h [moved from deps/v8/src/snapshot.h with 86% similarity]
deps/v8/src/string-iterator.js
deps/v8/src/string.js
deps/v8/src/strings-storage.cc [new file with mode: 0644]
deps/v8/src/strings-storage.h [new file with mode: 0644]
deps/v8/src/symbol.js
deps/v8/src/templates.js [moved from deps/v8/src/harmony-templates.js with 62% similarity]
deps/v8/src/third_party/fdlibm/fdlibm.js
deps/v8/src/token.h
deps/v8/src/transitions-inl.h
deps/v8/src/transitions.cc
deps/v8/src/transitions.h
deps/v8/src/type-feedback-vector.cc
deps/v8/src/type-feedback-vector.h
deps/v8/src/type-info.cc
deps/v8/src/type-info.h
deps/v8/src/typedarray.js
deps/v8/src/types.cc
deps/v8/src/types.h
deps/v8/src/typing.cc
deps/v8/src/unique.h
deps/v8/src/utils.h
deps/v8/src/v8.cc
deps/v8/src/v8natives.js
deps/v8/src/variables.cc
deps/v8/src/variables.h
deps/v8/src/weak-collection.js
deps/v8/src/x64/assembler-x64-inl.h
deps/v8/src/x64/assembler-x64.cc
deps/v8/src/x64/assembler-x64.h
deps/v8/src/x64/builtins-x64.cc
deps/v8/src/x64/code-stubs-x64.cc
deps/v8/src/x64/debug-x64.cc
deps/v8/src/x64/deoptimizer-x64.cc
deps/v8/src/x64/disasm-x64.cc
deps/v8/src/x64/frames-x64.h
deps/v8/src/x64/full-codegen-x64.cc
deps/v8/src/x64/interface-descriptors-x64.cc
deps/v8/src/x64/lithium-codegen-x64.cc
deps/v8/src/x64/lithium-x64.cc
deps/v8/src/x64/lithium-x64.h
deps/v8/src/x64/macro-assembler-x64.cc
deps/v8/src/x64/macro-assembler-x64.h
deps/v8/src/x64/regexp-macro-assembler-x64.cc
deps/v8/src/x87/assembler-x87-inl.h
deps/v8/src/x87/assembler-x87.cc
deps/v8/src/x87/assembler-x87.h
deps/v8/src/x87/builtins-x87.cc
deps/v8/src/x87/code-stubs-x87.cc
deps/v8/src/x87/debug-x87.cc
deps/v8/src/x87/deoptimizer-x87.cc
deps/v8/src/x87/frames-x87.h
deps/v8/src/x87/full-codegen-x87.cc
deps/v8/src/x87/interface-descriptors-x87.cc
deps/v8/src/x87/lithium-codegen-x87.cc
deps/v8/src/x87/lithium-x87.cc
deps/v8/src/x87/lithium-x87.h
deps/v8/src/x87/macro-assembler-x87.cc
deps/v8/src/x87/macro-assembler-x87.h
deps/v8/test/cctest/cctest.gyp
deps/v8/test/cctest/cctest.h
deps/v8/test/cctest/cctest.status
deps/v8/test/cctest/compiler/call-tester.h
deps/v8/test/cctest/compiler/function-tester.h
deps/v8/test/cctest/compiler/simplified-graph-builder.cc
deps/v8/test/cctest/compiler/test-codegen-deopt.cc
deps/v8/test/cctest/compiler/test-control-reducer.cc
deps/v8/test/cctest/compiler/test-instruction.cc
deps/v8/test/cctest/compiler/test-js-typed-lowering.cc
deps/v8/test/cctest/compiler/test-jump-threading.cc
deps/v8/test/cctest/compiler/test-linkage.cc
deps/v8/test/cctest/compiler/test-loop-assignment-analysis.cc
deps/v8/test/cctest/compiler/test-machine-operator-reducer.cc
deps/v8/test/cctest/compiler/test-node-algorithm.cc
deps/v8/test/cctest/compiler/test-node.cc
deps/v8/test/cctest/compiler/test-osr.cc
deps/v8/test/cctest/compiler/test-pipeline.cc
deps/v8/test/cctest/compiler/test-run-inlining.cc
deps/v8/test/cctest/compiler/test-run-intrinsics.cc
deps/v8/test/cctest/compiler/test-run-jsexceptions.cc
deps/v8/test/cctest/compiler/test-run-jsops.cc
deps/v8/test/cctest/compiler/test-run-machops.cc
deps/v8/test/cctest/compiler/test-run-stubs.cc [new file with mode: 0644]
deps/v8/test/cctest/compiler/test-run-variables.cc
deps/v8/test/cctest/compiler/test-simplified-lowering.cc
deps/v8/test/cctest/test-accessors.cc
deps/v8/test/cctest/test-alloc.cc
deps/v8/test/cctest/test-api-interceptors.cc
deps/v8/test/cctest/test-api.cc
deps/v8/test/cctest/test-array-list.cc [new file with mode: 0644]
deps/v8/test/cctest/test-assembler-arm64.cc
deps/v8/test/cctest/test-assembler-ia32.cc
deps/v8/test/cctest/test-assembler-mips64.cc
deps/v8/test/cctest/test-assembler-x64.cc
deps/v8/test/cctest/test-assembler-x87.cc
deps/v8/test/cctest/test-compiler.cc
deps/v8/test/cctest/test-constantpool.cc
deps/v8/test/cctest/test-conversions.cc
deps/v8/test/cctest/test-cpu-profiler.cc
deps/v8/test/cctest/test-date.cc
deps/v8/test/cctest/test-debug.cc
deps/v8/test/cctest/test-decls.cc
deps/v8/test/cctest/test-disasm-arm.cc
deps/v8/test/cctest/test-disasm-ia32.cc
deps/v8/test/cctest/test-disasm-mips.cc
deps/v8/test/cctest/test-disasm-mips64.cc
deps/v8/test/cctest/test-disasm-ppc.cc
deps/v8/test/cctest/test-disasm-x64.cc
deps/v8/test/cctest/test-disasm-x87.cc
deps/v8/test/cctest/test-feedback-vector.cc
deps/v8/test/cctest/test-func-name-inference.cc
deps/v8/test/cctest/test-heap-profiler.cc
deps/v8/test/cctest/test-heap.cc
deps/v8/test/cctest/test-javascript-arm64.cc
deps/v8/test/cctest/test-js-arm64-variables.cc
deps/v8/test/cctest/test-lockers.cc
deps/v8/test/cctest/test-log.cc
deps/v8/test/cctest/test-macro-assembler-ia32.cc
deps/v8/test/cctest/test-macro-assembler-x64.cc
deps/v8/test/cctest/test-macro-assembler-x87.cc
deps/v8/test/cctest/test-mark-compact.cc
deps/v8/test/cctest/test-mementos.cc
deps/v8/test/cctest/test-migrations.cc
deps/v8/test/cctest/test-parsing.cc
deps/v8/test/cctest/test-serialize.cc
deps/v8/test/cctest/test-spaces.cc
deps/v8/test/cctest/test-strings.cc
deps/v8/test/cctest/test-thread-termination.cc
deps/v8/test/cctest/test-transitions.cc
deps/v8/test/cctest/test-typedarrays.cc [new file with mode: 0644]
deps/v8/test/cctest/test-unboxed-doubles.cc
deps/v8/test/cctest/test-weakmaps.cc
deps/v8/test/cctest/test-weaksets.cc
deps/v8/test/cctest/test-weaktypedarrays.cc
deps/v8/test/js-perf-test/JSTests.json
deps/v8/test/message/class-constructor-accessor.js [moved from deps/v8/test/mjsunit/harmony/disable-harmony-string.js with 66% similarity]
deps/v8/test/message/class-constructor-accessor.out [new file with mode: 0644]
deps/v8/test/message/class-constructor-generator.js [new file with mode: 0644]
deps/v8/test/message/class-constructor-generator.out [new file with mode: 0644]
deps/v8/test/message/export-duplicate-as.js [new file with mode: 0644]
deps/v8/test/message/export-duplicate-as.out [new file with mode: 0644]
deps/v8/test/message/export-duplicate-default.js [new file with mode: 0644]
deps/v8/test/message/export-duplicate-default.out [new file with mode: 0644]
deps/v8/test/message/export-duplicate.js [new file with mode: 0644]
deps/v8/test/message/export-duplicate.out [new file with mode: 0644]
deps/v8/test/message/import-as-eval.js [new file with mode: 0644]
deps/v8/test/message/import-as-eval.out [new file with mode: 0644]
deps/v8/test/message/import-as-redeclaration.js [new file with mode: 0644]
deps/v8/test/message/import-as-redeclaration.out [new file with mode: 0644]
deps/v8/test/message/import-as-reserved-word.js [new file with mode: 0644]
deps/v8/test/message/import-as-reserved-word.out [new file with mode: 0644]
deps/v8/test/message/import-eval.js [new file with mode: 0644]
deps/v8/test/message/import-eval.out [new file with mode: 0644]
deps/v8/test/message/import-redeclaration.js [new file with mode: 0644]
deps/v8/test/message/import-redeclaration.out [new file with mode: 0644]
deps/v8/test/message/import-reserved-word.js [new file with mode: 0644]
deps/v8/test/message/import-reserved-word.out [new file with mode: 0644]
deps/v8/test/message/testcfg.py
deps/v8/test/message/unterminated-arg-list.js [new file with mode: 0644]
deps/v8/test/message/unterminated-arg-list.out [new file with mode: 0644]
deps/v8/test/mjsunit/asm/construct-double.js [new file with mode: 0644]
deps/v8/test/mjsunit/asm/double-hi.js [new file with mode: 0644]
deps/v8/test/mjsunit/asm/double-lo.js [new file with mode: 0644]
deps/v8/test/mjsunit/asm/if-cloning.js [new file with mode: 0644]
deps/v8/test/mjsunit/asm/math-clz32.js [new file with mode: 0644]
deps/v8/test/mjsunit/bugs/harmony/debug-blockscopes.js
deps/v8/test/mjsunit/compiler/deopt-tonumber-binop.js [new file with mode: 0644]
deps/v8/test/mjsunit/compiler/eager-deopt-simple.js [new file with mode: 0644]
deps/v8/test/mjsunit/compiler/osr-forin-nested.js [new file with mode: 0644]
deps/v8/test/mjsunit/compiler/osr-infinite.js [new file with mode: 0644]
deps/v8/test/mjsunit/compiler/osr-labeled.js [new file with mode: 0644]
deps/v8/test/mjsunit/compiler/osr-literals-adapted.js [new file with mode: 0644]
deps/v8/test/mjsunit/compiler/osr-literals.js [new file with mode: 0644]
deps/v8/test/mjsunit/compiler/regress-463056.js [new file with mode: 0644]
deps/v8/test/mjsunit/compiler/regress-468727.js [new file with mode: 0644]
deps/v8/test/mjsunit/compiler/regress-469089.js [new file with mode: 0644]
deps/v8/test/mjsunit/compiler/truncating-store-deopt.js [new file with mode: 0644]
deps/v8/test/mjsunit/compiler/try-deopt.js [new file with mode: 0644]
deps/v8/test/mjsunit/constant-folding-2.js
deps/v8/test/mjsunit/debug-allscopes-on-debugger.js [new file with mode: 0644]
deps/v8/test/mjsunit/debug-liveedit-check-stack.js
deps/v8/test/mjsunit/debug-references.js
deps/v8/test/mjsunit/debug-scopes.js
deps/v8/test/mjsunit/debug-set-variable-value.js
deps/v8/test/mjsunit/debug-sourceinfo.js
deps/v8/test/mjsunit/debug-step-turbofan.js
deps/v8/test/mjsunit/debug-stepframe-clearing.js [new file with mode: 0644]
deps/v8/test/mjsunit/debug-stepin-foreach.js
deps/v8/test/mjsunit/es6/block-conflicts.js [moved from deps/v8/test/mjsunit/harmony/block-conflicts.js with 99% similarity]
deps/v8/test/mjsunit/es6/block-const-assign.js [new file with mode: 0644]
deps/v8/test/mjsunit/es6/block-early-errors.js [moved from deps/v8/test/mjsunit/harmony/block-early-errors.js with 98% similarity]
deps/v8/test/mjsunit/es6/block-for.js [moved from deps/v8/test/mjsunit/harmony/block-for.js with 99% similarity]
deps/v8/test/mjsunit/es6/block-leave.js [moved from deps/v8/test/mjsunit/harmony/block-leave.js with 99% similarity]
deps/v8/test/mjsunit/es6/block-let-crankshaft.js [moved from deps/v8/test/mjsunit/harmony/block-let-crankshaft.js with 99% similarity]
deps/v8/test/mjsunit/es6/block-let-declaration.js [moved from deps/v8/test/mjsunit/harmony/block-let-declaration.js with 87% similarity]
deps/v8/test/mjsunit/es6/block-let-semantics.js [moved from deps/v8/test/mjsunit/harmony/block-let-semantics.js with 99% similarity]
deps/v8/test/mjsunit/es6/block-non-strict-errors.js [moved from deps/v8/test/mjsunit/harmony/block-non-strict-errors.js with 95% similarity]
deps/v8/test/mjsunit/es6/block-scoping.js [moved from deps/v8/test/mjsunit/harmony/block-scoping.js with 98% similarity]
deps/v8/test/mjsunit/es6/collections.js
deps/v8/test/mjsunit/es6/debug-blockscopes.js [moved from deps/v8/test/mjsunit/harmony/debug-blockscopes.js with 99% similarity]
deps/v8/test/mjsunit/es6/debug-evaluate-blockscopes.js [moved from deps/v8/test/mjsunit/harmony/debug-evaluate-blockscopes.js with 98% similarity]
deps/v8/test/mjsunit/es6/debug-function-scopes.js [moved from deps/v8/test/mjsunit/harmony/debug-function-scopes.js with 98% similarity]
deps/v8/test/mjsunit/es6/debug-promises/resolve-after-aborted-try-finally.js [new file with mode: 0644]
deps/v8/test/mjsunit/es6/debug-promises/resolve-after-try-catch.js [new file with mode: 0644]
deps/v8/test/mjsunit/es6/debug-promises/rethrow-in-try-finally.js [new file with mode: 0644]
deps/v8/test/mjsunit/es6/debug-stepin-promises.js [new file with mode: 0644]
deps/v8/test/mjsunit/es6/empty-for.js [moved from deps/v8/test/mjsunit/harmony/empty-for.js with 98% similarity]
deps/v8/test/mjsunit/es6/function-length-configurable.js [new file with mode: 0644]
deps/v8/test/mjsunit/es6/function-name-configurable.js [new file with mode: 0644]
deps/v8/test/mjsunit/es6/generators-debug-liveedit.js
deps/v8/test/mjsunit/es6/generators-objects.js
deps/v8/test/mjsunit/es6/indexed-integer-exotics.js [new file with mode: 0644]
deps/v8/test/mjsunit/es6/iteration-semantics.js
deps/v8/test/mjsunit/es6/iteration-syntax.js
deps/v8/test/mjsunit/es6/map-minus-zero.js [new file with mode: 0644]
deps/v8/test/mjsunit/es6/promises.js
deps/v8/test/mjsunit/es6/regress/regress-2243.js [moved from deps/v8/test/mjsunit/harmony/regress/regress-2243.js with 98% similarity]
deps/v8/test/mjsunit/es6/regress/regress-2322.js [moved from deps/v8/test/mjsunit/harmony/regress/regress-2322.js with 98% similarity]
deps/v8/test/mjsunit/es6/regress/regress-2506.js [moved from deps/v8/test/mjsunit/regress/regress-2506.js with 97% similarity]
deps/v8/test/mjsunit/es6/regress/regress-2858.js [moved from deps/v8/test/mjsunit/harmony/regress/regress-2858.js with 94% similarity]
deps/v8/test/mjsunit/es6/regress/regress-3426.js [moved from deps/v8/test/mjsunit/harmony/regress/regress-3426.js with 89% similarity]
deps/v8/test/mjsunit/es6/regress/regress-347906.js [moved from deps/v8/test/mjsunit/regress/regress-347906.js with 86% similarity]
deps/v8/test/mjsunit/es6/regress/regress-3683.js [moved from deps/v8/test/mjsunit/harmony/regress/regress-3683.js with 97% similarity]
deps/v8/test/mjsunit/es6/regress/regress-3741.js [moved from deps/v8/test/mjsunit/harmony/regress/regress-3741.js with 89% similarity]
deps/v8/test/mjsunit/es6/regress/regress-3938.js [new file with mode: 0644]
deps/v8/test/mjsunit/es6/regress/regress-411237.js [moved from deps/v8/test/mjsunit/regress/regress-411237.js with 87% similarity]
deps/v8/test/mjsunit/es6/regress/regress-468661.js [new file with mode: 0644]
deps/v8/test/mjsunit/es6/regress/regress-474783.js [new file with mode: 0644]
deps/v8/test/mjsunit/es6/set-minus-zero.js [new file with mode: 0644]
deps/v8/test/mjsunit/es6/string-codepointat.js [moved from deps/v8/test/mjsunit/harmony/string-codepointat.js with 99% similarity]
deps/v8/test/mjsunit/es6/string-endswith.js [moved from deps/v8/test/mjsunit/harmony/string-endswith.js with 99% similarity]
deps/v8/test/mjsunit/es6/string-fromcodepoint.js [moved from deps/v8/test/mjsunit/harmony/string-fromcodepoint.js with 98% similarity]
deps/v8/test/mjsunit/es6/string-includes.js [moved from deps/v8/test/mjsunit/harmony/string-includes.js with 99% similarity]
deps/v8/test/mjsunit/es6/string-raw.js [moved from deps/v8/test/mjsunit/harmony/string-raw.js with 88% similarity]
deps/v8/test/mjsunit/es6/string-repeat.js [moved from deps/v8/test/mjsunit/harmony/string-repeat.js with 99% similarity]
deps/v8/test/mjsunit/es6/string-startswith.js [moved from deps/v8/test/mjsunit/harmony/string-startswith.js with 99% similarity]
deps/v8/test/mjsunit/es6/symbols.js
deps/v8/test/mjsunit/es6/templates.js [moved from deps/v8/test/mjsunit/harmony/templates.js with 80% similarity]
deps/v8/test/mjsunit/es7/object-observe.js
deps/v8/test/mjsunit/function-length-accessor.js
deps/v8/test/mjsunit/function-prototype.js
deps/v8/test/mjsunit/harmony/block-const-assign.js [deleted file]
deps/v8/test/mjsunit/harmony/computed-property-names-classes.js
deps/v8/test/mjsunit/harmony/computed-property-names.js
deps/v8/test/mjsunit/harmony/module-linking.js
deps/v8/test/mjsunit/harmony/module-resolution.js
deps/v8/test/mjsunit/harmony/private.js
deps/v8/test/mjsunit/harmony/reflect-apply.js [new file with mode: 0644]
deps/v8/test/mjsunit/harmony/reflect-construct.js [new file with mode: 0644]
deps/v8/test/mjsunit/harmony/regress/regress-3501.js [moved from deps/v8/test/mjsunit/regress/regress-3501.js with 100% similarity]
deps/v8/test/mjsunit/harmony/regress/regress-crbug-448730.js [moved from deps/v8/test/mjsunit/regress/regress-crbug-448730.js with 100% similarity]
deps/v8/test/mjsunit/harmony/regress/regress-crbug-451770.js [moved from deps/v8/test/mjsunit/regress/regress-crbug-451770.js with 100% similarity]
deps/v8/test/mjsunit/harmony/regress/regress-crbug-461520.js [new file with mode: 0644]
deps/v8/test/mjsunit/harmony/regress/regress-crbug-465671-null.js [new file with mode: 0644]
deps/v8/test/mjsunit/harmony/regress/regress-crbug-465671.js [new file with mode: 0644]
deps/v8/test/mjsunit/harmony/rest-params.js
deps/v8/test/mjsunit/harmony/typedarrays.js
deps/v8/test/mjsunit/json2.js
deps/v8/test/mjsunit/mjsunit.status
deps/v8/test/mjsunit/regexp-stack-overflow.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-1530.js
deps/v8/test/mjsunit/regress/regress-270142.js
deps/v8/test/mjsunit/regress/regress-330046.js
deps/v8/test/mjsunit/regress/regress-3960.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-3969.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-3976.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-3985.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-4023.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-4027.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-430201b.js [moved from deps/v8/test/preparser/strict-const.js with 80% similarity]
deps/v8/test/mjsunit/regress/regress-460937.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-463028.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-469605.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-470804.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-crbug-385002.js
deps/v8/test/mjsunit/regress/regress-crbug-401915.js
deps/v8/test/mjsunit/regress/regress-crbug-465564.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-crbug-467047.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-crbug-467531.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-filter-contexts.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-function-length-strict.js
deps/v8/test/mjsunit/regress/string-compare-memcmp.js
deps/v8/test/mjsunit/stack-traces.js
deps/v8/test/mjsunit/strict-mode.js
deps/v8/test/mjsunit/string-concat.js [new file with mode: 0644]
deps/v8/test/mjsunit/string-index.js
deps/v8/test/mjsunit/strong/arrays.js [new file with mode: 0644]
deps/v8/test/mjsunit/strong/classes.js
deps/v8/test/mjsunit/strong/declaration-after-use.js [new file with mode: 0644]
deps/v8/test/mjsunit/strong/functions.js
deps/v8/test/mozilla/mozilla.status
deps/v8/test/preparser/strict-function-statement.pyt [deleted file]
deps/v8/test/test262-es6/test262-es6.status
deps/v8/test/test262-es6/testcfg.py
deps/v8/test/test262/test262.status
deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
deps/v8/test/unittests/compiler/change-lowering-unittest.cc
deps/v8/test/unittests/compiler/common-operator-reducer-unittest.cc
deps/v8/test/unittests/compiler/common-operator-unittest.cc
deps/v8/test/unittests/compiler/control-equivalence-unittest.cc
deps/v8/test/unittests/compiler/control-flow-optimizer-unittest.cc
deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc
deps/v8/test/unittests/compiler/instruction-selector-unittest.cc
deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc
deps/v8/test/unittests/compiler/instruction-sequence-unittest.h
deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc
deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc
deps/v8/test/unittests/compiler/js-operator-unittest.cc
deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc
deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc [new file with mode: 0644]
deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc
deps/v8/test/unittests/compiler/machine-operator-unittest.cc
deps/v8/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc
deps/v8/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc
deps/v8/test/unittests/compiler/move-optimizer-unittest.cc
deps/v8/test/unittests/compiler/node-properties-unittest.cc
deps/v8/test/unittests/compiler/node-test-utils.cc
deps/v8/test/unittests/compiler/node-test-utils.h
deps/v8/test/unittests/compiler/node-unittest.cc
deps/v8/test/unittests/compiler/opcodes-unittest.cc
deps/v8/test/unittests/compiler/ppc/OWNERS [new file with mode: 0644]
deps/v8/test/unittests/compiler/register-allocator-unittest.cc
deps/v8/test/unittests/compiler/schedule-unittest.cc
deps/v8/test/unittests/compiler/scheduler-unittest.cc
deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc
deps/v8/test/unittests/compiler/simplified-operator-unittest.cc
deps/v8/test/unittests/compiler/state-values-utils-unittest.cc [new file with mode: 0644]
deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc
deps/v8/test/unittests/heap/gc-idle-time-handler-unittest.cc
deps/v8/test/unittests/unittests.gyp
deps/v8/test/webkit/fast/js/kde/prototype_length-expected.txt
deps/v8/test/webkit/fast/js/kde/prototype_length.js
deps/v8/test/webkit/webkit.status
deps/v8/testing/commit_queue/OWNERS [new file with mode: 0644]
deps/v8/testing/commit_queue/config.json [new file with mode: 0644]
deps/v8/tools/check-name-clashes.py
deps/v8/tools/cpu.sh
deps/v8/tools/external-reference-check.py
deps/v8/tools/gyp/v8.gyp
deps/v8/tools/js2c.py
deps/v8/tools/ll_prof.py
deps/v8/tools/parser-shell.cc
deps/v8/tools/perf-to-html.py [new file with mode: 0755]
deps/v8/tools/release/auto_push.py
deps/v8/tools/release/auto_roll.py
deps/v8/tools/release/chromium_roll.py
deps/v8/tools/release/common_includes.py
deps/v8/tools/release/create_release.py
deps/v8/tools/release/merge_to_branch.py
deps/v8/tools/release/releases.py
deps/v8/tools/release/test_scripts.py
deps/v8/tools/run-tests.py
deps/v8/tools/run_perf.py
deps/v8/tools/test-push-to-trunk.sh [deleted file]
deps/v8/tools/testrunner/local/statusfile.py
deps/v8/tools/v8-info.sh

index 2eac303..cc42433 100644 (file)
@@ -24,6 +24,7 @@
 .cproject
 .d8_history
 .gclient_entries
+.landmines
 .project
 .pydevproject
 .settings
index 39fb88c..5b976b8 100644 (file)
@@ -64,6 +64,7 @@ Jianghua Yang <jianghua.yjh@alibaba-inc.com>
 Joel Stanley <joel@jms.id.au>
 Johan Bergström <johan@bergstroem.nu>
 Jonathan Liu <net147@gmail.com>
+JunHo Seo <sejunho@gmail.com>
 Kang-Hao (Kenny) Lu <kennyluck@csail.mit.edu>
 Luis Reis <luis.m.reis@gmail.com>
 Luke Zarko <lukezarko@gmail.com>
index 713ab6d..fc0ea8e 100644 (file)
@@ -2,6 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/android/config.gni")
+import("//build/config/arm.gni")
+import("//build/config/mips.gni")
+
 # Because standalone V8 builds are not supported, assume this is part of a
 # Chromium build.
 import("//build/module_args/v8.gni")
@@ -18,10 +22,23 @@ v8_interpreted_regexp = false
 v8_object_print = false
 v8_postmortem_support = false
 v8_use_snapshot = true
-v8_target_arch = cpu_arch
+v8_target_arch = target_cpu
 v8_random_seed = "314159265"
 v8_toolset_for_d8 = "host"
 
+# The snapshot needs to be compiled for the host, but compiled with
+# a toolchain that matches the bit-width of the target.
+#
+# TODO(GYP): For now we only support 32-bit little-endian target builds from an
+# x64 Linux host. Eventually we need to support all of the host/target
+# configurations v8 runs on.
+if (host_cpu == "x64" && host_os == "linux" &&
+    (target_cpu == "arm" || target_cpu == "mipsel" || target_cpu == "x86")) {
+  snapshot_toolchain = "//build/toolchain/linux:clang_x86"
+} else {
+  snapshot_toolchain = default_toolchain
+}
+
 ###############################################################################
 # Configurations
 #
@@ -96,37 +113,49 @@ config("toolchain") {
   defines = []
   cflags = []
 
-  # TODO(jochen): Add support for arm subarchs, mips, mipsel.
+  # TODO(jochen): Add support for arm subarchs, mips, mipsel, mips64el.
 
   if (v8_target_arch == "arm") {
     defines += [ "V8_TARGET_ARCH_ARM" ]
-    if (arm_version == 7) {
-      defines += [ "CAN_USE_ARMV7_INSTRUCTIONS" ]
-    }
-    if (arm_fpu == "vfpv3-d16") {
-      defines += [ "CAN_USE_VFP3_INSTRUCTIONS" ]
-    }
-    if (arm_fpu == "vfpv3") {
-      defines += [
-        "CAN_USE_VFP3_INSTRUCTIONS",
-        "CAN_USE_VFP32DREGS",
-      ]
-    }
-    if (arm_fpu == "neon") {
+    if (current_cpu == "arm") {
+      if (arm_version == 7) {
+        defines += [ "CAN_USE_ARMV7_INSTRUCTIONS" ]
+      }
+      if (arm_fpu == "vfpv3-d16") {
+        defines += [ "CAN_USE_VFP3_INSTRUCTIONS" ]
+      } else if (arm_fpu == "vfpv3") {
+        defines += [
+          "CAN_USE_VFP3_INSTRUCTIONS",
+          "CAN_USE_VFP32DREGS",
+        ]
+      } else if (arm_fpu == "neon") {
+        defines += [
+          "CAN_USE_VFP3_INSTRUCTIONS",
+          "CAN_USE_VFP32DREGS",
+          "CAN_USE_NEON",
+        ]
+      }
+    } else {
+      # These defines ares used for the ARM simulator.
       defines += [
+        "CAN_USE_ARMV7_INSTRUCTIONS",
         "CAN_USE_VFP3_INSTRUCTIONS",
         "CAN_USE_VFP32DREGS",
-        "CAN_USE_NEON",
+        "USE_EABI_HARDFLOAT=0",
       ]
     }
 
     # TODO(jochen): Add support for arm_test_noprobe.
-
-    # TODO(jochen): Add support for cpu_arch != v8_target_arch/
   }
   if (v8_target_arch == "arm64") {
     defines += [ "V8_TARGET_ARCH_ARM64" ]
   }
+  if (v8_target_arch == "mipsel") {
+    defines += [ "V8_TARGET_ARCH_MIPS" ]
+  }
+  if (v8_target_arch == "mips64el") {
+    defines += [ "V8_TARGET_ARCH_MIPS64" ]
+  }
   if (v8_target_arch == "x86") {
     defines += [ "V8_TARGET_ARCH_IA32" ]
   }
@@ -173,8 +202,8 @@ action("js2c") {
     "src/array.js",
     "src/string.js",
     "src/uri.js",
-    "src/third_party/fdlibm/fdlibm.js",
     "src/math.js",
+    "src/third_party/fdlibm/fdlibm.js",
     "src/date.js",
     "src/regexp.js",
     "src/arraybuffer.js",
@@ -192,6 +221,7 @@ action("js2c") {
     "src/debug-debugger.js",
     "src/mirror-debugger.js",
     "src/liveedit-debugger.js",
+    "src/templates.js",
     "src/macros.py",
   ]
 
@@ -230,13 +260,12 @@ action("js2c_experimental") {
     "src/macros.py",
     "src/proxy.js",
     "src/generator.js",
-    "src/harmony-string.js",
     "src/harmony-array.js",
     "src/harmony-array-includes.js",
     "src/harmony-typedarray.js",
     "src/harmony-tostring.js",
-    "src/harmony-templates.js",
     "src/harmony-regexp.js",
+    "src/harmony-reflect.js"
   ]
 
   outputs = [
@@ -322,7 +351,7 @@ action("run_mksnapshot") {
   visibility = [ ":*" ]  # Only targets in this file can depend on this.
 
   deps = [
-    ":mksnapshot($host_toolchain)",
+    ":mksnapshot($snapshot_toolchain)",
   ]
 
   script = "tools/run.py"
@@ -332,7 +361,7 @@ action("run_mksnapshot") {
   ]
 
   args = [
-    "./" + rebase_path(get_label_info(":mksnapshot($host_toolchain)",
+    "./" + rebase_path(get_label_info(":mksnapshot($snapshot_toolchain)",
                                       "root_out_dir") + "/mksnapshot",
                        root_build_dir),
     "--log-snapshot-positions",
@@ -373,7 +402,7 @@ source_set("v8_nosnapshot") {
   sources = [
     "$target_gen_dir/libraries.cc",
     "$target_gen_dir/experimental-libraries.cc",
-    "src/snapshot-empty.cc",
+    "src/snapshot/snapshot-empty.cc",
   ]
 
   configs -= [ "//build/config/compiler:chromium_code" ]
@@ -423,8 +452,8 @@ if (v8_use_external_startup_data) {
     ]
 
     sources = [
-      "src/natives-external.cc",
-      "src/snapshot-external.cc",
+      "src/snapshot/natives-external.cc",
+      "src/snapshot/snapshot-external.cc",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -535,9 +564,7 @@ source_set("v8_base") {
     "src/compiler/frame.h",
     "src/compiler/gap-resolver.cc",
     "src/compiler/gap-resolver.h",
-    "src/compiler/generic-algorithm.h",
     "src/compiler/graph-builder.h",
-    "src/compiler/graph-inl.h",
     "src/compiler/graph-reducer.cc",
     "src/compiler/graph-reducer.h",
     "src/compiler/graph-replay.cc",
@@ -566,6 +593,8 @@ source_set("v8_base") {
     "src/compiler/js-intrinsic-lowering.h",
     "src/compiler/js-operator.cc",
     "src/compiler/js-operator.h",
+    "src/compiler/js-type-feedback.cc",
+    "src/compiler/js-type-feedback.h",
     "src/compiler/js-typed-lowering.cc",
     "src/compiler/js-typed-lowering.h",
     "src/compiler/jump-threading.cc",
@@ -573,6 +602,8 @@ source_set("v8_base") {
     "src/compiler/linkage-impl.h",
     "src/compiler/linkage.cc",
     "src/compiler/linkage.h",
+    "src/compiler/liveness-analyzer.cc",
+    "src/compiler/liveness-analyzer.h",
     "src/compiler/load-elimination.cc",
     "src/compiler/load-elimination.h",
     "src/compiler/loop-peeling.cc",
@@ -591,6 +622,7 @@ source_set("v8_base") {
     "src/compiler/node-cache.h",
     "src/compiler/node-marker.cc",
     "src/compiler/node-marker.h",
+    "src/compiler/node-matchers.cc",
     "src/compiler/node-matchers.h",
     "src/compiler/node-properties.cc",
     "src/compiler/node-properties.h",
@@ -631,6 +663,8 @@ source_set("v8_base") {
     "src/compiler/simplified-operator.h",
     "src/compiler/source-position.cc",
     "src/compiler/source-position.h",
+    "src/compiler/state-values-utils.cc",
+    "src/compiler/state-values-utils.h",
     "src/compiler/typer.cc",
     "src/compiler/typer.h",
     "src/compiler/value-numbering-reducer.cc",
@@ -848,7 +882,6 @@ source_set("v8_base") {
     "src/modules.cc",
     "src/modules.h",
     "src/msan.h",
-    "src/natives.h",
     "src/objects-debug.cc",
     "src/objects-inl.h",
     "src/objects-printer.cc",
@@ -860,6 +893,8 @@ source_set("v8_base") {
     "src/ostreams.h",
     "src/parser.cc",
     "src/parser.h",
+    "src/pending-compilation-error-handler.cc",
+    "src/pending-compilation-error-handler.h",
     "src/perf-jit.cc",
     "src/perf-jit.h",
     "src/preparse-data-format.h",
@@ -929,20 +964,23 @@ source_set("v8_base") {
     "src/scopeinfo.h",
     "src/scopes.cc",
     "src/scopes.h",
-    "src/serialize.cc",
-    "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/snapshot/natives.h",
+    "src/snapshot/serialize.cc",
+    "src/snapshot/serialize.h",
+    "src/snapshot/snapshot-common.cc",
+    "src/snapshot/snapshot-source-sink.cc",
+    "src/snapshot/snapshot-source-sink.h",
+    "src/snapshot/snapshot.h",
     "src/string-builder.cc",
     "src/string-builder.h",
     "src/string-search.cc",
     "src/string-search.h",
     "src/string-stream.cc",
     "src/string-stream.h",
+    "src/strings-storage.cc",
+    "src/strings-storage.h",
     "src/strtod.cc",
     "src/strtod.h",
     "src/token.cc",
@@ -1356,11 +1394,11 @@ source_set("v8_libbase") {
   if (is_linux) {
     sources += [ "src/base/platform/platform-linux.cc" ]
 
-    libs = [ "rt" ]
+    libs = [ "dl", "rt" ]
   } else if (is_android) {
     defines += [ "CAN_USE_VFP_INSTRUCTIONS" ]
 
-    if (build_os == "mac") {
+    if (host_os == "mac") {
       if (current_toolchain == host_toolchain) {
         sources += [ "src/base/platform/platform-macos.cc" ]
       } else {
@@ -1425,12 +1463,12 @@ source_set("v8_libplatform") {
 # Executables
 #
 
-if (current_toolchain == host_toolchain) {
+if (current_toolchain == snapshot_toolchain) {
   executable("mksnapshot") {
     visibility = [ ":*" ]  # Only targets in this file can depend on this.
 
     sources = [
-      "src/mksnapshot.cc",
+      "src/snapshot/mksnapshot.cc",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
index 0f835dc..69ecd92 100644 (file)
@@ -1,3 +1,449 @@
+2015-03-30: Version 4.3.61
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-28: Version 4.3.60
+
+        Reland^2 "Filter invalid slots out from the SlotsBuffer after marking."
+        (Chromium issues 454297, 470801).
+
+        This fixes missing incremental write barrier issue when double fields
+        unboxing is enabled (Chromium issue 469146).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-27: Version 4.3.59
+
+        Use a slot that is located on a heap page when removing invalid entries
+        from the SlotsBuffer (Chromium issue 470801).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-26: Version 4.3.58
+
+        Return timestamp of the last recorded interval to the caller of
+        HeapProfiler::GetHeapStats (Chromium issue 467222).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-26: Version 4.3.57
+
+        Reland [V8] Removed SourceLocationRestrict (Chromium issue 468781).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-25: Version 4.3.56
+
+        Remove v8::Isolate::ClearInterrupt.
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-25: Version 4.3.55
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-24: Version 4.3.54
+
+        Do not assign positions to parser-generated desugarings (Chromium issue
+        468661).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-24: Version 4.3.53
+
+        Filter invalid slots out from the SlotsBuffer after marking (Chromium
+        issue 454297).
+
+        Fix OOM bug 3976 (issue 3976).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-24: Version 4.3.52
+
+        Remove calls to IdleNotification().
+
+        Save heap object tracking data in heap snapshot (Chromium issue 467222).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-24: Version 4.3.51
+
+        [V8] Removed SourceLocationRestrict (Chromium issue 468781).
+
+        [turbofan] Fix control reducer bug with walking non-control edges during
+        ConnectNTL phase (Chromium issue 469605).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-23: Version 4.3.50
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-23: Version 4.3.49
+
+        Ensure we don't overflow in BCE (Chromium issue 469148).
+
+        [turbofan] Fix lowering of Math.max for integral inputs (Chromium issue
+        468162).
+
+        Use libdl to get symbols for backtraces.
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-19: Version 4.3.48
+
+        Clarify what APIs return Maybe and MaybeLocal values (issue 3929).
+
+        Introduce explicit constant for per Context debug data set by embedder
+        (Chromium issue 466631).
+
+        Adjust key behaviour for weak collections (issues 3970, 3971, Chromium
+        issue 460083).
+
+        Turn on overapproximation of the weak closure (issue 3862).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-18: Version 4.3.47
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-17: Version 4.3.46
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-17: Version 4.3.45
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-17: Version 4.3.44
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-16: Version 4.3.43
+
+        Bugfix in hydrogen GVN (Chromium issue 467481).
+
+        Remove obsolete TakeHeapSnapshot method from API (Chromium issue
+        465651).
+
+        Beautify syntax error for unterminated argument list (Chromium issue
+        339474).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-16: Version 4.3.42
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-15: Version 4.3.41
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-14: Version 4.3.40
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-14: Version 4.3.39
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-14: Version 4.3.38
+
+        Remove --harmony-scoping flag.
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-13: Version 4.3.37
+
+        Implement TDZ in StoreIC for top-level lexicals (issue 3941).
+
+        Turn on job-based optimizing compiler (issue 3608).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-13: Version 4.3.36
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-12: Version 4.3.35
+
+        Add Cast() for Int32 and Uint32 (Chromium issue 462402).
+
+        Incorrect handling of HTransitionElementsKind in hydrogen check
+        elimination phase fixed (Chromium issue 460917).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-12: Version 4.3.34
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-12: Version 4.3.33
+
+        Fix the toolchain used to build the snapshots in GN (Chromium issues
+        395249, 465456).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-11: Version 4.3.32
+
+        Reland of Remove slots that point to unboxed doubles from the
+        StoreBuffer/SlotsBuffer (Chromium issues 454297, 465273).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-11: Version 4.3.31
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-11: Version 4.3.30
+
+        Remove uid and title from HeapSnapshot (Chromium issue 465651).
+
+        Remove deprecated CpuProfiler methods.
+
+        [turbofan] Fix --turbo-osr for OSRing into inner loop inside for-in
+        (Chromium issue 462775).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-10: Version 4.3.29
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-10: Version 4.3.28
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-10: Version 4.3.27
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-07: Version 4.3.26
+
+        Remove slots that point to unboxed doubles from the
+        StoreBuffer/SlotsBuffer (Chromium issue 454297).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-06: Version 4.3.25
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-06: Version 4.3.24
+
+        convert more things to maybe (issue 3929).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-05: Version 4.3.23
+
+        [V8] Use Function.name for stack frames in v8::StackTrace (Chromium
+        issue 17356).
+
+        Allow passing sourceMapUrl when compiling scripts (Chromium issue
+        462572).
+
+        convert compile functions to use maybe (issue 3929).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-05: Version 4.3.22
+
+        give UniquePersistent full move semantics (issue 3669).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-05: Version 4.3.21
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-04: Version 4.3.20
+
+        convert remaining object functions to maybes (issue 3929).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-04: Version 4.3.19
+
+        ARM assembler: fix undefined behaviour in fits_shifter (Chromium issues
+        444089, 463436).
+
+        Implement subclassing Arrays (issue 3930).
+
+        [es6] Fix for-const loops (issue 3983).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-04: Version 4.3.18
+
+        Implement subclassing Arrays (issue 3930).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-04: Version 4.3.17
+
+        Implement subclassing Arrays (issue 3930).
+
+        convert more object functions to return maybes (issue 3929).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-03: Version 4.3.16
+
+        check for null context on execution entry (issue 3929).
+
+        convert object::* to return maybe values (issue 3929).
+
+        Removed funky Maybe constructor and made fields private (issue 3929).
+
+        Polish Maybe API a bit, removing useless creativity and fixing some
+        signatures (issue 3929).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-02: Version 4.3.15
+
+        Performance and stability improvements on all platforms.
+
+
+2015-03-02: Version 4.3.14
+
+        Performance and stability improvements on all platforms.
+
+
+2015-02-28: Version 4.3.13
+
+        Disallow subclassing Arrays (issue 3930).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-02-28: Version 4.3.12
+
+        Performance and stability improvements on all platforms.
+
+
+2015-02-27: Version 4.3.11
+
+        Disallow subclassing Arrays (issue 3930).
+
+        convert Value::*Value() function to return Maybe results (issue 3929).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-02-27: Version 4.3.10
+
+        Convert v8::Value::To* to use MaybeLocal (issue 3929).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-02-26: Version 4.3.9
+
+        Add public version macros (issue 3075).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-02-26: Version 4.3.8
+
+        Performance and stability improvements on all platforms.
+
+
+2015-02-25: Version 4.3.7
+
+        Performance and stability improvements on all platforms.
+
+
+2015-02-25: Version 4.3.6
+
+        Performance and stability improvements on all platforms.
+
+
+2015-02-25: Version 4.3.5
+
+        Turn on job based recompilation (issue 3608).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-02-24: Version 4.3.4
+
+        Reland "Correctly propagate terminate exception in TryCall." (issue
+        3892).
+
+        Performance and stability improvements on all platforms.
+
+
+2015-02-24: Version 4.3.3
+
+        Performance and stability improvements on all platforms.
+
+
+2015-02-24: Version 4.3.2
+
+        Update GN build files with the cpu_arch -> current_cpu change.
+
+        Performance and stability improvements on all platforms.
+
+
+2015-02-23: Version 4.3.1
+
+        Limit size of first page based on serialized data (Chromium issue
+        453111).
+
+        Performance and stability improvements on all platforms.
+
+
 2015-02-19: Version 4.2.77
 
         Make generator constructors configurable (issue 3902).
index b829d05..42606ac 100644 (file)
@@ -8,17 +8,17 @@ vars = {
 
 deps = {
   "v8/build/gyp":
-    Var("git_url") + "/external/gyp.git" + "@" + "34640080d08ab2a37665512e52142947def3056d",
+    Var("git_url") + "/external/gyp.git" + "@" + "d174d75bf69c682cb62af9187879e01513b35e52",
   "v8/third_party/icu":
-    Var("git_url") + "/chromium/deps/icu.git" + "@" + "4e3266f32c62d30a3f9e2232a753c60129d1e670",
+    Var("git_url") + "/chromium/deps/icu.git" + "@" + "7c81740601355556e630da515b74d889ba2f8d08",
   "v8/buildtools":
-    Var("git_url") + "/chromium/buildtools.git" + "@" + "5c5e924788fe40f7d6e0a3841ac572de2475e689",
+    Var("git_url") + "/chromium/buildtools.git" + "@" + "3b302fef93f7cc58d9b8168466905237484b2772",
   "v8/testing/gtest":
     Var("git_url") + "/external/googletest.git" + "@" + "be1868139ffe0ccd0e8e3b37292b84c821d9c8ad",
   "v8/testing/gmock":
     Var("git_url") + "/external/googlemock.git" + "@" + "29763965ab52f24565299976b936d1265cb6a271",  # from svn revision 501
   "v8/tools/clang":
-    Var("git_url") + "/chromium/src/tools/clang.git" + "@" + "f6daa55d03995e82201a3278203e7c0421a59546",
+    Var("git_url") + "/chromium/src/tools/clang.git" + "@" + "ea2f0a2d96ffc6f5a51c034db704ccc1a6543156",
 }
 
 deps_os = {
@@ -46,6 +46,17 @@ skip_child_includes = [
 ]
 
 hooks = [
+  {
+    # This clobbers when necessary (based on get_landmines.py). It must be the
+    # first hook so that other things that get/generate into the output
+    # directory will not subsequently be clobbered.
+    'name': 'landmines',
+    'pattern': '.',
+    'action': [
+        'python',
+        'v8/build/landmines.py',
+    ],
+  },
   # Pull clang-format binaries using checked-in hashes.
   {
     "name": "clang_format_win",
index 5468d91..055a57d 100644 (file)
@@ -234,7 +234,8 @@ ARCHES = ia32 x64 x32 arm arm64 mips mipsel mips64el x87 ppc ppc64
 DEFAULT_ARCHES = ia32 x64 arm
 MODES = release debug optdebug
 DEFAULT_MODES = release debug
-ANDROID_ARCHES = android_ia32 android_arm android_arm64 android_mipsel android_x87
+ANDROID_ARCHES = android_ia32 android_x64 android_arm android_arm64 \
+                android_mipsel android_x87
 NACL_ARCHES = nacl_ia32 nacl_x64
 
 # List of files that trigger Makefile regeneration:
index 2a36403..f89fd21 100644 (file)
@@ -26,7 +26,8 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 # Those definitions should be consistent with the main Makefile
-ANDROID_ARCHES = android_ia32 android_arm android_arm64 android_mipsel android_x87
+ANDROID_ARCHES = android_ia32 android_x64 android_arm android_arm64 \
+                android_mipsel android_x87
 MODES = release debug
 
 # Generates all combinations of ANDROID ARCHES and MODES,
@@ -66,6 +67,11 @@ else ifeq ($(ARCH), android_ia32)
   TOOLCHAIN_ARCH = x86
   TOOLCHAIN_PREFIX = i686-linux-android
   TOOLCHAIN_VER = 4.8
+else ifeq ($(ARCH), android_x64)
+  DEFINES = target_arch=x64 v8_target_arch=x64 android_target_arch=x86_64 android_target_platform=21
+  TOOLCHAIN_ARCH = x86_64
+  TOOLCHAIN_PREFIX = x86_64-linux-android
+  TOOLCHAIN_VER = 4.9
 else ifeq ($(ARCH), android_x87)
   DEFINES = target_arch=x87 v8_target_arch=x87 android_target_arch=x86 android_target_platform=14
   TOOLCHAIN_ARCH = x86
index fd0601f..5b3d58d 100644 (file)
@@ -244,6 +244,7 @@ def GetPreferredTryMasters(project, change):
   return {
     'tryserver.v8': {
       'v8_linux_rel': set(['defaulttests']),
+      'v8_linux_dbg': set(['defaulttests']),
       'v8_linux_nodcheck_rel': set(['defaulttests']),
       'v8_linux_gcc_compile_rel': set(['defaulttests']),
       'v8_linux64_rel': set(['defaulttests']),
index bc1685a..5cd4b58 100644 (file)
@@ -18,13 +18,13 @@ Getting the Code
 
 Checkout [depot tools](http://www.chromium.org/developers/how-tos/install-depot-tools), and run
 
-> `fetch v8`
+        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`
+        git pull origin
+        gclient sync
 
 For fetching all branches, add the following into your remote
 configuration in `.git/config`:
index 5d3b25a..533250e 100644 (file)
           'android_stlport': '<(android_toolchain)/sources/cxx-stl/stlport/',
         },
         'android_include': '<(android_sysroot)/usr/include',
-        'android_lib': '<(android_sysroot)/usr/lib',
+        'conditions': [
+          ['target_arch=="x64"', {
+            'android_lib': '<(android_sysroot)/usr/lib64',
+          }, {
+            'android_lib': '<(android_sysroot)/usr/lib',
+          }],
+        ],
         'android_stlport_include': '<(android_stlport)/stlport',
         'android_stlport_libs': '<(android_stlport)/libs',
       }, {
           'android_stlport': '<(android_ndk_root)/sources/cxx-stl/stlport/',
         },
         'android_include': '<(android_sysroot)/usr/include',
-        'android_lib': '<(android_sysroot)/usr/lib',
+        'conditions': [
+          ['target_arch=="x64"', {
+            'android_lib': '<(android_sysroot)/usr/lib64',
+          }, {
+            'android_lib': '<(android_sysroot)/usr/lib',
+          }],
+        ],
         'android_stlport_include': '<(android_stlport)/stlport',
         'android_stlport_libs': '<(android_stlport)/libs',
       }],
         'target_conditions': [
           ['_type=="executable"', {
             'conditions': [
-              ['target_arch=="arm64"', {
+              ['target_arch=="arm64" or target_arch=="x64"', {
                 'ldflags': [
                   '-Wl,-dynamic-linker,/system/bin/linker64',
                 ],
index 3460a9a..89e8286 100644 (file)
@@ -41,6 +41,7 @@ def DoMain(_):
   """Hook to be called from gyp without starting a separate python
   interpreter."""
   host_arch = platform.machine()
+  host_system = platform.system();
 
   # Convert machine type to format recognized by gyp.
   if re.match(r'i.86', host_arch) or host_arch == 'i86pc':
@@ -56,6 +57,13 @@ def DoMain(_):
   elif host_arch.startswith('mips'):
     host_arch = 'mipsel'
 
+  # Under AIX the value returned by platform.machine is not
+  # the best indicator of the host architecture
+  # AIX 6.1 which is the lowest level supported only provides
+  # a 64 bit kernel
+  if host_system == 'AIX':
+    host_arch = 'ppc64'
+
   # platform.machine is based on running kernel. It's possible to use 64-bit
   # kernel with 32-bit userland, e.g. to give linker slightly more memory.
   # Distinguish between different userland bitness by querying
index 2eadca3..5c60273 100644 (file)
       'DebugBaseCommon': {
         'abstract': 1,
         'variables': {
-          'v8_enable_handle_zapping%': 1,
+          'v8_enable_handle_zapping%': 0,
         },
         'conditions': [
           ['v8_enable_handle_zapping==1', {
       },  # Debug
       'Release': {
         'variables': {
-          'v8_enable_handle_zapping%': 0,
+          'v8_enable_handle_zapping%': 1,
         },
         'conditions': [
           ['v8_enable_handle_zapping==1', {
index 66a86cb..f61c04d 100755 (executable)
@@ -20,6 +20,7 @@ def main():
   print 'Activating MSVS 2013.'
   print 'Revert activation of MSVS 2013.'
   print 'Activating MSVS 2013 again.'
+  print 'Clobber after ICU roll.'
   return 0
 
 
diff --git a/deps/v8/build/gyp_environment.py b/deps/v8/build/gyp_environment.py
new file mode 100644 (file)
index 0000000..f1cee6e
--- /dev/null
@@ -0,0 +1,52 @@
+# 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.
+
+"""
+Sets up various automatic gyp environment variables. These are used by
+gyp_v8 and landmines.py which run at different stages of runhooks. To
+make sure settings are consistent between them, all setup should happen here.
+"""
+
+import os
+import sys
+
+SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
+V8_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, os.pardir))
+
+
+def apply_gyp_environment(file_path=None):
+  """
+  Reads in a *.gyp_env file and applies the valid keys to os.environ.
+  """
+  if not file_path or not os.path.exists(file_path):
+    return
+  file_contents = open(file_path).read()
+  try:
+    file_data = eval(file_contents, {'__builtins__': None}, None)
+  except SyntaxError, e:
+    e.filename = os.path.abspath(file_path)
+    raise
+  supported_vars = ( 'V8_GYP_FILE',
+                     'V8_GYP_SYNTAX_CHECK',
+                     'GYP_DEFINES',
+                     'GYP_GENERATOR_FLAGS',
+                     'GYP_GENERATOR_OUTPUT', )
+  for var in supported_vars:
+    val = file_data.get(var)
+    if val:
+      if var in os.environ:
+        print 'INFO: Environment value for "%s" overrides value in %s.' % (
+            var, os.path.abspath(file_path)
+        )
+      else:
+        os.environ[var] = val
+
+
+def set_environment():
+  """Sets defaults for GYP_* variables."""
+
+  if 'SKIP_V8_GYP_ENV' not in os.environ:
+    # Update the environment based on v8.gyp_env
+    gyp_env_path = os.path.join(os.path.dirname(V8_ROOT), 'v8.gyp_env')
+    apply_gyp_environment(gyp_env_path)
index 14467ec..1e8a5c8 100755 (executable)
@@ -31,6 +31,7 @@
 # is invoked by V8 beyond what can be done in the gclient hooks.
 
 import glob
+import gyp_environment
 import os
 import platform
 import shlex
@@ -48,34 +49,6 @@ sys.path.insert(
     1, os.path.abspath(os.path.join(v8_root, 'tools', 'generate_shim_headers')))
 
 
-def apply_gyp_environment(file_path=None):
-  """
-  Reads in a *.gyp_env file and applies the valid keys to os.environ.
-  """
-  if not file_path or not os.path.exists(file_path):
-    return
-  file_contents = open(file_path).read()
-  try:
-    file_data = eval(file_contents, {'__builtins__': None}, None)
-  except SyntaxError, e:
-    e.filename = os.path.abspath(file_path)
-    raise
-  supported_vars = ( 'V8_GYP_FILE',
-                     'V8_GYP_SYNTAX_CHECK',
-                     'GYP_DEFINES',
-                     'GYP_GENERATOR_FLAGS',
-                     'GYP_GENERATOR_OUTPUT', )
-  for var in supported_vars:
-    val = file_data.get(var)
-    if val:
-      if var in os.environ:
-        print 'INFO: Environment value for "%s" overrides value in %s.' % (
-            var, os.path.abspath(file_path)
-        )
-      else:
-        os.environ[var] = val
-
-
 def additional_include_files(args=[]):
   """
   Returns a list of additional (.gypi) files to include, without
@@ -109,13 +82,6 @@ def additional_include_files(args=[]):
 def run_gyp(args):
   rc = gyp.main(args)
 
-  # Check for landmines (reasons to clobber the build). This must be run here,
-  # rather than a separate runhooks step so that any environment modifications
-  # from above are picked up.
-  print 'Running build/landmines.py...'
-  subprocess.check_call(
-      [sys.executable, os.path.join(script_dir, 'landmines.py')])
-
   if rc != 0:
     print 'Error running GYP'
     sys.exit(rc)
@@ -124,10 +90,7 @@ def run_gyp(args):
 if __name__ == '__main__':
   args = sys.argv[1:]
 
-  if 'SKIP_V8_GYP_ENV' not in os.environ:
-    # Update the environment based on v8.gyp_env
-    gyp_env_path = os.path.join(os.path.dirname(v8_root), 'v8.gyp_env')
-    apply_gyp_environment(gyp_env_path)
+  gyp_environment.set_environment()
 
   # This could give false positives since it doesn't actually do real option
   # parsing.  Oh well.
index e8b7c98..cb34991 100644 (file)
@@ -47,10 +47,19 @@ def gyp_defines():
   return dict(arg.split('=', 1)
       for arg in shlex.split(os.environ.get('GYP_DEFINES', '')))
 
+
+@memoize()
+def gyp_generator_flags():
+  """Parses and returns GYP_GENERATOR_FLAGS env var as a dictionary."""
+  return dict(arg.split('=', 1)
+      for arg in shlex.split(os.environ.get('GYP_GENERATOR_FLAGS', '')))
+
+
 @memoize()
 def gyp_msvs_version():
   return os.environ.get('GYP_MSVS_VERSION', '')
 
+
 @memoize()
 def distributor():
   """
index bd1fb28..97c6390 100755 (executable)
@@ -4,10 +4,9 @@
 # found in the LICENSE file.
 
 """
-This script runs every build as a hook. If it detects that the build should
-be clobbered, it will touch the file <build_dir>/.landmine_triggered. The
-various build scripts will then check for the presence of this file and clobber
-accordingly. The script will also emit the reasons for the clobber to stdout.
+This script runs every build as the first hook (See DEPS). If it detects that
+the build should be clobbered, it will delete the contents of the build
+directory.
 
 A landmine is tripped when a builder checks out a different revision, and the
 diff between the new landmines and the old ones is non-null. At this point, the
@@ -15,9 +14,13 @@ build is clobbered.
 """
 
 import difflib
+import errno
+import gyp_environment
 import logging
 import optparse
 import os
+import re
+import shutil
 import sys
 import subprocess
 import time
@@ -28,46 +31,109 @@ import landmine_utils
 SRC_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
 
 
-def get_target_build_dir(build_tool, target):
+def get_build_dir(build_tool, is_iphone=False):
   """
   Returns output directory absolute path dependent on build and targets.
   Examples:
-    r'c:\b\build\slave\win\build\src\out\Release'
-    '/mnt/data/b/build/slave/linux/build/src/out/Debug'
-    '/b/build/slave/ios_rel_device/build/src/xcodebuild/Release-iphoneos'
+    r'c:\b\build\slave\win\build\src\out'
+    '/mnt/data/b/build/slave/linux/build/src/out'
+    '/b/build/slave/ios_rel_device/build/src/xcodebuild'
 
   Keep this function in sync with tools/build/scripts/slave/compile.py
   """
   ret = None
   if build_tool == 'xcode':
-    ret = os.path.join(SRC_DIR, 'xcodebuild', target)
+    ret = os.path.join(SRC_DIR, 'xcodebuild')
   elif build_tool in ['make', 'ninja', 'ninja-ios']:  # TODO: Remove ninja-ios.
-    ret = os.path.join(SRC_DIR, 'out', target)
+    if 'CHROMIUM_OUT_DIR' in os.environ:
+      output_dir = os.environ.get('CHROMIUM_OUT_DIR').strip()
+      if not output_dir:
+        raise Error('CHROMIUM_OUT_DIR environment variable is set but blank!')
+    else:
+      output_dir = landmine_utils.gyp_generator_flags().get('output_dir', 'out')
+    ret = os.path.join(SRC_DIR, output_dir)
   elif build_tool in ['msvs', 'vs', 'ib']:
-    ret = os.path.join(SRC_DIR, 'build', target)
+    ret = os.path.join(SRC_DIR, 'build')
   else:
     raise NotImplementedError('Unexpected GYP_GENERATORS (%s)' % build_tool)
   return os.path.abspath(ret)
 
 
-def set_up_landmines(target, new_landmines):
-  """Does the work of setting, planting, and triggering landmines."""
-  out_dir = get_target_build_dir(landmine_utils.builder(), target)
-
-  landmines_path = os.path.join(out_dir, '.landmines')
-  if not os.path.exists(out_dir):
+def extract_gn_build_commands(build_ninja_file):
+  """Extracts from a build.ninja the commands to run GN.
+
+  The commands to run GN are the gn rule and build.ninja build step at the
+  top of the build.ninja file. We want to keep these when deleting GN builds
+  since we want to preserve the command-line flags to GN.
+
+  On error, returns the empty string."""
+  result = ""
+  with open(build_ninja_file, 'r') as f:
+    # Read until the second blank line. The first thing GN writes to the file
+    # is the "rule gn" and the second is the section for "build build.ninja",
+    # separated by blank lines.
+    num_blank_lines = 0
+    while num_blank_lines < 2:
+      line = f.readline()
+      if len(line) == 0:
+        return ''  # Unexpected EOF.
+      result += line
+      if line[0] == '\n':
+        num_blank_lines = num_blank_lines + 1
+  return result
+
+def delete_build_dir(build_dir):
+  # GN writes a build.ninja.d file. Note that not all GN builds have args.gn.
+  build_ninja_d_file = os.path.join(build_dir, 'build.ninja.d')
+  if not os.path.exists(build_ninja_d_file):
+    shutil.rmtree(build_dir)
     return
 
-  if not os.path.exists(landmines_path):
-    print "Landmines tracker didn't exists."
-
-  # FIXME(machenbach): Clobber deletes the .landmines tracker. Difficult
-  # to know if we are right after a clobber or if it is first-time landmines
-  # deployment. Also, a landmine-triggered clobber right after a clobber is
-  # not possible. Different clobber methods for msvs, xcode and make all
-  # have different blacklists of files that are not deleted.
+  # GN builds aren't automatically regenerated when you sync. To avoid
+  # messing with the GN workflow, erase everything but the args file, and
+  # write a dummy build.ninja file that will automatically rerun GN the next
+  # time Ninja is run.
+  build_ninja_file = os.path.join(build_dir, 'build.ninja')
+  build_commands = extract_gn_build_commands(build_ninja_file)
+
+  try:
+    gn_args_file = os.path.join(build_dir, 'args.gn')
+    with open(gn_args_file, 'r') as f:
+      args_contents = f.read()
+  except IOError:
+    args_contents = ''
+
+  shutil.rmtree(build_dir)
+
+  # Put back the args file (if any).
+  os.mkdir(build_dir)
+  if args_contents != '':
+    with open(gn_args_file, 'w') as f:
+      f.write(args_contents)
+
+  # Write the build.ninja file sufficiently to regenerate itself.
+  with open(os.path.join(build_dir, 'build.ninja'), 'w') as f:
+    if build_commands != '':
+      f.write(build_commands)
+    else:
+      # Couldn't parse the build.ninja file, write a default thing.
+      f.write('''rule gn
+command = gn -q gen //out/%s/
+description = Regenerating ninja files
+
+build build.ninja: gn
+generator = 1
+depfile = build.ninja.d
+''' % (os.path.split(build_dir)[1]))
+
+  # Write a .d file for the build which references a nonexistant file. This
+  # will make Ninja always mark the build as dirty.
+  with open(build_ninja_d_file, 'w') as f:
+    f.write('build.ninja: nonexistant_file.gn\n')
+
+
+def needs_clobber(landmines_path, new_landmines):
   if os.path.exists(landmines_path):
-    triggered = os.path.join(out_dir, '.landmines_triggered')
     with open(landmines_path, 'r') as f:
       old_landmines = f.readlines()
     if old_landmines != new_landmines:
@@ -75,14 +141,54 @@ def set_up_landmines(target, new_landmines):
       diff = difflib.unified_diff(old_landmines, new_landmines,
           fromfile='old_landmines', tofile='new_landmines',
           fromfiledate=old_date, tofiledate=time.ctime(), n=0)
+      sys.stdout.write('Clobbering due to:\n')
+      sys.stdout.writelines(diff)
+      return True
+  else:
+    sys.stdout.write('Clobbering due to missing landmines file.\n')
+    return True
+  return False
 
-      with open(triggered, 'w') as f:
-        f.writelines(diff)
-      print "Setting landmine: %s" % triggered
-    elif os.path.exists(triggered):
-      # Remove false triggered landmines.
-      os.remove(triggered)
-      print "Removing landmine: %s" % triggered
+
+def clobber_if_necessary(new_landmines):
+  """Does the work of setting, planting, and triggering landmines."""
+  out_dir = get_build_dir(landmine_utils.builder())
+  landmines_path = os.path.normpath(os.path.join(out_dir, '..', '.landmines'))
+  try:
+    os.makedirs(out_dir)
+  except OSError as e:
+    if e.errno == errno.EEXIST:
+      pass
+
+  if needs_clobber(landmines_path, new_landmines):
+    # Clobber contents of build directory but not directory itself: some
+    # checkouts have the build directory mounted.
+    for f in os.listdir(out_dir):
+      path = os.path.join(out_dir, f)
+      if os.path.basename(out_dir) == 'build':
+        # Only delete build directories and files for MSVS builds as the folder
+        # shares some checked out files and directories.
+        if (os.path.isdir(path) and
+            re.search(r'(?:[Rr]elease)|(?:[Dd]ebug)', f)):
+          delete_build_dir(path)
+        elif (os.path.isfile(path) and
+              (path.endswith('.sln') or
+               path.endswith('.vcxproj') or
+               path.endswith('.vcxproj.user'))):
+          os.unlink(path)
+      else:
+        if os.path.isfile(path):
+          os.unlink(path)
+        elif os.path.isdir(path):
+          delete_build_dir(path)
+    if os.path.basename(out_dir) == 'xcodebuild':
+      # Xcodebuild puts an additional project file structure into build,
+      # while the output folder is xcodebuild.
+      project_dir = os.path.join(SRC_DIR, 'build', 'all.xcodeproj')
+      if os.path.exists(project_dir) and os.path.isdir(project_dir):
+        delete_build_dir(project_dir)
+
+  # Save current set of landmines for next time.
   with open(landmines_path, 'w') as f:
     f.writelines(new_landmines)
 
@@ -123,14 +229,14 @@ def main():
   if landmine_utils.builder() in ('dump_dependency_json', 'eclipse'):
     return 0
 
+  gyp_environment.set_environment()
+
   landmines = []
   for s in landmine_scripts:
     proc = subprocess.Popen([sys.executable, s], stdout=subprocess.PIPE)
     output, _ = proc.communicate()
     landmines.extend([('%s\n' % l.strip()) for l in output.splitlines()])
-
-  for target in ('Debug', 'Release'):
-    set_up_landmines(target, landmines)
+  clobber_if_necessary(landmines)
 
   return 0
 
index 56cebbe..d95cb7a 100644 (file)
       }, {
         'v8_enable_gdbjit%': 0,
       }],
-      ['(OS=="linux" or OS=="mac") and (target_arch=="ia32" or target_arch=="x64")', {
+      ['(OS=="linux" or OS=="mac") and (target_arch=="ia32" or target_arch=="x64") and \
+        (v8_target_arch!="x87")', {
         'clang%': 1,
       }, {
         'clang%': 0,
       }],
+      ['host_arch!="ppc" and host_arch!="ppc64" and host_arch!="ppc64le"', {
+        'host_clang%': '1',
+      }, {
+        'host_clang%': '0',
+      }],
     ],
     # Default ARM variable settings.
     'arm_version%': 'default',
     'default_configuration': 'Debug',
     'configurations': {
       'DebugBaseCommon': {
-        'cflags': [ '-g', '-O0' ],
         'conditions': [
-          ['(v8_target_arch=="ia32" or v8_target_arch=="x87") and \
-            OS=="linux"', {
-            'defines': [
-              '_GLIBCXX_DEBUG'
-            ],
-          }],
-          [ 'OS=="aix"', {
-            'cflags': [ '-gxcoff' ],
+          ['OS=="aix"', {
+            'cflags': [ '-g', '-Og', '-gxcoff' ],
+          }, {
+            'cflags': [ '-g', '-O0' ],
           }],
         ],
       },
         # Xcode insists on this empty entry.
       },
     },
+    'conditions':[
+      ['(clang==1 or host_clang==1) and OS!="win"', {
+        # This is here so that all files get recompiled after a clang roll and
+        # when turning clang on or off.
+        # (defines are passed via the command line, and build systems rebuild
+        # things when their commandline changes). Nothing should ever read this
+        # define.
+        'defines': ['CR_CLANG_REVISION=<!(<(DEPTH)/tools/clang/scripts/update.sh --print-revision)'],
+        'cflags+': [
+          '-Wno-format-pedantic',
+        ],
+      }],
+    ],
     'target_conditions': [
       ['v8_code == 0', {
         'defines!': [
         ],
         'conditions': [
           ['os_posix == 1 and OS != "mac"', {
+            # We don't want to get warnings from third-party code,
+            # so remove any existing warning-enabling flags like -Wall.
             'cflags!': [
+              '-pedantic',
+              '-Wall',
               '-Werror',
+              '-Wextra',
+            ],
+            'cflags+': [
+              # Clang considers the `register` keyword as deprecated, but
+              # ICU uses it all over the place.
+              '-Wno-deprecated-register',
+              # ICU uses its own deprecated functions.
+              '-Wno-deprecated-declarations',
+              # ICU prefers `a && b || c` over `(a && b) || c`.
+              '-Wno-logical-op-parentheses',
+              # ICU has some `unsigned < 0` checks.
+              '-Wno-tautological-compare',
+              # uresdata.c has switch(RES_GET_TYPE(x)) code. The
+              # RES_GET_TYPE macro returns an UResType enum, but some switch
+              # statement contains case values that aren't part of that
+              # enum (e.g. URES_TABLE32 which is in UResInternalType). This
+              # is on purpose.
+              '-Wno-switch',
+            ],
+            'cflags_cc!': [
+              '-Wnon-virtual-dtor',
             ],
           }],
           ['OS == "mac"', {
         'cflags': [
           '-Wall',
           '<(werror)',
-          '-W',
           '-Wno-unused-parameter',
           '-Wno-long-long',
           '-pthread',
         'cflags_cc': [ '-Wnon-virtual-dtor', '-fno-rtti', '-std=gnu++0x' ],
         'ldflags': [ '-pthread', ],
         'conditions': [
-          [ 'host_arch=="ppc64"', {
+          [ 'host_arch=="ppc64" and OS!="aix"', {
             'cflags': [ '-mminimal-toc' ],
           }],
           [ 'visibility=="hidden" and v8_enable_backtrace==0', {
         'cflags': [
           '-Wall',
           '<(werror)',
-          '-W',
           '-Wno-unused-parameter',
           '-fno-exceptions',
           # Don't warn about the "struct foo f = {0};" initialization pattern.
           'WARNING_CFLAGS': [
             '-Wall',
             '-Wendif-labels',
-            '-W',
             '-Wno-unused-parameter',
             # Don't warn about the "struct foo f = {0};" initialization pattern.
             '-Wno-missing-field-initializers',
         ],  # target_conditions
       },  # target_defaults
     }],  # OS=="mac"
+    ['clang!=1 and host_clang==1 and target_arch!="ia32" and target_arch!="x64"', {
+      'make_global_settings': [
+        ['CC.host', '../<(clang_dir)/bin/clang'],
+        ['CXX.host', '../<(clang_dir)/bin/clang++'],
+      ],
+    }],
+    ['clang==0 and host_clang==1 and target_arch!="ia32" and target_arch!="x64"', {
+      'target_conditions': [
+        ['_toolset=="host"', {
+          'cflags_cc': [ '-std=gnu++11', ],
+        }],
+      ],
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="host"', { 'cflags!': [ '-Wno-unused-local-typedefs' ]}],
+        ],
+      },
+    }],
+    ['clang==1 and "<(GENERATOR)"=="ninja"', {
+      # See http://crbug.com/110262
+      'target_defaults': {
+        'cflags': [ '-fcolor-diagnostics' ],
+        'xcode_settings': { 'OTHER_CFLAGS': [ '-fcolor-diagnostics' ] },
+      },
+    }],
     ['clang==1 and ((OS!="mac" and OS!="ios") or clang_xcode==0) '
         'and OS!="win" and "<(GENERATOR)"=="make"', {
       'make_global_settings': [
index d4a9403..f1f46c8 100644 (file)
@@ -61,6 +61,9 @@
     # Similar to the ARM hard float ABI but on MIPS.
     'v8_use_mips_abi_hardfloat%': 'true',
 
+    # Force disable libstdc++ debug mode.
+    'disable_glibcxx_debug%': 0,
+
     'v8_enable_backtrace%': 0,
 
     # Enable profiling support. Only required on Windows.
             # Support for backtrace_symbols.
             'ldflags': [ '-rdynamic' ],
           }],
+          ['OS=="linux" and disable_glibcxx_debug==0', {
+            # Enable libstdc++ debugging facilities to help catch problems
+            # early, see http://crbug.com/65151 .
+            'defines': ['_GLIBCXX_DEBUG=1',],
+          }],
           ['OS=="aix"', {
             'ldflags': [ '-Wl,-bbigtoc' ],
+            'conditions': [
+              ['v8_target_arch=="ppc64"', {
+                'cflags': [ '-maix64 -mcmodel=large' ],
+              }],
+            ],
           }],
           ['OS=="android"', {
             'variables': {
index 6abf4e0..ae11a2a 100644 (file)
@@ -202,13 +202,22 @@ class V8_EXPORT Debug {
   *   }
   * \endcode
   */
-  static Local<Value> Call(v8::Handle<v8::Function> fun,
-                           Handle<Value> data = Handle<Value>());
+  static V8_DEPRECATE_SOON(
+      "Use maybe version",
+      Local<Value> Call(v8::Handle<v8::Function> fun,
+                        Handle<Value> data = Handle<Value>()));
+  // TODO(dcarney): data arg should be a MaybeLocal
+  static MaybeLocal<Value> Call(Local<Context> context,
+                                v8::Handle<v8::Function> fun,
+                                Handle<Value> data = Handle<Value>());
 
   /**
    * Returns a mirror object for the given object.
    */
-  static Local<Value> GetMirror(v8::Handle<v8::Value> obj);
+  static V8_DEPRECATE_SOON("Use maybe version",
+                           Local<Value> GetMirror(v8::Handle<v8::Value> obj));
+  static MaybeLocal<Value> GetMirror(Local<Context> context,
+                                     v8::Handle<v8::Value> obj);
 
   /**
    * Makes V8 process all pending debug messages.
index d021520..f9439c2 100644 (file)
@@ -168,21 +168,12 @@ class V8_EXPORT CpuProfiler {
    */
   void StartProfiling(Handle<String> title, bool record_samples = false);
 
-  /** Deprecated. Use StartProfiling instead. */
-  V8_DEPRECATED("Use StartProfiling",
-      void StartCpuProfiling(Handle<String> title,
-                             bool record_samples = false));
-
   /**
    * Stops collecting CPU profile with a given title and returns it.
    * If the title given is empty, finishes the last profile started.
    */
   CpuProfile* StopProfiling(Handle<String> title);
 
-  /** Deprecated. Use StopProfiling instead. */
-  V8_DEPRECATED("Use StopProfiling",
-      const CpuProfile* StopCpuProfiling(Handle<String> title));
-
   /**
    * Tells the profiler whether the embedder is idle.
    */
@@ -272,10 +263,6 @@ class V8_EXPORT HeapGraphNode {
   SnapshotObjectId GetId() const;
 
   /** Returns node's own size, in bytes. */
-  V8_DEPRECATED("Use GetShallowSize instead",
-                int GetSelfSize() const);
-
-  /** Returns node's own size, in bytes. */
   size_t GetShallowSize() const;
 
   /** Returns child nodes count of the node. */
@@ -326,12 +313,6 @@ class V8_EXPORT HeapSnapshot {
     kJSON = 0  // See format description near 'Serialize' method.
   };
 
-  /** Returns heap snapshot UID (assigned by the profiler.) */
-  unsigned GetUid() const;
-
-  /** Returns heap snapshot title. */
-  Handle<String> GetTitle() const;
-
   /** Returns the root node of the heap graph. */
   const HeapGraphNode* GetRoot() const;
 
@@ -380,7 +361,8 @@ class V8_EXPORT HeapSnapshot {
    * Nodes reference strings, other nodes, and edges by their indexes
    * in corresponding arrays.
    */
-  void Serialize(OutputStream* stream, SerializationFormat format) const;
+  void Serialize(OutputStream* stream,
+                 SerializationFormat format = kJSON) const;
 };
 
 
@@ -465,10 +447,9 @@ class V8_EXPORT HeapProfiler {
   };
 
   /**
-   * Takes a heap snapshot and returns it. Title may be an empty string.
+   * Takes a heap snapshot and returns it.
    */
   const HeapSnapshot* TakeHeapSnapshot(
-      Handle<String> title,
       ActivityControl* control = NULL,
       ObjectNameResolver* global_object_name_resolver = NULL);
 
@@ -490,17 +471,19 @@ class V8_EXPORT HeapProfiler {
    * reports updates for all previous time intervals via the OutputStream
    * object. Updates on each time interval are provided as a stream of the
    * HeapStatsUpdate structure instances.
-   * The return value of the function is the last seen heap object Id.
+   * If |timestamp_us| is supplied, timestamp of the new entry will be written
+   * into it. The return value of the function is the last seen heap object Id.
    *
    * StartTrackingHeapObjects must be called before the first call to this
    * method.
    */
-  SnapshotObjectId GetHeapStats(OutputStream* stream);
+  SnapshotObjectId GetHeapStats(OutputStream* stream,
+                                int64_t* timestamp_us = NULL);
 
   /**
    * Stops tracking of heap objects population statistics, cleans up all
    * collected data. StartHeapObjectsTracking must be called again prior to
-   * calling PushHeapObjectsStats next time.
+   * calling GetHeapStats next time.
    */
   void StopTrackingHeapObjects();
 
index ca36b6c..b01d527 100644 (file)
@@ -12,7 +12,7 @@
 /**
  * Support for Persistent containers.
  *
- * C++11 embedders can use STL containers with UniquePersistent values,
+ * C++11 embedders can use STL containers with Global values,
  * but pre-C++11 does not support the required move semantic and hence
  * may want these container classes.
  */
@@ -22,7 +22,10 @@ typedef uintptr_t PersistentContainerValue;
 static const uintptr_t kPersistentContainerNotFound = 0;
 enum PersistentContainerCallbackType {
   kNotWeak,
-  kWeak
+  // These correspond to v8::WeakCallbackType
+  kWeakWithParameter,
+  kWeakWithInternalFields,
+  kWeak = kWeakWithParameter  // For backwards compatibility.  Deprecate.
 };
 
 
@@ -101,12 +104,12 @@ class DefaultPersistentValueMapTraits : public StdMapTraits<K, V> {
     return K();
   }
   static void DisposeCallbackData(WeakCallbackDataType* data) { }
-  static void Dispose(Isolate* isolate, UniquePersistent<V> value, K key) { }
+  static void Dispose(Isolate* isolate, Global<V> value, K key) {}
 };
 
 
 template <typename K, typename V>
-class DefaultPhantomPersistentValueMapTraits : public StdMapTraits<K, V> {
+class DefaultGlobalMapTraits : public StdMapTraits<K, V> {
  private:
   template <typename T>
   struct RemovePointer;
@@ -114,25 +117,26 @@ class DefaultPhantomPersistentValueMapTraits : public StdMapTraits<K, V> {
  public:
   // Weak callback & friends:
   static const PersistentContainerCallbackType kCallbackType = kNotWeak;
-  typedef PersistentValueMap<
-      K, V, DefaultPhantomPersistentValueMapTraits<K, V> > MapType;
-  typedef void PhantomCallbackDataType;
+  typedef PersistentValueMap<K, V, DefaultGlobalMapTraits<K, V> > MapType;
+  typedef void WeakCallbackInfoType;
 
-  static PhantomCallbackDataType* PhantomCallbackParameter(MapType* map,
-                                                           const K& key,
-                                                           Local<V> value) {
-    return NULL;
+  static WeakCallbackInfoType* WeakCallbackParameter(MapType* map, const K& key,
+                                                     Local<V> value) {
+    return nullptr;
   }
-  static MapType* MapFromPhantomCallbackData(
-      const PhantomCallbackData<PhantomCallbackDataType>& data) {
-    return NULL;
+  static MapType* MapFromWeakCallbackInfo(
+      const WeakCallbackInfo<WeakCallbackInfoType>& data) {
+    return nullptr;
   }
-  static K KeyFromPhantomCallbackData(
-      const PhantomCallbackData<PhantomCallbackDataType>& data) {
+  static K KeyFromWeakCallbackInfo(
+      const WeakCallbackInfo<WeakCallbackInfoType>& data) {
     return K();
   }
-  static void DisposeCallbackData(PhantomCallbackDataType* data) {}
-  static void Dispose(Isolate* isolate, UniquePersistent<V> value, K key) {}
+  static void DisposeCallbackData(WeakCallbackInfoType* data) {}
+  static void Dispose(Isolate* isolate, Global<V> value, K key) {}
+  static void DisposeWeak(Isolate* isolate,
+                          const WeakCallbackInfo<WeakCallbackInfoType>& data,
+                          K key) {}
 
  private:
   template <typename T>
@@ -143,8 +147,8 @@ class DefaultPhantomPersistentValueMapTraits : public StdMapTraits<K, V> {
 
 
 /**
- * A map wrapper that allows using UniquePersistent as a mapped value.
- * C++11 embedders don't need this class, as they can use UniquePersistent
+ * A map wrapper that allows using Global as a mapped value.
+ * C++11 embedders don't need this class, as they can use Global
  * directly in std containers.
  *
  * The map relies on a backing map, whose type and accessors are described
@@ -203,7 +207,7 @@ class PersistentValueMapBase {
   /**
    * Return value for key and remove it from the map.
    */
-  UniquePersistent<V> Remove(const K& key) {
+  Global<V> Remove(const K& key) {
     return Release(Traits::Remove(&impl_, key)).Pass();
   }
 
@@ -255,7 +259,7 @@ class PersistentValueMapBase {
    private:
     friend class PersistentValueMapBase;
     friend class PersistentValueMap<K, V, Traits>;
-    friend class PhantomPersistentValueMap<K, V, Traits>;
+    friend class GlobalValueMap<K, V, Traits>;
 
     explicit PersistentValueReference(PersistentContainerValue value)
         : value_(value) { }
@@ -293,24 +297,23 @@ class PersistentValueMapBase {
     return reinterpret_cast<V*>(v);
   }
 
-  static PersistentContainerValue ClearAndLeak(
-      UniquePersistent<V>* persistent) {
+  static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
     V* v = persistent->val_;
     persistent->val_ = 0;
     return reinterpret_cast<PersistentContainerValue>(v);
   }
 
-  static PersistentContainerValue Leak(UniquePersistent<V>* persistent) {
+  static PersistentContainerValue Leak(Global<V>* persistent) {
     return reinterpret_cast<PersistentContainerValue>(persistent->val_);
   }
 
   /**
-   * Return a container value as UniquePersistent and make sure the weak
+   * Return a container value as Global and make sure the weak
    * callback is properly disposed of. All remove functionality should go
    * through this.
    */
-  static UniquePersistent<V> Release(PersistentContainerValue v) {
-    UniquePersistent<V> p;
+  static Global<V> Release(PersistentContainerValue v) {
+    Global<V> p;
     p.val_ = FromVal(v);
     if (Traits::kCallbackType != kNotWeak && p.IsWeak()) {
       Traits::DisposeCallbackData(
@@ -319,6 +322,12 @@ class PersistentValueMapBase {
     return p.Pass();
   }
 
+  void RemoveWeak(const K& key) {
+    Global<V> p;
+    p.val_ = FromVal(Traits::Remove(&impl_, key));
+    p.Reset();
+  }
+
  private:
   PersistentValueMapBase(PersistentValueMapBase&);
   void operator=(PersistentValueMapBase&);
@@ -351,17 +360,17 @@ class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
   /**
    * Put value into map. Depending on Traits::kIsWeak, the value will be held
    * by the map strongly or weakly.
-   * Returns old value as UniquePersistent.
+   * Returns old value as Global.
    */
-  UniquePersistent<V> Set(const K& key, Local<V> value) {
-    UniquePersistent<V> persistent(this->isolate(), value);
+  Global<V> Set(const K& key, Local<V> value) {
+    Global<V> persistent(this->isolate(), value);
     return SetUnique(key, &persistent);
   }
 
   /**
    * Put value into map, like Set(const K&, Local<V>).
    */
-  UniquePersistent<V> Set(const K& key, UniquePersistent<V> value) {
+  Global<V> Set(const K& key, Global<V> value) {
     return SetUnique(key, &value);
   }
 
@@ -369,7 +378,7 @@ class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
    * Put the value into the map, and set the 'weak' callback when demanded
    * by the Traits class.
    */
-  UniquePersistent<V> SetUnique(const K& key, UniquePersistent<V>* persistent) {
+  Global<V> SetUnique(const K& key, Global<V>* persistent) {
     if (Traits::kCallbackType != kNotWeak) {
       Local<V> value(Local<V>::New(this->isolate(), *persistent));
       persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
@@ -384,8 +393,8 @@ class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
    * Put a value into the map and update the reference.
    * Restrictions of GetReference apply here as well.
    */
-  UniquePersistent<V> Set(const K& key, UniquePersistent<V> value,
-                          PersistentValueReference* reference) {
+  Global<V> Set(const K& key, Global<V> value,
+                PersistentValueReference* reference) {
     *reference = this->Leak(&value);
     return SetUnique(key, &value);
   }
@@ -406,9 +415,9 @@ class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
 
 
 template <typename K, typename V, typename Traits>
-class PhantomPersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
+class GlobalValueMap : public PersistentValueMapBase<K, V, Traits> {
  public:
-  explicit PhantomPersistentValueMap(Isolate* isolate)
+  explicit GlobalValueMap(Isolate* isolate)
       : PersistentValueMapBase<K, V, Traits>(isolate) {}
 
   typedef
@@ -418,17 +427,17 @@ class PhantomPersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
   /**
    * Put value into map. Depending on Traits::kIsWeak, the value will be held
    * by the map strongly or weakly.
-   * Returns old value as UniquePersistent.
+   * Returns old value as Global.
    */
-  UniquePersistent<V> Set(const K& key, Local<V> value) {
-    UniquePersistent<V> persistent(this->isolate(), value);
+  Global<V> Set(const K& key, Local<V> value) {
+    Global<V> persistent(this->isolate(), value);
     return SetUnique(key, &persistent);
   }
 
   /**
    * Put value into map, like Set(const K&, Local<V>).
    */
-  UniquePersistent<V> Set(const K& key, UniquePersistent<V> value) {
+  Global<V> Set(const K& key, Global<V> value) {
     return SetUnique(key, &value);
   }
 
@@ -436,11 +445,16 @@ class PhantomPersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
    * Put the value into the map, and set the 'weak' callback when demanded
    * by the Traits class.
    */
-  UniquePersistent<V> SetUnique(const K& key, UniquePersistent<V>* persistent) {
+  Global<V> SetUnique(const K& key, Global<V>* persistent) {
     if (Traits::kCallbackType != kNotWeak) {
+      WeakCallbackType callback_type =
+          Traits::kCallbackType == kWeakWithInternalFields
+              ? WeakCallbackType::kInternalFields
+              : WeakCallbackType::kParameter;
       Local<V> value(Local<V>::New(this->isolate(), *persistent));
-      persistent->template SetPhantom<typename Traits::WeakCallbackDataType>(
-          Traits::WeakCallbackParameter(this, key, value), WeakCallback, 0, 1);
+      persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
+          Traits::WeakCallbackParameter(this, key, value), WeakCallback,
+          callback_type);
     }
     PersistentContainerValue old_value =
         Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
@@ -451,33 +465,32 @@ class PhantomPersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
    * Put a value into the map and update the reference.
    * Restrictions of GetReference apply here as well.
    */
-  UniquePersistent<V> Set(const K& key, UniquePersistent<V> value,
-                          PersistentValueReference* reference) {
+  Global<V> Set(const K& key, Global<V> value,
+                PersistentValueReference* reference) {
     *reference = this->Leak(&value);
     return SetUnique(key, &value);
   }
 
  private:
   static void WeakCallback(
-      const PhantomCallbackData<typename Traits::WeakCallbackDataType>& data) {
+      const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
     if (Traits::kCallbackType != kNotWeak) {
-      PhantomPersistentValueMap<K, V, Traits>* persistentValueMap =
-          Traits::MapFromPhantomCallbackData(data);
-      K key = Traits::KeyFromPhantomCallbackData(data);
-      Traits::Dispose(data.GetIsolate(), persistentValueMap->Remove(key).Pass(),
-                      key);
-      Traits::DisposeCallbackData(data.GetParameter());
+      GlobalValueMap<K, V, Traits>* persistentValueMap =
+          Traits::MapFromWeakCallbackInfo(data);
+      K key = Traits::KeyFromWeakCallbackInfo(data);
+      persistentValueMap->RemoveWeak(key);
+      Traits::DisposeWeak(data.GetIsolate(), data, key);
     }
   }
 };
 
 
 /**
- * A map that uses UniquePersistent as value and std::map as the backing
+ * A map that uses Global as value and std::map as the backing
  * implementation. Persistents are held non-weak.
  *
  * C++11 embedders don't need this class, as they can use
- * UniquePersistent directly in std containers.
+ * Global directly in std containers.
  */
 template<typename K, typename V,
     typename Traits = DefaultPersistentValueMapTraits<K, V> >
@@ -514,8 +527,8 @@ class DefaultPersistentValueVectorTraits {
 
 
 /**
- * A vector wrapper that safely stores UniquePersistent values.
- * C++11 embedders don't need this class, as they can use UniquePersistent
+ * A vector wrapper that safely stores Global values.
+ * C++11 embedders don't need this class, as they can use Global
  * directly in std containers.
  *
  * This class relies on a backing vector implementation, whose type and methods
@@ -536,14 +549,14 @@ class PersistentValueVector {
    * Append a value to the vector.
    */
   void Append(Local<V> value) {
-    UniquePersistent<V> persistent(isolate_, value);
+    Global<V> persistent(isolate_, value);
     Traits::Append(&impl_, ClearAndLeak(&persistent));
   }
 
   /**
    * Append a persistent's value to the vector.
    */
-  void Append(UniquePersistent<V> persistent) {
+  void Append(Global<V> persistent) {
     Traits::Append(&impl_, ClearAndLeak(&persistent));
   }
 
@@ -574,7 +587,7 @@ class PersistentValueVector {
   void Clear() {
     size_t length = Traits::Size(&impl_);
     for (size_t i = 0; i < length; i++) {
-      UniquePersistent<V> p;
+      Global<V> p;
       p.val_ = FromVal(Traits::Get(&impl_, i));
     }
     Traits::Clear(&impl_);
@@ -589,8 +602,7 @@ class PersistentValueVector {
   }
 
  private:
-  static PersistentContainerValue ClearAndLeak(
-      UniquePersistent<V>* persistent) {
+  static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
     V* v = persistent->val_;
     persistent->val_ = 0;
     return reinterpret_cast<PersistentContainerValue>(v);
@@ -606,4 +618,4 @@ class PersistentValueVector {
 
 }  // namespace v8
 
-#endif  // V8_UTIL_H_
+#endif  // V8_UTIL_H
index b20ccdb..9cdb125 100644 (file)
@@ -9,8 +9,8 @@
 // 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 V8_MAJOR_VERSION 4
-#define V8_MINOR_VERSION 2
-#define V8_BUILD_NUMBER 77
+#define V8_MINOR_VERSION 3
+#define V8_BUILD_NUMBER 61
 #define V8_PATCH_LEVEL 21
 
 // Use 1 for candidates and 0 otherwise.
index e325fd6..d3543f2 100644 (file)
@@ -81,6 +81,8 @@ class ImplementationUtilities;
 class Int32;
 class Integer;
 class Isolate;
+template <class T>
+class Maybe;
 class Name;
 class Number;
 class NumberObject;
@@ -93,6 +95,7 @@ class Promise;
 class RawOperationDescriptor;
 class Script;
 class Signature;
+class StartupData;
 class StackFrame;
 class StackTrace;
 class String;
@@ -105,17 +108,20 @@ class Utils;
 class Value;
 template <class T> class Handle;
 template <class T> class Local;
+template <class T>
+class MaybeLocal;
 template <class T> class Eternal;
 template<class T> class NonCopyablePersistentTraits;
 template<class T> class PersistentBase;
 template<class T,
          class M = NonCopyablePersistentTraits<T> > class Persistent;
-template<class T> class UniquePersistent;
+template <class T>
+class Global;
 template<class K, class V, class T> class PersistentValueMap;
 template <class K, class V, class T>
 class PersistentValueMapBase;
 template <class K, class V, class T>
-class PhantomPersistentValueMap;
+class GlobalValueMap;
 template<class V, class T> class PersistentValueVector;
 template<class T, class P> class WeakCallbackObject;
 class FunctionTemplate;
@@ -141,20 +147,6 @@ template<typename T> class CustomArguments;
 class PropertyCallbackArguments;
 class FunctionCallbackArguments;
 class GlobalHandles;
-
-template <typename T>
-class CallbackData {
- public:
-  V8_INLINE v8::Isolate* GetIsolate() const { return isolate_; }
-
-  explicit CallbackData(v8::Isolate* isolate, T* parameter)
-      : isolate_(isolate), parameter_(parameter) {}
-  V8_INLINE T* GetParameter() const { return parameter_; }
-
- private:
-  v8::Isolate* isolate_;
-  T* parameter_;
-};
 }
 
 
@@ -321,6 +313,8 @@ template <class T> class Handle {
   template<class F> friend class PersistentBase;
   template<class F> friend class Handle;
   template<class F> friend class Local;
+  template <class F>
+  friend class MaybeLocal;
   template<class F> friend class FunctionCallbackInfo;
   template<class F> friend class PropertyCallbackInfo;
   template<class F> friend class internal::CustomArguments;
@@ -398,6 +392,8 @@ template <class T> class Local : public Handle<T> {
   template<class F, class M> friend class Persistent;
   template<class F> friend class Handle;
   template<class F> friend class Local;
+  template <class F>
+  friend class MaybeLocal;
   template<class F> friend class FunctionCallbackInfo;
   template<class F> friend class PropertyCallbackInfo;
   friend class String;
@@ -415,6 +411,47 @@ template <class T> class Local : public Handle<T> {
 };
 
 
+/**
+ * A MaybeLocal<> is a wrapper around Local<> that enforces a check whether
+ * the Local<> is empty before it can be used.
+ *
+ * If an API method returns a MaybeLocal<>, the API method can potentially fail
+ * either because an exception is thrown, or because an exception is pending,
+ * e.g. because a previous API call threw an exception that hasn't been caught
+ * yet, or because a TerminateExecution exception was thrown. In that case, an
+ * empty MaybeLocal is returned.
+ */
+template <class T>
+class MaybeLocal {
+ public:
+  V8_INLINE MaybeLocal() : val_(nullptr) {}
+  template <class S>
+  V8_INLINE MaybeLocal(Local<S> that)
+      : val_(reinterpret_cast<T*>(*that)) {
+    TYPE_CHECK(T, S);
+  }
+
+  V8_INLINE bool IsEmpty() const { return val_ == nullptr; }
+
+  template <class S>
+  V8_WARN_UNUSED_RESULT V8_INLINE bool ToLocal(Local<S>* out) const {
+    out->val_ = IsEmpty() ? nullptr : this->val_;
+    return !IsEmpty();
+  }
+
+  // Will crash when checks are enabled if the MaybeLocal<> is empty.
+  V8_INLINE Local<T> ToLocalChecked();
+
+  template <class S>
+  V8_INLINE Local<S> FromMaybe(Local<S> default_value) const {
+    return IsEmpty() ? default_value : Local<S>(val_);
+  }
+
+ private:
+  T* val_;
+};
+
+
 // Eternal handles are set-once handles that live for the life of the isolate.
 template <class T> class Eternal {
  public:
@@ -434,42 +471,79 @@ template <class T> class Eternal {
 };
 
 
+static const int kInternalFieldsInWeakCallback = 2;
+
+
 template <typename T>
-class PhantomCallbackData : public internal::CallbackData<T> {
+class WeakCallbackInfo {
  public:
-  typedef void (*Callback)(const PhantomCallbackData<T>& data);
+  typedef void (*Callback)(const WeakCallbackInfo<T>& data);
+
+  WeakCallbackInfo(Isolate* isolate, T* parameter,
+                   void* internal_fields[kInternalFieldsInWeakCallback],
+                   Callback* callback)
+      : isolate_(isolate), parameter_(parameter), callback_(callback) {
+    for (int i = 0; i < kInternalFieldsInWeakCallback; ++i) {
+      internal_fields_[i] = internal_fields[i];
+    }
+  }
+
+  V8_INLINE Isolate* GetIsolate() const { return isolate_; }
+  V8_INLINE T* GetParameter() const { return parameter_; }
+  V8_INLINE void* GetInternalField(int index) const;
 
-  V8_INLINE void* GetInternalField1() const { return internal_field1_; }
-  V8_INLINE void* GetInternalField2() const { return internal_field2_; }
+  V8_INLINE V8_DEPRECATE_SOON("use indexed version",
+                              void* GetInternalField1()) const {
+    return internal_fields_[0];
+  }
+  V8_INLINE V8_DEPRECATE_SOON("use indexed version",
+                              void* GetInternalField2()) const {
+    return internal_fields_[1];
+  }
 
-  PhantomCallbackData(Isolate* isolate, T* parameter, void* internal_field1,
-                      void* internal_field2)
-      : internal::CallbackData<T>(isolate, parameter),
-        internal_field1_(internal_field1),
-        internal_field2_(internal_field2) {}
+  bool IsFirstPass() const { return callback_ != nullptr; }
+
+  // When first called, the embedder MUST Reset() the Global which triggered the
+  // callback. The Global itself is unusable for anything else. No v8 other api
+  // calls may be called in the first callback. Should additional work be
+  // required, the embedder must set a second pass callback, which will be
+  // called after all the initial callbacks are processed.
+  // Calling SetSecondPassCallback on the second pass will immediately crash.
+  void SetSecondPassCallback(Callback callback) const { *callback_ = callback; }
 
  private:
-  void* internal_field1_;
-  void* internal_field2_;
+  Isolate* isolate_;
+  T* parameter_;
+  Callback* callback_;
+  void* internal_fields_[kInternalFieldsInWeakCallback];
 };
 
 
 template <class T, class P>
-class WeakCallbackData : public internal::CallbackData<P> {
+class WeakCallbackData {
  public:
   typedef void (*Callback)(const WeakCallbackData<T, P>& data);
 
+  WeakCallbackData(Isolate* isolate, P* parameter, Local<T> handle)
+      : isolate_(isolate), parameter_(parameter), handle_(handle) {}
+
+  V8_INLINE Isolate* GetIsolate() const { return isolate_; }
+  V8_INLINE P* GetParameter() const { return parameter_; }
   V8_INLINE Local<T> GetValue() const { return handle_; }
 
  private:
-  friend class internal::GlobalHandles;
-  WeakCallbackData(Isolate* isolate, P* parameter, Local<T> handle)
-      : internal::CallbackData<P>(isolate, parameter), handle_(handle) {}
+  Isolate* isolate_;
+  P* parameter_;
   Local<T> handle_;
 };
 
 
-static const int kNoInternalFieldIndex = -1;
+// TODO(dcarney): delete this with WeakCallbackData
+template <class T>
+using PhantomCallbackData = WeakCallbackInfo<T>;
+
+
+enum class WeakCallbackType { kParameter, kInternalFields };
 
 
 /**
@@ -542,15 +616,17 @@ template <class T> class PersistentBase {
    *  As always, GC-based finalization should *not* be relied upon for any
    *  critical form of resource management!
    */
-  template<typename P>
-  V8_INLINE void SetWeak(
-      P* parameter,
-      typename WeakCallbackData<T, P>::Callback callback);
+  template <typename P>
+  V8_INLINE V8_DEPRECATE_SOON(
+      "use WeakCallbackInfo version",
+      void SetWeak(P* parameter,
+                   typename WeakCallbackData<T, P>::Callback callback));
 
-  template<typename S, typename P>
-  V8_INLINE void SetWeak(
-      P* parameter,
-      typename WeakCallbackData<S, P>::Callback callback);
+  template <typename S, typename P>
+  V8_INLINE V8_DEPRECATE_SOON(
+      "use WeakCallbackInfo version",
+      void SetWeak(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.
@@ -559,10 +635,17 @@ template <class T> class PersistentBase {
   // 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,
-                            int internal_field_index1 = kNoInternalFieldIndex,
-                            int internal_field_index2 = kNoInternalFieldIndex);
+  V8_INLINE V8_DEPRECATE_SOON(
+      "use SetWeak",
+      void SetPhantom(P* parameter,
+                      typename WeakCallbackInfo<P>::Callback callback,
+                      int internal_field_index1 = -1,
+                      int internal_field_index2 = -1));
+
+  template <typename P>
+  V8_INLINE void SetWeak(P* parameter,
+                         typename WeakCallbackInfo<P>::Callback callback,
+                         WeakCallbackType type);
 
   template<typename P>
   V8_INLINE P* ClearWeak();
@@ -614,7 +697,8 @@ template <class T> class PersistentBase {
   template<class F> friend class Handle;
   template<class F> friend class Local;
   template<class F1, class F2> friend class Persistent;
-  template<class F> friend class UniquePersistent;
+  template <class F>
+  friend class Global;
   template<class F> friend class PersistentBase;
   template<class F> friend class ReturnValue;
   template <class F1, class F2, class F3>
@@ -623,8 +707,8 @@ template <class T> class PersistentBase {
   friend class Object;
 
   explicit V8_INLINE PersistentBase(T* val) : val_(val) {}
-  PersistentBase(PersistentBase& other); // NOLINT
-  void operator=(PersistentBase&);
+  PersistentBase(PersistentBase& other) = delete;  // NOLINT
+  void operator=(PersistentBase&) = delete;
   V8_INLINE static T* New(Isolate* isolate, T* that);
 
   T* val_;
@@ -770,72 +854,74 @@ template <class T, class M> class Persistent : public PersistentBase<T> {
  *
  * Note: Persistent class hierarchy is subject to future changes.
  */
-template<class T>
-class UniquePersistent : public PersistentBase<T> {
-  struct RValue {
-    V8_INLINE explicit RValue(UniquePersistent* obj) : object(obj) {}
-    UniquePersistent* object;
-  };
-
+template <class T>
+class Global : public PersistentBase<T> {
  public:
   /**
-   * A UniquePersistent with no storage cell.
+   * A Global with no storage cell.
    */
-  V8_INLINE UniquePersistent() : PersistentBase<T>(0) { }
+  V8_INLINE Global() : PersistentBase<T>(nullptr) {}
   /**
-   * Construct a UniquePersistent from a Handle.
+   * Construct a Global from a Handle.
    * When the Handle is non-empty, a new storage cell is created
    * pointing to the same object, and no flags are set.
    */
   template <class S>
-  V8_INLINE UniquePersistent(Isolate* isolate, Handle<S> that)
+  V8_INLINE Global(Isolate* isolate, Handle<S> that)
       : PersistentBase<T>(PersistentBase<T>::New(isolate, *that)) {
     TYPE_CHECK(T, S);
   }
   /**
-   * Construct a UniquePersistent from a PersistentBase.
+   * Construct a Global from a PersistentBase.
    * When the Persistent is non-empty, a new storage cell is created
    * pointing to the same object, and no flags are set.
    */
   template <class S>
-  V8_INLINE UniquePersistent(Isolate* isolate, const PersistentBase<S>& that)
-    : PersistentBase<T>(PersistentBase<T>::New(isolate, that.val_)) {
+  V8_INLINE Global(Isolate* isolate, const PersistentBase<S>& that)
+      : PersistentBase<T>(PersistentBase<T>::New(isolate, that.val_)) {
     TYPE_CHECK(T, S);
   }
   /**
    * Move constructor.
    */
-  V8_INLINE UniquePersistent(RValue rvalue)
-    : PersistentBase<T>(rvalue.object->val_) {
-    rvalue.object->val_ = 0;
+  V8_INLINE Global(Global&& other) : PersistentBase<T>(other.val_) {
+    other.val_ = nullptr;
   }
-  V8_INLINE ~UniquePersistent() { this->Reset(); }
+  V8_INLINE ~Global() { this->Reset(); }
   /**
    * Move via assignment.
    */
-  template<class S>
-  V8_INLINE UniquePersistent& operator=(UniquePersistent<S> rhs) {
+  template <class S>
+  V8_INLINE Global& operator=(Global<S>&& rhs) {
     TYPE_CHECK(T, S);
-    this->Reset();
-    this->val_ = rhs.val_;
-    rhs.val_ = 0;
+    if (this != &rhs) {
+      this->Reset();
+      this->val_ = rhs.val_;
+      rhs.val_ = nullptr;
+    }
     return *this;
   }
   /**
-   * Cast operator for moves.
-   */
-  V8_INLINE operator RValue() { return RValue(this); }
-  /**
    * Pass allows returning uniques from functions, etc.
    */
-  UniquePersistent Pass() { return UniquePersistent(RValue(this)); }
+  Global Pass() { return static_cast<Global&&>(*this); }
+
+  /*
+   * For compatibility with Chromium's base::Bind (base::Passed).
+   */
+  typedef void MoveOnlyTypeForCPP03;
 
  private:
-  UniquePersistent(UniquePersistent&);
-  void operator=(UniquePersistent&);
+  Global(Global&) = delete;
+  void operator=(Global&) = delete;
 };
 
 
+// UniquePersistent is an alias for Global for historical reason.
+template <class T>
+using UniquePersistent = Global<T>;
+
+
  /**
  * A stack-allocated class that governs a number of local handles.
  * After a handle scope has been created, all local handles will be
@@ -951,28 +1037,6 @@ class V8_EXPORT SealHandleScope {
 };
 
 
-/**
- * A simple Maybe type, representing an object which may or may not have a
- * value.
- */
-template<class T>
-struct Maybe {
-  Maybe() : has_value(false) {}
-  explicit Maybe(T t) : has_value(true), value(t) {}
-  Maybe(bool has, T t) : has_value(has), value(t) {}
-
-  bool has_value;
-  T value;
-};
-
-
-// Convenience wrapper.
-template <class T>
-inline Maybe<T> maybe(T t) {
-  return Maybe<T>(t);
-}
-
-
 // --- Special objects ---
 
 
@@ -996,13 +1060,15 @@ class ScriptOrigin {
       Handle<Integer> resource_column_offset = Handle<Integer>(),
       Handle<Boolean> resource_is_shared_cross_origin = Handle<Boolean>(),
       Handle<Integer> script_id = Handle<Integer>(),
-      Handle<Boolean> resource_is_embedder_debug_script = Handle<Boolean>())
+      Handle<Boolean> resource_is_embedder_debug_script = Handle<Boolean>(),
+      Handle<Value> source_map_url = Handle<Value>())
       : resource_name_(resource_name),
         resource_line_offset_(resource_line_offset),
         resource_column_offset_(resource_column_offset),
         resource_is_embedder_debug_script_(resource_is_embedder_debug_script),
         resource_is_shared_cross_origin_(resource_is_shared_cross_origin),
-        script_id_(script_id) {}
+        script_id_(script_id),
+        source_map_url_(source_map_url) {}
   V8_INLINE Handle<Value> ResourceName() const;
   V8_INLINE Handle<Integer> ResourceLineOffset() const;
   V8_INLINE Handle<Integer> ResourceColumnOffset() const;
@@ -1012,6 +1078,7 @@ class ScriptOrigin {
   V8_INLINE Handle<Boolean> ResourceIsEmbedderDebugScript() const;
   V8_INLINE Handle<Boolean> ResourceIsSharedCrossOrigin() const;
   V8_INLINE Handle<Integer> ScriptID() const;
+  V8_INLINE Handle<Value> SourceMapUrl() const;
 
  private:
   Handle<Value> resource_name_;
@@ -1020,6 +1087,7 @@ class ScriptOrigin {
   Handle<Boolean> resource_is_embedder_debug_script_;
   Handle<Boolean> resource_is_shared_cross_origin_;
   Handle<Integer> script_id_;
+  Handle<Value> source_map_url_;
 };
 
 
@@ -1064,19 +1132,25 @@ class V8_EXPORT Script {
   /**
    * A shorthand for ScriptCompiler::Compile().
    */
-  static Local<Script> Compile(Handle<String> source,
-                               ScriptOrigin* origin = NULL);
+  static V8_DEPRECATE_SOON(
+      "Use maybe version",
+      Local<Script> Compile(Handle<String> source,
+                            ScriptOrigin* origin = nullptr));
+  static MaybeLocal<Script> Compile(Local<Context> context,
+                                    Handle<String> source,
+                                    ScriptOrigin* origin = nullptr);
 
-  // To be decprecated, use the Compile above.
-  static Local<Script> Compile(Handle<String> source,
-                               Handle<String> file_name);
+  static Local<Script> V8_DEPRECATE_SOON("Use maybe version",
+                                         Compile(Handle<String> source,
+                                                 Handle<String> file_name));
 
   /**
    * Runs the script returning the resulting value. It will be run in the
    * context in which it was created (ScriptCompiler::CompileBound or
    * UnboundScript::BindToCurrentContext()).
    */
-  Local<Value> Run();
+  V8_DEPRECATE_SOON("Use maybe version", Local<Value> Run());
+  MaybeLocal<Value> Run(Local<Context> context);
 
   /**
    * Returns the corresponding context-unbound script.
@@ -1165,6 +1239,7 @@ class V8_EXPORT ScriptCompiler {
     Handle<Integer> resource_column_offset;
     Handle<Boolean> resource_is_embedder_debug_script;
     Handle<Boolean> resource_is_shared_cross_origin;
+    Handle<Value> source_map_url;
 
     // Cached data from previous compilation (if a kConsume*Cache flag is
     // set), or hold newly generated cache data (kProduce*Cache flags) are
@@ -1263,7 +1338,11 @@ class V8_EXPORT ScriptCompiler {
    * \return Compiled script object (context independent; for running it must be
    *   bound to a context).
    */
-  static Local<UnboundScript> CompileUnbound(
+  static V8_DEPRECATE_SOON("Use maybe version",
+                           Local<UnboundScript> CompileUnbound(
+                               Isolate* isolate, Source* source,
+                               CompileOptions options = kNoCompileOptions));
+  static MaybeLocal<UnboundScript> CompileUnboundScript(
       Isolate* isolate, Source* source,
       CompileOptions options = kNoCompileOptions);
 
@@ -1278,9 +1357,12 @@ class V8_EXPORT ScriptCompiler {
    *   when this function was called. When run it will always use this
    *   context.
    */
-  static Local<Script> Compile(
-      Isolate* isolate, Source* source,
-      CompileOptions options = kNoCompileOptions);
+  static V8_DEPRECATE_SOON(
+      "Use maybe version",
+      Local<Script> Compile(Isolate* isolate, Source* source,
+                            CompileOptions options = kNoCompileOptions));
+  static MaybeLocal<Script> Compile(Local<Context> context, Source* source,
+                                    CompileOptions options = kNoCompileOptions);
 
   /**
    * Returns a task which streams script data into V8, or NULL if the script
@@ -1304,9 +1386,15 @@ class V8_EXPORT ScriptCompiler {
    * (ScriptStreamingTask has been run). V8 doesn't construct the source string
    * during streaming, so the embedder needs to pass the full source here.
    */
-  static Local<Script> Compile(Isolate* isolate, StreamedSource* source,
-                               Handle<String> full_source_string,
-                               const ScriptOrigin& origin);
+  static V8_DEPRECATE_SOON(
+      "Use maybe version",
+      Local<Script> Compile(Isolate* isolate, StreamedSource* source,
+                            Handle<String> full_source_string,
+                            const ScriptOrigin& origin));
+  static MaybeLocal<Script> Compile(Local<Context> context,
+                                    StreamedSource* source,
+                                    Handle<String> full_source_string,
+                                    const ScriptOrigin& origin);
 
   /**
    * Return a version tag for CachedData for the current V8 version & flags.
@@ -1336,8 +1424,12 @@ class V8_EXPORT ScriptCompiler {
    * TODO(adamk): Script is likely the wrong return value for this;
    * should return some new Module type.
    */
-  static Local<Script> CompileModule(
-      Isolate* isolate, Source* source,
+  static V8_DEPRECATE_SOON(
+      "Use maybe version",
+      Local<Script> CompileModule(Isolate* isolate, Source* source,
+                                  CompileOptions options = kNoCompileOptions));
+  static MaybeLocal<Script> CompileModule(
+      Local<Context> context, Source* source,
       CompileOptions options = kNoCompileOptions);
 
   /**
@@ -1350,16 +1442,21 @@ class V8_EXPORT ScriptCompiler {
    * It is possible to specify multiple context extensions (obj in the above
    * example).
    */
-  static Local<Function> CompileFunctionInContext(
-      Isolate* isolate, Source* source, Local<Context> context,
-      size_t arguments_count, Local<String> arguments[],
-      size_t context_extension_count, Local<Object> context_extensions[]);
+  static V8_DEPRECATE_SOON("Use maybe version",
+                           Local<Function> CompileFunctionInContext(
+                               Isolate* isolate, Source* source,
+                               Local<Context> context, size_t arguments_count,
+                               Local<String> arguments[],
+                               size_t context_extension_count,
+                               Local<Object> context_extensions[]));
+  static MaybeLocal<Function> CompileFunctionInContext(
+      Local<Context> context, Source* source, size_t arguments_count,
+      Local<String> arguments[], size_t context_extension_count,
+      Local<Object> context_extensions[]);
 
  private:
-  static Local<UnboundScript> CompileUnboundInternal(Isolate* isolate,
-                                                     Source* source,
-                                                     CompileOptions options,
-                                                     bool is_module);
+  static MaybeLocal<UnboundScript> CompileUnboundInternal(
+      Isolate* isolate, Source* source, CompileOptions options, bool is_module);
 };
 
 
@@ -1369,7 +1466,9 @@ class V8_EXPORT ScriptCompiler {
 class V8_EXPORT Message {
  public:
   Local<String> Get() const;
-  Local<String> GetSourceLine() const;
+
+  V8_DEPRECATE_SOON("Use maybe version", Local<String> GetSourceLine()) const;
+  MaybeLocal<String> GetSourceLine(Local<Context> context) const;
 
   /**
    * Returns the origin for the script from where the function causing the
@@ -1393,7 +1492,8 @@ class V8_EXPORT Message {
   /**
    * Returns the number, 1-based, of the line where the error occurred.
    */
-  int GetLineNumber() const;
+  V8_DEPRECATE_SOON("Use maybe version", int GetLineNumber()) const;
+  Maybe<int> GetLineNumber(Local<Context> context) const;
 
   /**
    * Returns the index within the script of the first character where
@@ -1411,13 +1511,15 @@ class V8_EXPORT Message {
    * Returns the index within the line of the first character where
    * the error occurred.
    */
-  int GetStartColumn() const;
+  V8_DEPRECATE_SOON("Use maybe version", int GetStartColumn()) const;
+  Maybe<int> GetStartColumn(Local<Context> context) const;
 
   /**
    * Returns the index within the line of the last character where
    * the error occurred.
    */
-  int GetEndColumn() const;
+  V8_DEPRECATE_SOON("Use maybe version", int GetEndColumn()) const;
+  Maybe<int> GetEndColumn(Local<Context> context) const;
 
   /**
    * Passes on the value set by the embedder when it fed the script from which
@@ -1584,7 +1686,9 @@ class V8_EXPORT JSON {
    * \param json_string The string to parse.
    * \return The corresponding value if successfully parsed.
    */
-  static Local<Value> Parse(Local<String> json_string);
+  static V8_DEPRECATE_SOON("Use maybe version",
+                           Local<Value> Parse(Local<String> json_string));
+  static MaybeLocal<Value> Parse(Isolate* isolate, Local<String> json_string);
 };
 
 
@@ -1864,39 +1968,66 @@ class V8_EXPORT Value : public Data {
    */
   bool IsDataView() 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;
+  MaybeLocal<Boolean> ToBoolean(Local<Context> context) const;
+  MaybeLocal<Number> ToNumber(Local<Context> context) const;
+  MaybeLocal<String> ToString(Local<Context> context) const;
+  MaybeLocal<String> ToDetailString(Local<Context> context) const;
+  MaybeLocal<Object> ToObject(Local<Context> context) const;
+  MaybeLocal<Integer> ToInteger(Local<Context> context) const;
+  MaybeLocal<Uint32> ToUint32(Local<Context> context) const;
+  MaybeLocal<Int32> ToInt32(Local<Context> context) const;
+
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Boolean> ToBoolean(Isolate* isolate)) const;
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Number> ToNumber(Isolate* isolate)) const;
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<String> ToString(Isolate* isolate)) const;
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<String> ToDetailString(Isolate* isolate)) const;
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Object> ToObject(Isolate* isolate)) const;
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Integer> ToInteger(Isolate* isolate)) const;
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Uint32> ToUint32(Isolate* isolate)) const;
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Int32> ToInt32(Isolate* isolate)) const;
+
+  inline V8_DEPRECATE_SOON("Use maybe version",
+                           Local<Boolean> ToBoolean()) const;
+  inline V8_DEPRECATE_SOON("Use maybe version", Local<Number> ToNumber()) const;
+  inline V8_DEPRECATE_SOON("Use maybe version", Local<String> ToString()) const;
+  inline V8_DEPRECATE_SOON("Use maybe version",
+                           Local<String> ToDetailString()) const;
+  inline V8_DEPRECATE_SOON("Use maybe version", Local<Object> ToObject()) const;
+  inline V8_DEPRECATE_SOON("Use maybe version",
+                           Local<Integer> ToInteger()) const;
+  inline V8_DEPRECATE_SOON("Use maybe version", Local<Uint32> ToUint32()) const;
+  inline V8_DEPRECATE_SOON("Use maybe version", Local<Int32> ToInt32()) const;
 
   /**
    * Attempts to convert a string to an array index.
    * Returns an empty handle if the conversion fails.
    */
-  Local<Uint32> ToArrayIndex() const;
+  V8_DEPRECATE_SOON("Use maybe version", Local<Uint32> ToArrayIndex()) const;
+  MaybeLocal<Uint32> ToArrayIndex(Local<Context> context) const;
 
-  bool BooleanValue() const;
-  double NumberValue() const;
-  int64_t IntegerValue() const;
-  uint32_t Uint32Value() const;
-  int32_t Int32Value() const;
+  Maybe<bool> BooleanValue(Local<Context> context) const;
+  Maybe<double> NumberValue(Local<Context> context) const;
+  Maybe<int64_t> IntegerValue(Local<Context> context) const;
+  Maybe<uint32_t> Uint32Value(Local<Context> context) const;
+  Maybe<int32_t> Int32Value(Local<Context> context) const;
+
+  V8_DEPRECATE_SOON("Use maybe version", bool BooleanValue()) const;
+  V8_DEPRECATE_SOON("Use maybe version", double NumberValue()) const;
+  V8_DEPRECATE_SOON("Use maybe version", int64_t IntegerValue()) const;
+  V8_DEPRECATE_SOON("Use maybe version", uint32_t Uint32Value()) const;
+  V8_DEPRECATE_SOON("Use maybe version", int32_t Int32Value()) const;
 
   /** JS == */
-  bool Equals(Handle<Value> that) const;
+  V8_DEPRECATE_SOON("Use maybe version", bool Equals(Handle<Value> that)) const;
+  Maybe<bool> Equals(Local<Context> context, Handle<Value> that) const;
   bool StrictEquals(Handle<Value> that) const;
   bool SameValue(Handle<Value> that) const;
 
@@ -1925,7 +2056,10 @@ class V8_EXPORT Primitive : public Value { };
 class V8_EXPORT Boolean : public Primitive {
  public:
   bool Value() const;
+  V8_INLINE static Boolean* Cast(v8::Value* obj);
   V8_INLINE static Handle<Boolean> New(Isolate* isolate, bool value);
+ private:
+  static void CheckCast(v8::Value* obj);
 };
 
 
@@ -1949,11 +2083,16 @@ class V8_EXPORT Name : public Primitive {
 };
 
 
+enum class NewStringType { kNormal, kInternalized };
+
+
 /**
  * A JavaScript string value (ECMA-262, 4.3.17).
  */
 class V8_EXPORT String : public Name {
  public:
+  static const int kMaxLength = (1 << 28) - 16;
+
   enum Encoding {
     UNKNOWN_ENCODING = 0x1,
     TWO_BYTE_ENCODING = 0x0,
@@ -2150,26 +2289,52 @@ class V8_EXPORT String : public Name {
 
   V8_INLINE static String* Cast(v8::Value* obj);
 
-  enum NewStringType { kNormalString, kInternalizedString };
+  // TODO(dcarney): remove with deprecation of New functions.
+  enum NewStringType {
+    kNormalString = static_cast<int>(v8::NewStringType::kNormal),
+    kInternalizedString = static_cast<int>(v8::NewStringType::kInternalized)
+  };
 
   /** Allocates a new string from UTF-8 data.*/
-  static Local<String> NewFromUtf8(Isolate* isolate, const char* data,
-                                   NewStringType type = kNormalString,
-                                   int length = -1);
+  static V8_DEPRECATE_SOON(
+      "Use maybe version",
+      Local<String> NewFromUtf8(Isolate* isolate, const char* data,
+                                NewStringType type = kNormalString,
+                                int length = -1));
+
+  /** Allocates a new string from UTF-8 data. Only returns an empty value when
+   * length > kMaxLength. **/
+  static MaybeLocal<String> NewFromUtf8(Isolate* isolate, const char* data,
+                                        v8::NewStringType type,
+                                        int length = -1);
 
   /** Allocates a new string from Latin-1 data.*/
-  static Local<String> NewFromOneByte(
-      Isolate* isolate,
-      const uint8_t* data,
-      NewStringType type = kNormalString,
-      int length = -1);
+  static V8_DEPRECATE_SOON(
+      "Use maybe version",
+      Local<String> NewFromOneByte(Isolate* isolate, const uint8_t* data,
+                                   NewStringType type = kNormalString,
+                                   int length = -1));
+
+  /** Allocates a new string from Latin-1 data.  Only returns an empty value
+   * when length > kMaxLength. **/
+  static MaybeLocal<String> NewFromOneByte(Isolate* isolate,
+                                           const uint8_t* data,
+                                           v8::NewStringType type,
+                                           int length = -1);
 
   /** Allocates a new string from UTF-16 data.*/
-  static Local<String> NewFromTwoByte(
-      Isolate* isolate,
-      const uint16_t* data,
-      NewStringType type = kNormalString,
-      int length = -1);
+  static V8_DEPRECATE_SOON(
+      "Use maybe version",
+      Local<String> NewFromTwoByte(Isolate* isolate, const uint16_t* data,
+                                   NewStringType type = kNormalString,
+                                   int length = -1));
+
+  /** Allocates a new string from UTF-16 data. Only returns an empty value when
+   * length > kMaxLength. **/
+  static MaybeLocal<String> NewFromTwoByte(Isolate* isolate,
+                                           const uint16_t* data,
+                                           v8::NewStringType type,
+                                           int length = -1);
 
   /**
    * Creates a new string by concatenating the left and the right strings
@@ -2185,8 +2350,12 @@ class V8_EXPORT String : public Name {
    * should the underlying buffer be deallocated or modified except through the
    * destructor of the external string resource.
    */
-  static Local<String> NewExternal(Isolate* isolate,
-                                   ExternalStringResource* resource);
+  static V8_DEPRECATE_SOON(
+      "Use maybe version",
+      Local<String> NewExternal(Isolate* isolate,
+                                ExternalStringResource* resource));
+  static MaybeLocal<String> NewExternalTwoByte(
+      Isolate* isolate, ExternalStringResource* resource);
 
   /**
    * Associate an external string resource with this string by transforming it
@@ -2207,8 +2376,12 @@ class V8_EXPORT String : public Name {
    * should the underlying buffer be deallocated or modified except through the
    * destructor of the external string resource.
    */
-  static Local<String> NewExternal(Isolate* isolate,
-                                   ExternalOneByteStringResource* resource);
+  static V8_DEPRECATE_SOON(
+      "Use maybe version",
+      Local<String> NewExternal(Isolate* isolate,
+                                ExternalOneByteStringResource* resource));
+  static MaybeLocal<String> NewExternalOneByte(
+      Isolate* isolate, ExternalOneByteStringResource* resource);
 
   /**
    * Associate an external string resource with this string by transforming it
@@ -2380,8 +2553,11 @@ class V8_EXPORT Integer : public Number {
 class V8_EXPORT Int32 : public Integer {
  public:
   int32_t Value() const;
+  V8_INLINE static Int32* Cast(v8::Value* obj);
+
  private:
   Int32();
+  static void CheckCast(v8::Value* obj);
 };
 
 
@@ -2391,8 +2567,11 @@ class V8_EXPORT Int32 : public Integer {
 class V8_EXPORT Uint32 : public Integer {
  public:
   uint32_t Value() const;
+  V8_INLINE static Uint32* Cast(v8::Value* obj);
+
  private:
   Uint32();
+  static void CheckCast(v8::Value* obj);
 };
 
 
@@ -2471,9 +2650,13 @@ enum AccessControl {
  */
 class V8_EXPORT Object : public Value {
  public:
-  bool Set(Handle<Value> key, Handle<Value> value);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    bool Set(Handle<Value> key, Handle<Value> value));
+  Maybe<bool> Set(Local<Context> context, Local<Value> key, Local<Value> value);
 
-  bool Set(uint32_t index, Handle<Value> value);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    bool Set(uint32_t index, Handle<Value> value));
+  Maybe<bool> Set(Local<Context> context, uint32_t index, Local<Value> value);
 
   // Sets an own property on this object bypassing interceptors and
   // overriding accessors or read-only properties.
@@ -2483,46 +2666,68 @@ class V8_EXPORT Object : public Value {
   // will only be returned if the interceptor doesn't return a value.
   //
   // Note also that this only works for named properties.
-  bool ForceSet(Handle<Value> key,
-                Handle<Value> value,
-                PropertyAttribute attribs = None);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    bool ForceSet(Handle<Value> key, Handle<Value> value,
+                                  PropertyAttribute attribs = None));
+  Maybe<bool> ForceSet(Local<Context> context, Local<Value> key,
+                       Local<Value> value, PropertyAttribute attribs = None);
 
-  Local<Value> Get(Handle<Value> key);
+  V8_DEPRECATE_SOON("Use maybe version", Local<Value> Get(Handle<Value> key));
+  MaybeLocal<Value> Get(Local<Context> context, Local<Value> key);
 
-  Local<Value> Get(uint32_t index);
+  V8_DEPRECATE_SOON("Use maybe version", Local<Value> Get(uint32_t index));
+  MaybeLocal<Value> Get(Local<Context> context, uint32_t index);
 
   /**
    * Gets the property attributes of a property which can be None or
    * any combination of ReadOnly, DontEnum and DontDelete. Returns
    * None when the property doesn't exist.
    */
-  PropertyAttribute GetPropertyAttributes(Handle<Value> key);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    PropertyAttribute GetPropertyAttributes(Handle<Value> key));
+  Maybe<PropertyAttribute> GetPropertyAttributes(Local<Context> context,
+                                                 Local<Value> key);
 
   /**
    * Returns Object.getOwnPropertyDescriptor as per ES5 section 15.2.3.3.
    */
-  Local<Value> GetOwnPropertyDescriptor(Local<String> key);
-
-  bool Has(Handle<Value> key);
-
-  bool Delete(Handle<Value> key);
-
-  bool Has(uint32_t index);
-
-  bool Delete(uint32_t index);
-
-  bool SetAccessor(Handle<String> name,
-                   AccessorGetterCallback getter,
-                   AccessorSetterCallback setter = 0,
-                   Handle<Value> data = Handle<Value>(),
-                   AccessControl settings = DEFAULT,
-                   PropertyAttribute attribute = None);
-  bool SetAccessor(Handle<Name> name,
-                   AccessorNameGetterCallback getter,
-                   AccessorNameSetterCallback setter = 0,
-                   Handle<Value> data = Handle<Value>(),
-                   AccessControl settings = DEFAULT,
-                   PropertyAttribute attribute = None);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Value> GetOwnPropertyDescriptor(Local<String> key));
+  MaybeLocal<Value> GetOwnPropertyDescriptor(Local<Context> context,
+                                             Local<String> key);
+
+  V8_DEPRECATE_SOON("Use maybe version", bool Has(Handle<Value> key));
+  Maybe<bool> Has(Local<Context> context, Local<Value> key);
+
+  V8_DEPRECATE_SOON("Use maybe version", bool Delete(Handle<Value> key));
+  Maybe<bool> Delete(Local<Context> context, Local<Value> key);
+
+  V8_DEPRECATE_SOON("Use maybe version", bool Has(uint32_t index));
+  Maybe<bool> Has(Local<Context> context, uint32_t index);
+
+  V8_DEPRECATE_SOON("Use maybe version", bool Delete(uint32_t index));
+  Maybe<bool> Delete(Local<Context> context, uint32_t index);
+
+  V8_DEPRECATE_SOON("Use maybe version",
+                    bool SetAccessor(Handle<String> name,
+                                     AccessorGetterCallback getter,
+                                     AccessorSetterCallback setter = 0,
+                                     Handle<Value> data = Handle<Value>(),
+                                     AccessControl settings = DEFAULT,
+                                     PropertyAttribute attribute = None));
+  V8_DEPRECATE_SOON("Use maybe version",
+                    bool SetAccessor(Handle<Name> name,
+                                     AccessorNameGetterCallback getter,
+                                     AccessorNameSetterCallback setter = 0,
+                                     Handle<Value> data = Handle<Value>(),
+                                     AccessControl settings = DEFAULT,
+                                     PropertyAttribute attribute = None));
+  Maybe<bool> SetAccessor(Local<Context> context, Local<Name> name,
+                          AccessorNameGetterCallback getter,
+                          AccessorNameSetterCallback setter = 0,
+                          MaybeLocal<Value> data = MaybeLocal<Value>(),
+                          AccessControl settings = DEFAULT,
+                          PropertyAttribute attribute = None);
 
   void SetAccessorProperty(Local<Name> name,
                            Local<Function> getter,
@@ -2536,6 +2741,7 @@ class V8_EXPORT Object : public Value {
    * Note: Private properties are inherited. Do not rely on this, since it may
    * change.
    */
+  // TODO(dcarney): convert these or remove?
   bool HasPrivate(Handle<Private> key);
   bool SetPrivate(Handle<Private> key, Handle<Value> value);
   bool DeletePrivate(Handle<Private> key);
@@ -2547,14 +2753,16 @@ class V8_EXPORT Object : public Value {
    * array returned by this method contains the same values as would
    * be enumerated by a for-in statement over this object.
    */
-  Local<Array> GetPropertyNames();
+  V8_DEPRECATE_SOON("Use maybe version", Local<Array> GetPropertyNames());
+  MaybeLocal<Array> GetPropertyNames(Local<Context> context);
 
   /**
    * This function has the same functionality as GetPropertyNames but
    * the returned array doesn't contain the names of properties from
    * prototype objects.
    */
-  Local<Array> GetOwnPropertyNames();
+  V8_DEPRECATE_SOON("Use maybe version", Local<Array> GetOwnPropertyNames());
+  MaybeLocal<Array> GetOwnPropertyNames(Local<Context> context);
 
   /**
    * Get the prototype object.  This does not skip objects marked to
@@ -2568,7 +2776,9 @@ class V8_EXPORT Object : public Value {
    * be skipped by __proto__ and it does not consult the security
    * handler.
    */
-  bool SetPrototype(Handle<Value> prototype);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    bool SetPrototype(Handle<Value> prototype));
+  Maybe<bool> SetPrototype(Local<Context> context, Local<Value> prototype);
 
   /**
    * Finds an instance of the given function template in the prototype
@@ -2581,7 +2791,8 @@ class V8_EXPORT Object : public Value {
    * This is different from Value::ToString() that may call
    * user-defined toString function. This one does not.
    */
-  Local<String> ObjectProtoToString();
+  V8_DEPRECATE_SOON("Use maybe version", Local<String> ObjectProtoToString());
+  MaybeLocal<String> ObjectProtoToString(Local<Context> context);
 
   /**
    * Returns the name of the function invoked as a constructor for this object.
@@ -2624,23 +2835,62 @@ class V8_EXPORT Object : public Value {
   void SetAlignedPointerInInternalField(int index, void* value);
 
   // Testers for local properties.
-  bool HasOwnProperty(Handle<String> key);
-  bool HasRealNamedProperty(Handle<String> key);
-  bool HasRealIndexedProperty(uint32_t index);
-  bool HasRealNamedCallbackProperty(Handle<String> key);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    bool HasOwnProperty(Handle<String> key));
+  Maybe<bool> HasOwnProperty(Local<Context> context, Local<Name> key);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    bool HasRealNamedProperty(Handle<String> key));
+  Maybe<bool> HasRealNamedProperty(Local<Context> context, Local<Name> key);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    bool HasRealIndexedProperty(uint32_t index));
+  Maybe<bool> HasRealIndexedProperty(Local<Context> context, uint32_t index);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    bool HasRealNamedCallbackProperty(Handle<String> key));
+  Maybe<bool> HasRealNamedCallbackProperty(Local<Context> context,
+                                           Local<Name> key);
 
   /**
    * If result.IsEmpty() no real property was located in the prototype chain.
    * This means interceptors in the prototype chain are not called.
    */
-  Local<Value> GetRealNamedPropertyInPrototypeChain(Handle<String> key);
+  V8_DEPRECATE_SOON(
+      "Use maybe version",
+      Local<Value> GetRealNamedPropertyInPrototypeChain(Handle<String> key));
+  MaybeLocal<Value> GetRealNamedPropertyInPrototypeChain(Local<Context> context,
+                                                         Local<Name> key);
+
+  /**
+   * Gets the property attributes of a real property in the prototype chain,
+   * which can be None or any combination of ReadOnly, DontEnum and DontDelete.
+   * Interceptors in the prototype chain are not called.
+   */
+  V8_DEPRECATE_SOON(
+      "Use maybe version",
+      Maybe<PropertyAttribute> GetRealNamedPropertyAttributesInPrototypeChain(
+          Handle<String> key));
+  Maybe<PropertyAttribute> GetRealNamedPropertyAttributesInPrototypeChain(
+      Local<Context> context, Local<Name> key);
 
   /**
    * If result.IsEmpty() no real property was located on the object or
    * in the prototype chain.
    * This means interceptors in the prototype chain are not called.
    */
-  Local<Value> GetRealNamedProperty(Handle<String> key);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Value> GetRealNamedProperty(Handle<String> key));
+  MaybeLocal<Value> GetRealNamedProperty(Local<Context> context,
+                                         Local<Name> key);
+
+  /**
+   * Gets the property attributes of a real property which can be
+   * None or any combination of ReadOnly, DontEnum and DontDelete.
+   * Interceptors in the prototype chain are not called.
+   */
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Maybe<PropertyAttribute> GetRealNamedPropertyAttributes(
+                        Handle<String> key));
+  Maybe<PropertyAttribute> GetRealNamedPropertyAttributes(
+      Local<Context> context, Local<Name> key);
 
   /** Tests for a named lookup interceptor.*/
   bool HasNamedLookupInterceptor();
@@ -2653,7 +2903,7 @@ class V8_EXPORT Object : public Value {
    * a template that has access check callbacks. If an object has no
    * access check info, the object cannot be accessed by anyone.
    */
-  void TurnOnAccessCheck();
+  V8_DEPRECATE_SOON("No alternative", void TurnOnAccessCheck());
 
   /**
    * Returns the identity hash for this object. The current implementation
@@ -2670,6 +2920,7 @@ class V8_EXPORT Object : public Value {
    * C++ API. Hidden properties introduced by V8 internally (for example the
    * identity hash) are prefixed with "v8::".
    */
+  // TODO(dcarney): convert these to take a isolate and optionally bailout?
   bool SetHiddenValue(Handle<String> key, Handle<Value> value);
   Local<Value> GetHiddenValue(Handle<String> key);
   bool DeleteHiddenValue(Handle<String> key);
@@ -2678,6 +2929,7 @@ class V8_EXPORT Object : public Value {
    * Clone this object with a fast but shallow copy.  Values will point
    * to the same values as the original object.
    */
+  // TODO(dcarney): take an isolate and optionally bail out?
   Local<Object> Clone();
 
   /**
@@ -2723,21 +2975,27 @@ class V8_EXPORT Object : public Value {
    * Call an Object as a function if a callback is set by the
    * ObjectTemplate::SetCallAsFunctionHandler method.
    */
-  Local<Value> CallAsFunction(Handle<Value> recv,
-                              int argc,
-                              Handle<Value> argv[]);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Value> CallAsFunction(Handle<Value> recv, int argc,
+                                                Handle<Value> argv[]));
+  MaybeLocal<Value> CallAsFunction(Local<Context> context, Handle<Value> recv,
+                                   int argc, Handle<Value> argv[]);
 
   /**
    * Call an Object as a constructor if a callback is set by the
    * ObjectTemplate::SetCallAsFunctionHandler method.
    * Note: This method behaves like the Function::NewInstance method.
    */
-  Local<Value> CallAsConstructor(int argc, Handle<Value> argv[]);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Value> CallAsConstructor(int argc,
+                                                   Handle<Value> argv[]));
+  MaybeLocal<Value> CallAsConstructor(Local<Context> context, int argc,
+                                      Local<Value> argv[]);
 
   /**
    * Return the isolate to which the Object belongs to.
    */
-  Isolate* GetIsolate();
+  V8_DEPRECATE_SOON("Keep track of isolate correctly", Isolate* GetIsolate());
 
   static Local<Object> New(Isolate* isolate);
 
@@ -2762,7 +3020,9 @@ class V8_EXPORT Array : public Object {
    * Clones an element at index |index|.  Returns an empty
    * handle if cloning fails (for any reason).
    */
-  Local<Object> CloneElementAt(uint32_t index);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Object> CloneElementAt(uint32_t index));
+  MaybeLocal<Object> CloneElementAt(Local<Context> context, uint32_t index);
 
   /**
    * Creates a JavaScript array with the given length. If the length
@@ -2907,9 +3167,23 @@ class V8_EXPORT Function : public Object {
                              Local<Value> data = Local<Value>(),
                              int length = 0);
 
-  Local<Object> NewInstance() const;
-  Local<Object> NewInstance(int argc, Handle<Value> argv[]) const;
-  Local<Value> Call(Handle<Value> recv, int argc, Handle<Value> argv[]);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Object> NewInstance(int argc,
+                                              Handle<Value> argv[])) const;
+  MaybeLocal<Object> NewInstance(Local<Context> context, int argc,
+                                 Handle<Value> argv[]) const;
+
+  V8_DEPRECATE_SOON("Use maybe version", Local<Object> NewInstance()) const;
+  MaybeLocal<Object> NewInstance(Local<Context> context) const {
+    return NewInstance(context, 0, nullptr);
+  }
+
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Value> Call(Handle<Value> recv, int argc,
+                                      Handle<Value> argv[]));
+  MaybeLocal<Value> Call(Local<Context> context, Handle<Value> recv, int argc,
+                         Handle<Value> argv[]);
+
   void SetName(Handle<String> name);
   Handle<Value> GetName() const;
 
@@ -2975,7 +3249,9 @@ class V8_EXPORT Promise : public Object {
     /**
      * Create a new resolver, along with an associated promise in pending state.
      */
-    static Local<Resolver> New(Isolate* isolate);
+    static V8_DEPRECATE_SOON("Use maybe version",
+                             Local<Resolver> New(Isolate* isolate));
+    static MaybeLocal<Resolver> New(Local<Context> context);
 
     /**
      * Extract the associated promise.
@@ -2986,8 +3262,11 @@ class V8_EXPORT Promise : public Object {
      * Resolve/reject the associated promise with a given value.
      * Ignored if the promise is no longer pending.
      */
-    void Resolve(Handle<Value> value);
-    void Reject(Handle<Value> value);
+    V8_DEPRECATE_SOON("Use maybe version", void Resolve(Handle<Value> value));
+    Maybe<bool> Resolve(Local<Context> context, Handle<Value> value);
+
+    V8_DEPRECATE_SOON("Use maybe version", void Reject(Handle<Value> value));
+    Maybe<bool> Reject(Local<Context> context, Handle<Value> value);
 
     V8_INLINE static Resolver* Cast(Value* obj);
 
@@ -3002,9 +3281,17 @@ class V8_EXPORT Promise : public Object {
    * an argument. If the promise is already resolved/rejected, the handler is
    * invoked at the end of turn.
    */
-  Local<Promise> Chain(Handle<Function> handler);
-  Local<Promise> Catch(Handle<Function> handler);
-  Local<Promise> Then(Handle<Function> handler);
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Promise> Chain(Handle<Function> handler));
+  MaybeLocal<Promise> Chain(Local<Context> context, Handle<Function> handler);
+
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Promise> Catch(Handle<Function> handler));
+  MaybeLocal<Promise> Catch(Local<Context> context, Handle<Function> handler);
+
+  V8_DEPRECATE_SOON("Use maybe version",
+                    Local<Promise> Then(Handle<Function> handler));
+  MaybeLocal<Promise> Then(Local<Context> context, Handle<Function> handler);
 
   /**
    * Returns true if the promise has at least one derived promise, and
@@ -3025,6 +3312,10 @@ class V8_EXPORT Promise : public Object {
 #define V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT 2
 #endif
 
+
+enum class ArrayBufferCreationMode { kInternalized, kExternalized };
+
+
 /**
  * An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5).
  * This API is experimental and may change significantly.
@@ -3100,12 +3391,13 @@ class V8_EXPORT ArrayBuffer : public Object {
 
   /**
    * Create a new ArrayBuffer over an existing memory block.
-   * The created array buffer is immediately in externalized state.
+   * The created array buffer is by default immediately in externalized state.
    * The memory block will not be reclaimed when a created ArrayBuffer
    * is garbage-collected.
    */
-  static Local<ArrayBuffer> New(Isolate* isolate, void* data,
-                                size_t byte_length);
+  static Local<ArrayBuffer> New(
+      Isolate* isolate, void* data, size_t byte_length,
+      ArrayBufferCreationMode mode = ArrayBufferCreationMode::kExternalized);
 
   /**
    * Returns true if ArrayBuffer is extrenalized, that is, does not
@@ -3137,6 +3429,18 @@ class V8_EXPORT ArrayBuffer : public Object {
    */
   Contents Externalize();
 
+  /**
+   * Get a pointer to the ArrayBuffer's underlying memory block without
+   * externalizing it. If the ArrayBuffer is not externalized, this pointer
+   * will become invalid as soon as the ArrayBuffer became garbage collected.
+   *
+   * The embedder should make sure to hold a strong reference to the
+   * ArrayBuffer while accessing this pointer.
+   *
+   * The memory block is guaranteed to be allocated with |Allocator::Allocate|.
+   */
+  Contents GetContents();
+
   V8_INLINE static ArrayBuffer* Cast(Value* obj);
 
   static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT;
@@ -3174,6 +3478,23 @@ class V8_EXPORT ArrayBufferView : public Object {
    */
   size_t ByteLength();
 
+  /**
+   * Copy the contents of the ArrayBufferView's buffer to an embedder defined
+   * memory without additional overhead that calling ArrayBufferView::Buffer
+   * might incur.
+   *
+   * Will write at most min(|byte_length|, ByteLength) bytes starting at
+   * ByteOffset of the underling buffer to the memory starting at |dest|.
+   * Returns the number of bytes actually written.
+   */
+  size_t CopyContents(void* dest, size_t byte_length);
+
+  /**
+   * Returns true if ArrayBufferView's backing ArrayBuffer has already been
+   * allocated.
+   */
+  bool HasBuffer() const;
+
   V8_INLINE static ArrayBufferView* Cast(Value* obj);
 
   static const int kInternalFieldCount =
@@ -3370,7 +3691,9 @@ class V8_EXPORT DataView : public ArrayBufferView {
  */
 class V8_EXPORT Date : public Object {
  public:
-  static Local<Value> New(Isolate* isolate, double time);
+  static V8_DEPRECATE_SOON("Use maybe version.",
+                           Local<Value> New(Isolate* isolate, double time));
+  static MaybeLocal<Value> New(Local<Context> context, double time);
 
   /**
    * A specialization of Value::NumberValue that is more efficient
@@ -3491,7 +3814,11 @@ class V8_EXPORT RegExp : public Object {
    *               static_cast<RegExp::Flags>(kGlobal | kMultiline))
    * is equivalent to evaluating "/foo/gm".
    */
-  static Local<RegExp> New(Handle<String> pattern, Flags flags);
+  static V8_DEPRECATE_SOON("Use maybe version",
+                           Local<RegExp> New(Handle<String> pattern,
+                                             Flags flags));
+  static MaybeLocal<RegExp> New(Local<Context> context, Handle<String> pattern,
+                                Flags flags);
 
   /**
    * Returns the value of the source property: a string representing
@@ -3875,7 +4202,8 @@ class V8_EXPORT FunctionTemplate : public Template {
       int length = 0);
 
   /** Returns the unique function instance in the current execution context.*/
-  Local<Function> GetFunction();
+  V8_DEPRECATE_SOON("Use maybe version", Local<Function> GetFunction());
+  MaybeLocal<Function> GetFunction(Local<Context> context);
 
   /**
    * Set the call-handler callback for a FunctionTemplate.  This
@@ -3907,6 +4235,13 @@ class V8_EXPORT FunctionTemplate : public Template {
    */
   void SetClassName(Handle<String> name);
 
+
+  /**
+   * When set to true, no access check will be performed on the receiver of a
+   * function call.  Currently defaults to true, but this is subject to change.
+   */
+  void SetAcceptAnyReceiver(bool value);
+
   /**
    * Determines whether the __proto__ accessor ignores instances of
    * the function template.  If instances of the function template are
@@ -3946,7 +4281,17 @@ class V8_EXPORT FunctionTemplate : public Template {
 };
 
 
-enum class PropertyHandlerFlags { kNone = 0, kAllCanRead = 1 };
+enum class PropertyHandlerFlags {
+  kNone = 0,
+  // See ALL_CAN_READ above.
+  kAllCanRead = 1,
+  // Will not call into interceptor for properties on the receiver or prototype
+  // chain.  Currently only valid for named interceptors.
+  kNonMasking = 1 << 1,
+  // Will not call into interceptor for symbol lookup.  Only meaningful for
+  // named interceptors.
+  kOnlyInterceptStrings = 1 << 2,
+};
 
 
 struct NamedPropertyHandlerConfiguration {
@@ -4015,11 +4360,11 @@ class V8_EXPORT ObjectTemplate : public Template {
  public:
   /** Creates an ObjectTemplate. */
   static Local<ObjectTemplate> New(Isolate* isolate);
-  // Will be deprecated soon.
-  static Local<ObjectTemplate> New();
+  static V8_DEPRECATE_SOON("Use isolate version", Local<ObjectTemplate> New());
 
   /** Creates a new instance of this template.*/
-  Local<Object> NewInstance();
+  V8_DEPRECATE_SOON("Use maybe version", Local<Object> NewInstance());
+  MaybeLocal<Object> NewInstance(Local<Context> context);
 
   /**
    * Sets an accessor on the object template.
@@ -4406,8 +4751,7 @@ enum ObjectSpace {
   kObjectSpaceCodeSpace = 1 << 3,
   kObjectSpaceMapSpace = 1 << 4,
   kObjectSpaceCellSpace = 1 << 5,
-  kObjectSpacePropertyCellSpace = 1 << 6,
-  kObjectSpaceLoSpace = 1 << 7,
+  kObjectSpaceLoSpace = 1 << 6,
   kObjectSpaceAll = kObjectSpaceNewSpace | kObjectSpaceOldPointerSpace |
                     kObjectSpaceOldDataSpace | kObjectSpaceCodeSpace |
                     kObjectSpaceMapSpace | kObjectSpaceLoSpace
@@ -4665,7 +5009,10 @@ class V8_EXPORT Isolate {
     CreateParams()
         : entry_hook(NULL),
           code_event_handler(NULL),
-          enable_serializer(false) {}
+          snapshot_blob(NULL),
+          counter_lookup_callback(NULL),
+          create_histogram_callback(NULL),
+          add_histogram_sample_callback(NULL) {}
 
     /**
      * The optional entry_hook allows the host application to provide the
@@ -4688,9 +5035,25 @@ class V8_EXPORT Isolate {
     ResourceConstraints constraints;
 
     /**
-     * This flag currently renders the Isolate unusable.
+     * Explicitly specify a startup snapshot blob. The embedder owns the blob.
+     */
+    StartupData* snapshot_blob;
+
+
+    /**
+     * Enables the host application to provide a mechanism for recording
+     * statistics counters.
      */
-    bool enable_serializer;
+    CounterLookupCallback counter_lookup_callback;
+
+    /**
+     * Enables the host application to provide a mechanism for recording
+     * histograms. The CreateHistogram function returns a
+     * histogram which will later be passed to the AddHistogramSample
+     * function.
+     */
+    CreateHistogramCallback create_histogram_callback;
+    AddHistogramSampleCallback add_histogram_sample_callback;
   };
 
 
@@ -4789,6 +5152,7 @@ class V8_EXPORT Isolate {
   enum UseCounterFeature {
     kUseAsm = 0,
     kBreakIterator = 1,
+    kLegacyConst = 2,
     kUseCounterFeatureCount  // This enum value must be last.
   };
 
@@ -5056,13 +5420,6 @@ class V8_EXPORT Isolate {
   void RequestInterrupt(InterruptCallback callback, void* data);
 
   /**
-   * Clear interrupt request created by |RequestInterrupt|.
-   * Can be called from another thread without acquiring a |Locker|.
-   */
-  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
    * function if --expose_gc was specified.
    *
@@ -5157,7 +5514,9 @@ class V8_EXPORT Isolate {
    *
    * 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.
+   * done within the time limit. This variant is deprecated and will be removed
+   * in the future.
+   *
    * 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
@@ -5367,16 +5726,17 @@ typedef uintptr_t (*ReturnAddressLocationResolver)(
 class V8_EXPORT V8 {
  public:
   /** Set the callback to invoke in case of fatal errors. */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static void SetFatalErrorHandler(FatalErrorCallback that);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version",
+      void SetFatalErrorHandler(FatalErrorCallback that));
 
   /**
    * Set the callback to invoke to check if code generation from
    * strings should be allowed.
    */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static void SetAllowCodeGenerationFromStringsCallback(
-      AllowCodeGenerationFromStringsCallback that);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version", void SetAllowCodeGenerationFromStringsCallback(
+                                 AllowCodeGenerationFromStringsCallback that));
 
   /**
    * Set allocator to use for ArrayBuffer memory.
@@ -5390,8 +5750,7 @@ class V8_EXPORT V8 {
   * 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();
+  V8_INLINE static V8_DEPRECATE_SOON("no alternative", bool IsDead());
 
   /**
    * Hand startup data to V8, in case the embedder has chosen to build
@@ -5416,7 +5775,7 @@ class V8_EXPORT V8 {
    * Returns { NULL, 0 } on failure.
    * The caller owns the data array in the return value.
    */
-  static StartupData CreateSnapshotDataBlob(char* custom_source = NULL);
+  static StartupData CreateSnapshotDataBlob(const char* custom_source = NULL);
 
   /**
    * Adds a message listener.
@@ -5427,24 +5786,26 @@ class V8_EXPORT V8 {
    * 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.
    */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static bool AddMessageListener(
-      MessageCallback that, Handle<Value> data = Handle<Value>());
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version",
+      bool AddMessageListener(MessageCallback that,
+                              Handle<Value> data = Handle<Value>()));
 
   /**
    * Remove all message listeners from the specified callback function.
    */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static void RemoveMessageListeners(MessageCallback that);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version", 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.
    */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static void SetCaptureStackTraceForUncaughtExceptions(
-      bool capture, int frame_limit = 10,
-      StackTrace::StackTraceOptions options = StackTrace::kOverview);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version",
+      void SetCaptureStackTraceForUncaughtExceptions(
+          bool capture, int frame_limit = 10,
+          StackTrace::StackTraceOptions options = StackTrace::kOverview));
 
   /**
    * Sets V8 flags from a string.
@@ -5462,9 +5823,9 @@ class V8_EXPORT V8 {
   static const char* GetVersion();
 
   /** Callback function for reporting failed access checks.*/
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static void SetFailedAccessCheckCallbackFunction(
-      FailedAccessCheckCallback);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version",
+      void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback));
 
   /**
    * Enables the host application to receive a notification before a
@@ -5476,16 +5837,18 @@ class V8_EXPORT V8 {
    * 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);
+  static V8_DEPRECATE_SOON(
+      "Use isolate version",
+      void AddGCPrologueCallback(GCPrologueCallback callback,
+                                 GCType gc_type_filter = kGCTypeAll));
 
   /**
    * This function removes callback which was installed by
    * AddGCPrologueCallback function.
    */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static void RemoveGCPrologueCallback(GCPrologueCallback callback);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version",
+      void RemoveGCPrologueCallback(GCPrologueCallback callback));
 
   /**
    * Enables the host application to receive a notification after a
@@ -5497,32 +5860,35 @@ class V8_EXPORT V8 {
    * 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);
+  static V8_DEPRECATE_SOON(
+      "Use isolate version",
+      void AddGCEpilogueCallback(GCEpilogueCallback callback,
+                                 GCType gc_type_filter = kGCTypeAll));
 
   /**
    * This function removes callback which was installed by
    * AddGCEpilogueCallback function.
    */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static void RemoveGCEpilogueCallback(GCEpilogueCallback callback);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version",
+      void RemoveGCEpilogueCallback(GCEpilogueCallback callback));
 
   /**
    * Enables the host application to provide a mechanism to be notified
    * and perform custom logging when V8 Allocates Executable Memory.
    */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static void AddMemoryAllocationCallback(
-      MemoryAllocationCallback callback, ObjectSpace space,
-      AllocationAction action);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version",
+      void AddMemoryAllocationCallback(MemoryAllocationCallback callback,
+                                       ObjectSpace space,
+                                       AllocationAction action));
 
   /**
    * Removes callback that was installed by AddMemoryAllocationCallback.
    */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static void RemoveMemoryAllocationCallback(
-      MemoryAllocationCallback callback);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version",
+      void RemoveMemoryAllocationCallback(MemoryAllocationCallback callback));
 
   /**
    * Initializes V8. This function needs to be called before the first Isolate
@@ -5552,8 +5918,8 @@ class V8_EXPORT V8 {
    *
    * \param isolate The isolate in which to terminate the current JS execution.
    */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static void TerminateExecution(Isolate* isolate);
+  V8_INLINE static V8_DEPRECATE_SOON("Use isolate version",
+                                     void TerminateExecution(Isolate* isolate));
 
   /**
    * Is V8 terminating JavaScript execution.
@@ -5565,8 +5931,9 @@ class V8_EXPORT V8 {
    *
    * \param isolate The isolate in which to check.
    */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static bool IsExecutionTerminating(Isolate* isolate = NULL);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version",
+      bool IsExecutionTerminating(Isolate* isolate = NULL));
 
   /**
    * Resume execution capability in the given isolate, whose execution
@@ -5584,8 +5951,8 @@ class V8_EXPORT V8 {
    *
    * \param isolate The isolate in which to resume execution capability.
    */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static void CancelTerminateExecution(Isolate* isolate);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version", void CancelTerminateExecution(Isolate* isolate));
 
   /**
    * Releases any resources used by v8 and stops any utility threads
@@ -5603,25 +5970,26 @@ class V8_EXPORT V8 {
    * heap.  GC is not invoked prior to iterating, therefore there is no
    * guarantee that visited objects are still alive.
    */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static void VisitExternalResources(
-      ExternalResourceVisitor* visitor);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isoalte version",
+      void VisitExternalResources(ExternalResourceVisitor* visitor));
 
   /**
    * Iterates through all the persistent handles in the current isolate's heap
    * that have class_ids.
    */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static void VisitHandlesWithClassIds(
-      PersistentHandleVisitor* visitor);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version",
+      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);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version",
+      void VisitHandlesWithClassIds(Isolate* isolate,
+                                    PersistentHandleVisitor* visitor));
 
   /**
    * Iterates through all the persistent handles in the current isolate's heap
@@ -5630,9 +5998,10 @@ class V8_EXPORT V8 {
    * garbage collection but is free to visit an arbitrary superset of these
    * objects.
    */
-  // TODO(dcarney): deprecate this.
-  V8_INLINE static void VisitHandlesForPartialDependence(
-      Isolate* isolate, PersistentHandleVisitor* visitor);
+  V8_INLINE static V8_DEPRECATE_SOON(
+      "Use isolate version",
+      void VisitHandlesForPartialDependence(Isolate* isolate,
+                                            PersistentHandleVisitor* visitor));
 
   /**
    * Initialize the ICU library bundled with V8. The embedder should only
@@ -5658,8 +6027,6 @@ class V8_EXPORT V8 {
  private:
   V8();
 
-  enum WeakHandleType { PhantomHandle, NonphantomHandle };
-
   static internal::Object** GlobalizeReference(internal::Isolate* isolate,
                                                internal::Object** handle);
   static internal::Object** CopyPersistent(internal::Object** handle);
@@ -5667,20 +6034,33 @@ class V8_EXPORT V8 {
   typedef WeakCallbackData<Value, void>::Callback WeakCallback;
   static void MakeWeak(internal::Object** global_handle, void* data,
                        WeakCallback weak_callback);
-  static void MakePhantom(internal::Object** global_handle, void* data,
-                          // Must be 0 or kNoInternalFieldIndex.
-                          int internal_field_index1,
-                          // Must be 1 or kNoInternalFieldIndex.
-                          int internal_field_index2,
-                          PhantomCallbackData<void>::Callback weak_callback);
+  static void MakeWeak(internal::Object** global_handle, void* data,
+                       WeakCallbackInfo<void>::Callback weak_callback,
+                       WeakCallbackType type);
+  static void MakeWeak(internal::Object** global_handle, void* data,
+                       // Must be 0 or -1.
+                       int internal_field_index1,
+                       // Must be 1 or -1.
+                       int internal_field_index2,
+                       WeakCallbackInfo<void>::Callback weak_callback);
   static void* ClearWeak(internal::Object** global_handle);
   static void Eternalize(Isolate* isolate,
                          Value* handle,
                          int* index);
   static Local<Value> GetEternal(Isolate* isolate, int index);
 
+  static void CheckIsJust(bool is_just);
+  static void ToLocalEmpty();
+  static void InternalFieldOutOfBounds(int index);
+
   template <class T> friend class Handle;
   template <class T> friend class Local;
+  template <class T>
+  friend class MaybeLocal;
+  template <class T>
+  friend class Maybe;
+  template <class T>
+  friend class WeakCallbackInfo;
   template <class T> friend class Eternal;
   template <class T> friend class PersistentBase;
   template <class T, class M> friend class Persistent;
@@ -5689,6 +6069,69 @@ class V8_EXPORT V8 {
 
 
 /**
+ * A simple Maybe type, representing an object which may or may not have a
+ * value, see https://hackage.haskell.org/package/base/docs/Data-Maybe.html.
+ *
+ * If an API method returns a Maybe<>, the API method can potentially fail
+ * either because an exception is thrown, or because an exception is pending,
+ * e.g. because a previous API call threw an exception that hasn't been caught
+ * yet, or because a TerminateExecution exception was thrown. In that case, a
+ * "Nothing" value is returned.
+ */
+template <class T>
+class Maybe {
+ public:
+  V8_INLINE bool IsNothing() const { return !has_value; }
+  V8_INLINE bool IsJust() const { return has_value; }
+
+  // Will crash when checks are enabled if the Maybe<> is nothing.
+  V8_INLINE T FromJust() const {
+#ifdef V8_ENABLE_CHECKS
+    V8::CheckIsJust(IsJust());
+#endif
+    return value;
+  }
+
+  V8_INLINE T FromMaybe(const T& default_value) const {
+    return has_value ? value : default_value;
+  }
+
+  V8_INLINE bool operator==(const Maybe& other) const {
+    return (IsJust() == other.IsJust()) &&
+           (!IsJust() || FromJust() == other.FromJust());
+  }
+
+  V8_INLINE bool operator!=(const Maybe& other) const {
+    return !operator==(other);
+  }
+
+ private:
+  Maybe() : has_value(false) {}
+  explicit Maybe(const T& t) : has_value(true), value(t) {}
+
+  bool has_value;
+  T value;
+
+  template <class U>
+  friend Maybe<U> Nothing();
+  template <class U>
+  friend Maybe<U> Just(const U& u);
+};
+
+
+template <class T>
+inline Maybe<T> Nothing() {
+  return Maybe<T>();
+}
+
+
+template <class T>
+inline Maybe<T> Just(const T& t) {
+  return Maybe<T>(t);
+}
+
+
+/**
  * An external exception handler.
  */
 class V8_EXPORT TryCatch {
@@ -5698,8 +6141,7 @@ class V8_EXPORT TryCatch {
    * all TryCatch blocks should be stack allocated because the memory
    * location itself is compared against JavaScript try/catch blocks.
    */
-  // TODO(dcarney): deprecate.
-  TryCatch();
+  V8_DEPRECATE_SOON("Use isolate version", TryCatch());
 
   /**
    * Creates a new try/catch block and registers it with v8.  Note that
@@ -5763,7 +6205,8 @@ class V8_EXPORT TryCatch {
    * Returns the .stack property of the thrown object.  If no .stack
    * property is present an empty handle is returned.
    */
-  Local<Value> StackTrace() const;
+  V8_DEPRECATE_SOON("Use maybe version.", Local<Value> StackTrace()) const;
+  MaybeLocal<Value> StackTrace(Local<Context> context) const;
 
   /**
    * Returns the message associated with this exception.  If there is
@@ -5832,10 +6275,7 @@ class V8_EXPORT TryCatch {
   v8::TryCatch* next_;
   void* exception_;
   void* message_obj_;
-  void* message_script_;
   void* js_stack_comparable_address_;
-  int message_start_pos_;
-  int message_end_pos_;
   bool is_verbose_ : 1;
   bool can_continue_ : 1;
   bool capture_message_ : 1;
@@ -5947,6 +6387,13 @@ class V8_EXPORT Context {
   v8::Isolate* GetIsolate();
 
   /**
+   * The field at kDebugIdIndex is reserved for V8 debugger implementation.
+   * The value is propagated to the scripts compiled in given Context and
+   * can be used for filtering scripts.
+   */
+  enum EmbedderDataFields { kDebugIdIndex = 0 };
+
+  /**
    * Gets the embedder data with the given index, which must have been set by a
    * previous call to SetEmbedderData with the same index. Note that index 0
    * currently has a special meaning for Chrome's debugger.
@@ -6255,7 +6702,7 @@ class Internals {
   static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
   static const int kFixedArrayHeaderSize = 2 * kApiPointerSize;
   static const int kContextHeaderSize = 2 * kApiPointerSize;
-  static const int kContextEmbedderDataIndex = 74;
+  static const int kContextEmbedderDataIndex = 76;
   static const int kFullStringRepresentationMask = 0x07;
   static const int kStringEncodingMask = 0x4;
   static const int kExternalTwoByteRepresentationTag = 0x02;
@@ -6273,7 +6720,7 @@ class Internals {
   static const int kNullValueRootIndex = 7;
   static const int kTrueValueRootIndex = 8;
   static const int kFalseValueRootIndex = 9;
-  static const int kEmptyStringRootIndex = 155;
+  static const int kEmptyStringRootIndex = 156;
 
   // The external allocation limit should be below 256 MB on all architectures
   // to avoid that resource-constrained embedders run low on memory.
@@ -6291,7 +6738,7 @@ class Internals {
   static const int kJSObjectType = 0xbd;
   static const int kFirstNonstringType = 0x80;
   static const int kOddballType = 0x83;
-  static const int kForeignType = 0x88;
+  static const int kForeignType = 0x87;
 
   static const int kUndefinedOddballKind = 5;
   static const int kNullOddballKind = 3;
@@ -6457,6 +6904,26 @@ Local<T> Eternal<T>::Get(Isolate* isolate) {
 
 
 template <class T>
+Local<T> MaybeLocal<T>::ToLocalChecked() {
+#ifdef V8_ENABLE_CHECKS
+  if (val_ == nullptr) V8::ToLocalEmpty();
+#endif
+  return Local<T>(val_);
+}
+
+
+template <class T>
+void* WeakCallbackInfo<T>::GetInternalField(int index) const {
+#ifdef V8_ENABLE_CHECKS
+  if (index < 0 || index >= kInternalFieldsInWeakCallback) {
+    V8::InternalFieldOutOfBounds(index);
+  }
+#endif
+  return internal_fields_[index];
+}
+
+
+template <class T>
 T* PersistentBase<T>::New(Isolate* isolate, T* that) {
   if (that == NULL) return NULL;
   internal::Object** p = reinterpret_cast<internal::Object**>(that);
@@ -6560,12 +7027,23 @@ void PersistentBase<T>::SetWeak(
 template <class T>
 template <typename P>
 void PersistentBase<T>::SetPhantom(
-    P* parameter, typename PhantomCallbackData<P>::Callback callback,
+    P* parameter, typename WeakCallbackInfo<P>::Callback callback,
     int internal_field_index1, int internal_field_index2) {
-  typedef typename PhantomCallbackData<void>::Callback Callback;
-  V8::MakePhantom(reinterpret_cast<internal::Object**>(this->val_), parameter,
-                  internal_field_index1, internal_field_index2,
-                  reinterpret_cast<Callback>(callback));
+  typedef typename WeakCallbackInfo<void>::Callback Callback;
+  V8::MakeWeak(reinterpret_cast<internal::Object**>(this->val_), parameter,
+               internal_field_index1, internal_field_index2,
+               reinterpret_cast<Callback>(callback));
+}
+
+
+template <class T>
+template <typename P>
+V8_INLINE void PersistentBase<T>::SetWeak(
+    P* parameter, typename WeakCallbackInfo<P>::Callback callback,
+    WeakCallbackType type) {
+  typedef typename WeakCallbackInfo<void>::Callback Callback;
+  V8::MakeWeak(reinterpret_cast<internal::Object**>(this->val_), parameter,
+               reinterpret_cast<Callback>(callback), type);
 }
 
 
@@ -6823,6 +7301,9 @@ Handle<Integer> ScriptOrigin::ScriptID() const {
 }
 
 
+Handle<Value> ScriptOrigin::SourceMapUrl() const { return source_map_url_; }
+
+
 ScriptCompiler::Source::Source(Local<String> string, const ScriptOrigin& origin,
                                CachedData* data)
     : source_string(string),
@@ -6831,6 +7312,7 @@ ScriptCompiler::Source::Source(Local<String> string, const ScriptOrigin& origin,
       resource_column_offset(origin.ResourceColumnOffset()),
       resource_is_embedder_debug_script(origin.ResourceIsEmbedderDebugScript()),
       resource_is_shared_cross_origin(origin.ResourceIsSharedCrossOrigin()),
+      source_map_url(origin.SourceMapUrl()),
       cached_data(data) {}
 
 
@@ -7046,6 +7528,14 @@ Local<Uint32> Value::ToUint32() const {
 Local<Int32> Value::ToInt32() const { return ToInt32(Isolate::GetCurrent()); }
 
 
+Boolean* Boolean::Cast(v8::Value* value) {
+#ifdef V8_ENABLE_CHECKS
+  CheckCast(value);
+#endif
+  return static_cast<Boolean*>(value);
+}
+
+
 Name* Name::Cast(v8::Value* value) {
 #ifdef V8_ENABLE_CHECKS
   CheckCast(value);
@@ -7078,6 +7568,22 @@ Integer* Integer::Cast(v8::Value* value) {
 }
 
 
+Int32* Int32::Cast(v8::Value* value) {
+#ifdef V8_ENABLE_CHECKS
+  CheckCast(value);
+#endif
+  return static_cast<Int32*>(value);
+}
+
+
+Uint32* Uint32::Cast(v8::Value* value) {
+#ifdef V8_ENABLE_CHECKS
+  CheckCast(value);
+#endif
+  return static_cast<Uint32*>(value);
+}
+
+
 Date* Date::Cast(v8::Value* value) {
 #ifdef V8_ENABLE_CHECKS
   CheckCast(value);
index ca806cb..a0d9b5c 100644 (file)
@@ -42,8 +42,8 @@
     ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >=   \
      ((major) * 10000 + (minor) * 100 + (patchlevel)))
 #elif defined(__GNUC__) && defined(__GNUC_MINOR__)
-# define V8_GNUC_PREREQ(major, minor, patchlevel)       \
-    ((__GNUC__ * 10000 + __GNUC_MINOR__) >=             \
+# define V8_GNUC_PREREQ(major, minor, patchlevel)      \
+    ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >=      \
      ((major) * 10000 + (minor) * 100 + (patchlevel)))
 #else
 # define V8_GNUC_PREREQ(major, minor, patchlevel) 0
@@ -343,6 +343,10 @@ declarator __attribute__((deprecated))
 #endif
 
 
+// a macro to make it easier to see what will be deprecated.
+#define V8_DEPRECATE_SOON(message, declarator) declarator
+
+
 // A macro to provide the compiler with branch prediction information.
 #if V8_HAS_BUILTIN_EXPECT
 # define V8_UNLIKELY(condition) (__builtin_expect(!!(condition), 0))
@@ -425,4 +429,13 @@ namespace v8 { template <typename T> class AlignOfHelper { char c; T t; }; }
 # define V8_ALIGNOF(type) (sizeof(::v8::AlignOfHelper<type>) - sizeof(type))
 #endif
 
+// Annotate a function indicating the caller must examine the return value.
+// Use like:
+//   int foo() WARN_UNUSED_RESULT;
+#if V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT
+#define V8_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#define V8_WARN_UNUSED_RESULT /* NOT SUPPORTED */
+#endif
+
 #endif  // V8CONFIG_H_
index 4dbb3c7..4d32053 100644 (file)
@@ -7,7 +7,7 @@ include_rules = [
 ]
 
 specific_include_rules = {
-  "(mksnapshot|d8)\.cc": [
+  "d8\.cc": [
     "+include/libplatform/libplatform.h",
   ],
 }
index e08f86f..f774c6d 100644 (file)
@@ -242,14 +242,8 @@ void Accessors::ArrayLengthSetter(
     return;
   }
 
-  Handle<Object> exception;
-  maybe = isolate->factory()->NewRangeError("invalid_array_length",
-                                            HandleVector<Object>(NULL, 0));
-  if (!maybe.ToHandle(&exception)) {
-    isolate->OptionalRescheduleException(false);
-    return;
-  }
-
+  Handle<Object> exception = isolate->factory()->NewRangeError(
+      "invalid_array_length", HandleVector<Object>(NULL, 0));
   isolate->ScheduleThrow(*exception);
 }
 
@@ -1101,12 +1095,52 @@ void Accessors::FunctionLengthGetter(
 }
 
 
+MUST_USE_RESULT static MaybeHandle<Object> ReplaceAccessorWithDataProperty(
+    Isolate* isolate, Handle<JSObject> object, Handle<Name> name,
+    Handle<Object> value, bool is_observed, Handle<Object> old_value) {
+  LookupIterator it(object, name);
+  CHECK_EQ(LookupIterator::ACCESSOR, it.state());
+  DCHECK(it.HolderIsReceiverOrHiddenPrototype());
+  it.ReconfigureDataProperty(value, it.property_details().attributes());
+  value = it.WriteDataValue(value);
+
+  if (is_observed && !old_value->SameValue(*value)) {
+    return JSObject::EnqueueChangeRecord(object, "update", name, old_value);
+  }
+
+  return value;
+}
+
+
+MUST_USE_RESULT static MaybeHandle<Object> SetFunctionLength(
+    Isolate* isolate, Handle<JSFunction> function, Handle<Object> value) {
+  Handle<Object> old_value;
+  bool is_observed = function->map()->is_observed();
+  if (is_observed) {
+    old_value = handle(Smi::FromInt(function->shared()->length()), isolate);
+  }
+
+  return ReplaceAccessorWithDataProperty(isolate, function,
+                                         isolate->factory()->length_string(),
+                                         value, is_observed, old_value);
+}
+
+
 void Accessors::FunctionLengthSetter(
     v8::Local<v8::Name> name,
     v8::Local<v8::Value> val,
     const v8::PropertyCallbackInfo<void>& info) {
-  // Function length is non writable, non configurable.
-  UNREACHABLE();
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
+  HandleScope scope(isolate);
+  Handle<Object> value = Utils::OpenHandle(*val);
+
+  if (SetPropertyOnInstanceIfInherited(isolate, info, name, value)) return;
+
+  Handle<JSFunction> object =
+      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
+  if (SetFunctionLength(isolate, object, value).is_null()) {
+    isolate->OptionalRescheduleException(false);
+  }
 }
 
 
@@ -1137,12 +1171,35 @@ void Accessors::FunctionNameGetter(
 }
 
 
+MUST_USE_RESULT static MaybeHandle<Object> SetFunctionName(
+    Isolate* isolate, Handle<JSFunction> function, Handle<Object> value) {
+  Handle<Object> old_value;
+  bool is_observed = function->map()->is_observed();
+  if (is_observed) {
+    old_value = handle(function->shared()->name(), isolate);
+  }
+
+  return ReplaceAccessorWithDataProperty(isolate, function,
+                                         isolate->factory()->name_string(),
+                                         value, is_observed, old_value);
+}
+
+
 void Accessors::FunctionNameSetter(
     v8::Local<v8::Name> name,
     v8::Local<v8::Value> val,
     const v8::PropertyCallbackInfo<void>& info) {
-  // Function name is non writable, non configurable.
-  UNREACHABLE();
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
+  HandleScope scope(isolate);
+  Handle<Object> value = Utils::OpenHandle(*val);
+
+  if (SetPropertyOnInstanceIfInherited(isolate, info, name, value)) return;
+
+  Handle<JSFunction> object =
+      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
+  if (SetFunctionName(isolate, object, value).is_null()) {
+    isolate->OptionalRescheduleException(false);
+  }
 }
 
 
@@ -1459,14 +1516,8 @@ static void ModuleGetExport(
   if (value->IsTheHole()) {
     Handle<String> name = v8::Utils::OpenHandle(*property);
 
-    Handle<Object> exception;
-    MaybeHandle<Object> maybe = isolate->factory()->NewReferenceError(
+    Handle<Object> exception = isolate->factory()->NewReferenceError(
         "not_defined", HandleVector(&name, 1));
-    if (!maybe.ToHandle(&exception)) {
-      isolate->OptionalRescheduleException(false);
-      return;
-    }
-
     isolate->ScheduleThrow(*exception);
     return;
   }
@@ -1486,14 +1537,8 @@ static void ModuleSetExport(
   Isolate* isolate = context->GetIsolate();
   if (old_value->IsTheHole()) {
     Handle<String> name = v8::Utils::OpenHandle(*property);
-    Handle<Object> exception;
-    MaybeHandle<Object> maybe = isolate->factory()->NewReferenceError(
+    Handle<Object> exception = isolate->factory()->NewReferenceError(
         "not_defined", HandleVector(&name, 1));
-    if (!maybe.ToHandle(&exception)) {
-      isolate->OptionalRescheduleException(false);
-      return;
-    }
-
     isolate->ScheduleThrow(*exception);
     return;
   }
index 11f20ef..e792453 100644 (file)
@@ -81,14 +81,14 @@ MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
     LookupIterator it(object, Handle<Name>::cast(key),
                       LookupIterator::OWN_SKIP_INTERCEPTOR);
     Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
-    DCHECK(maybe.has_value);
+    DCHECK(maybe.IsJust());
     duplicate = it.IsFound();
   } else {
     uint32_t index = 0;
     key->ToArrayIndex(&index);
     Maybe<bool> maybe = JSReceiver::HasOwnElement(object, index);
-    if (!maybe.has_value) return MaybeHandle<Object>();
-    duplicate = maybe.value;
+    if (!maybe.IsJust()) return MaybeHandle<Object>();
+    duplicate = maybe.FromJust();
   }
   if (duplicate) {
     Handle<Object> args[1] = {key};
index 4d07f82..049c35a 100644 (file)
@@ -22,6 +22,7 @@
 #include "src/bootstrapper.h"
 #include "src/code-stubs.h"
 #include "src/compiler.h"
+#include "src/contexts.h"
 #include "src/conversions-inl.h"
 #include "src/counters.h"
 #include "src/cpu-profiler.h"
@@ -34,8 +35,8 @@
 #include "src/icu_util.h"
 #include "src/json-parser.h"
 #include "src/messages.h"
-#include "src/natives.h"
 #include "src/parser.h"
+#include "src/pending-compilation-error-handler.h"
 #include "src/profile-generator-inl.h"
 #include "src/property.h"
 #include "src/property-details.h"
 #include "src/sampler.h"
 #include "src/scanner-character-streams.h"
 #include "src/simulator.h"
-#include "src/snapshot.h"
+#include "src/snapshot/natives.h"
+#include "src/snapshot/snapshot.h"
 #include "src/unicode-inl.h"
 #include "src/v8threads.h"
 #include "src/version.h"
 #include "src/vm-state-inl.h"
 
 
-#define LOG_API(isolate, expr) LOG(isolate, ApiEntryCall(expr))
+namespace v8 {
 
-#define ENTER_V8(isolate)             \
-  i::VMState<v8::OTHER> __state__((isolate))
+#define LOG_API(isolate, expr) LOG(isolate, ApiEntryCall(expr))
 
-namespace v8 {
 
-#define ON_BAILOUT(isolate, location, code)                        \
-  if (IsExecutionTerminatingCheck(isolate)) {                      \
-    code;                                                          \
-    UNREACHABLE();                                                 \
-  }
+#define ENTER_V8(isolate) i::VMState<v8::OTHER> __state__((isolate))
 
 
-#define EXCEPTION_PREAMBLE(isolate)                                         \
-  (isolate)->handle_scope_implementer()->IncrementCallDepth();              \
-  DCHECK(!(isolate)->external_caught_exception());                          \
+#define PREPARE_FOR_EXECUTION_GENERIC(isolate, context, function_name, \
+                                      bailout_value, HandleScopeClass, \
+                                      do_callback)                     \
+  if (IsExecutionTerminatingCheck(isolate)) {                          \
+    return bailout_value;                                              \
+  }                                                                    \
+  HandleScopeClass handle_scope(isolate);                              \
+  CallDepthScope call_depth_scope(isolate, context, do_callback);      \
+  LOG_API(isolate, function_name);                                     \
+  ENTER_V8(isolate);                                                   \
   bool has_pending_exception = false
 
 
-#define EXCEPTION_BAILOUT_CHECK_GENERIC(isolate, value, do_callback)           \
-  do {                                                                         \
-    i::HandleScopeImplementer* handle_scope_implementer =                      \
-        (isolate)->handle_scope_implementer();                                 \
-    handle_scope_implementer->DecrementCallDepth();                            \
-    if (has_pending_exception) {                                               \
-      bool call_depth_is_zero = handle_scope_implementer->CallDepthIsZero();   \
-      (isolate)->OptionalRescheduleException(call_depth_is_zero);              \
-      do_callback                                                              \
-      return value;                                                            \
-    }                                                                          \
-    do_callback                                                                \
+#define PREPARE_FOR_EXECUTION_WITH_CONTEXT(                                  \
+    context, function_name, bailout_value, HandleScopeClass, do_callback)    \
+  auto isolate = context.IsEmpty()                                           \
+                     ? i::Isolate::Current()                                 \
+                     : reinterpret_cast<i::Isolate*>(context->GetIsolate()); \
+  PREPARE_FOR_EXECUTION_GENERIC(isolate, context, function_name,             \
+                                bailout_value, HandleScopeClass, do_callback);
+
+
+#define PREPARE_FOR_EXECUTION_WITH_ISOLATE(isolate, function_name, T)     \
+  PREPARE_FOR_EXECUTION_GENERIC(isolate, Local<Context>(), function_name, \
+                                MaybeLocal<T>(), InternalEscapableScope,  \
+                                false);
+
+
+#define PREPARE_FOR_EXECUTION(context, function_name, T)                      \
+  PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, function_name, MaybeLocal<T>(), \
+                                     InternalEscapableScope, false)
+
+
+#define PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, function_name, T)        \
+  PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, function_name, MaybeLocal<T>(), \
+                                     InternalEscapableScope, true)
+
+
+#define PREPARE_FOR_EXECUTION_PRIMITIVE(context, function_name, T)         \
+  PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, function_name, Nothing<T>(), \
+                                     i::HandleScope, false)
+
+
+#define EXCEPTION_BAILOUT_CHECK_SCOPED(isolate, value) \
+  do {                                                 \
+    if (has_pending_exception) {                       \
+      call_depth_scope.Escape();                       \
+      return value;                                    \
+    }                                                  \
   } while (false)
 
 
-#define EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, value)                    \
-  EXCEPTION_BAILOUT_CHECK_GENERIC(                                             \
-      isolate, value, isolate->FireCallCompletedCallback();)
+#define RETURN_ON_FAILED_EXECUTION(T) \
+  EXCEPTION_BAILOUT_CHECK_SCOPED(isolate, MaybeLocal<T>())
+
+
+#define RETURN_ON_FAILED_EXECUTION_PRIMITIVE(T) \
+  EXCEPTION_BAILOUT_CHECK_SCOPED(isolate, Nothing<T>())
+
+
+#define RETURN_TO_LOCAL_UNCHECKED(maybe_local, T) \
+  return maybe_local.FromMaybe(Local<T>());
+
+
+#define RETURN_ESCAPED(value) return handle_scope.Escape(value);
+
+
+namespace {
+
+Local<Context> ContextFromHeapObject(i::Handle<i::Object> obj) {
+  return reinterpret_cast<v8::Isolate*>(i::HeapObject::cast(*obj)->GetIsolate())
+      ->GetCurrentContext();
+}
+
+class InternalEscapableScope : public v8::EscapableHandleScope {
+ public:
+  explicit inline InternalEscapableScope(i::Isolate* isolate)
+      : v8::EscapableHandleScope(reinterpret_cast<v8::Isolate*>(isolate)) {}
+};
+
+
+class CallDepthScope {
+ public:
+  explicit CallDepthScope(i::Isolate* isolate, Local<Context> context,
+                          bool do_callback)
+      : isolate_(isolate),
+        context_(context),
+        escaped_(false),
+        do_callback_(do_callback) {
+    // TODO(dcarney): remove this when blink stops crashing.
+    DCHECK(!isolate_->external_caught_exception());
+    isolate_->handle_scope_implementer()->IncrementCallDepth();
+    if (!context_.IsEmpty()) context_->Enter();
+  }
+  ~CallDepthScope() {
+    if (!context_.IsEmpty()) context_->Exit();
+    if (!escaped_) isolate_->handle_scope_implementer()->DecrementCallDepth();
+    if (do_callback_) isolate_->FireCallCompletedCallback();
+  }
+
+  void Escape() {
+    DCHECK(!escaped_);
+    escaped_ = true;
+    auto handle_scope_implementer = isolate_->handle_scope_implementer();
+    handle_scope_implementer->DecrementCallDepth();
+    bool call_depth_is_zero = handle_scope_implementer->CallDepthIsZero();
+    isolate_->OptionalRescheduleException(call_depth_is_zero);
+  }
+
+ private:
+  i::Isolate* const isolate_;
+  Local<Context> context_;
+  bool escaped_;
+  bool do_callback_;
+};
+
+}  // namespace
 
 
-#define EXCEPTION_BAILOUT_CHECK(isolate, value)                                \
-  EXCEPTION_BAILOUT_CHECK_GENERIC(isolate, value, ;)
+static ScriptOrigin GetScriptOriginForScript(i::Isolate* isolate,
+                                             i::Handle<i::Script> script) {
+  i::Handle<i::Object> scriptName(i::Script::GetNameOrSourceURL(script));
+  i::Handle<i::Object> source_map_url(script->source_mapping_url(), isolate);
+  v8::Isolate* v8_isolate =
+      reinterpret_cast<v8::Isolate*>(script->GetIsolate());
+  v8::ScriptOrigin origin(
+      Utils::ToLocal(scriptName),
+      v8::Integer::New(v8_isolate, script->line_offset()->value()),
+      v8::Integer::New(v8_isolate, script->column_offset()->value()),
+      v8::Boolean::New(v8_isolate, script->is_shared_cross_origin()),
+      v8::Integer::New(v8_isolate, script->id()->value()),
+      v8::Boolean::New(v8_isolate, script->is_embedder_debug_script()),
+      Utils::ToLocal(source_map_url));
+  return origin;
+}
 
 
 // --- E x c e p t i o n   B e h a v i o r ---
@@ -134,10 +237,6 @@ void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) {
   heap_stats.cell_space_size = &cell_space_size;
   intptr_t cell_space_capacity;
   heap_stats.cell_space_capacity = &cell_space_capacity;
-  intptr_t property_cell_space_size;
-  heap_stats.property_cell_space_size = &property_cell_space_size;
-  intptr_t property_cell_space_capacity;
-  heap_stats.property_cell_space_capacity = &property_cell_space_capacity;
   intptr_t lo_space_size;
   heap_stats.lo_space_size = &lo_space_size;
   int global_handle_count;
@@ -207,8 +306,10 @@ void V8::SetSnapshotDataBlob(StartupData* snapshot_blob) {
 }
 
 
-bool RunExtraCode(Isolate* isolate, char* utf8_source) {
+bool RunExtraCode(Isolate* isolate, const char* utf8_source) {
   // Run custom script if provided.
+  base::ElapsedTimer timer;
+  timer.Start();
   TryCatch try_catch;
   Local<String> source_string = String::NewFromUtf8(isolate, utf8_source);
   if (try_catch.HasCaught()) return false;
@@ -217,18 +318,24 @@ bool RunExtraCode(Isolate* isolate, char* utf8_source) {
   Local<Script> script = ScriptCompiler::Compile(isolate, &source);
   if (try_catch.HasCaught()) return false;
   script->Run();
+  if (i::FLAG_profile_deserialization) {
+    i::PrintF("Executing custom snapshot script took %0.3f ms\n",
+              timer.Elapsed().InMillisecondsF());
+  }
+  timer.Stop();
   return !try_catch.HasCaught();
 }
 
 
-StartupData V8::CreateSnapshotDataBlob(char* custom_source) {
-  Isolate::CreateParams params;
-  params.enable_serializer = true;
-  Isolate* isolate = v8::Isolate::New(params);
+StartupData V8::CreateSnapshotDataBlob(const char* custom_source) {
+  i::Isolate* internal_isolate = new i::Isolate(true);
+  Isolate* isolate = reinterpret_cast<Isolate*>(internal_isolate);
   StartupData result = {NULL, 0};
   {
+    base::ElapsedTimer timer;
+    timer.Start();
     Isolate::Scope isolate_scope(isolate);
-    i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
+    internal_isolate->Init(NULL);
     Persistent<Context> context;
     i::Snapshot::Metadata metadata;
     {
@@ -266,6 +373,11 @@ StartupData V8::CreateSnapshotDataBlob(char* custom_source) {
 
       result = i::Snapshot::CreateSnapshotBlob(ser, context_ser, metadata);
     }
+    if (i::FLAG_profile_deserialization) {
+      i::PrintF("Creating snapshot took %0.3f ms\n",
+                timer.Elapsed().InMillisecondsF());
+    }
+    timer.Stop();
   }
   isolate->Dispose();
   return result;
@@ -431,21 +543,29 @@ void V8::MakeWeak(i::Object** object, void* parameter,
 }
 
 
-void V8::MakePhantom(i::Object** object, void* parameter,
-                     int internal_field_index1, int internal_field_index2,
-                     PhantomCallbackData<void>::Callback weak_callback) {
+void V8::MakeWeak(i::Object** object, void* parameter,
+                  int internal_field_index1, int internal_field_index2,
+                  WeakCallbackInfo<void>::Callback weak_callback) {
+  WeakCallbackType type = WeakCallbackType::kParameter;
   if (internal_field_index1 == 0) {
     if (internal_field_index2 == 1) {
-      i::GlobalHandles::MakePhantom(object, parameter, 2, weak_callback);
+      type = WeakCallbackType::kInternalFields;
     } else {
-      DCHECK_EQ(internal_field_index2, kNoInternalFieldIndex);
-      i::GlobalHandles::MakePhantom(object, parameter, 1, weak_callback);
+      DCHECK_EQ(internal_field_index2, -1);
+      type = WeakCallbackType::kInternalFields;
     }
   } else {
-    DCHECK_EQ(internal_field_index1, kNoInternalFieldIndex);
-    DCHECK_EQ(internal_field_index2, kNoInternalFieldIndex);
-    i::GlobalHandles::MakePhantom(object, parameter, 0, weak_callback);
+    DCHECK_EQ(internal_field_index1, -1);
+    DCHECK_EQ(internal_field_index2, -1);
   }
+  i::GlobalHandles::MakeWeak(object, parameter, weak_callback, type);
+}
+
+
+void V8::MakeWeak(i::Object** object, void* parameter,
+                  WeakCallbackInfo<void>::Callback weak_callback,
+                  WeakCallbackType type) {
+  i::GlobalHandles::MakeWeak(object, parameter, weak_callback, type);
 }
 
 
@@ -472,6 +592,23 @@ Local<Value> V8::GetEternal(Isolate* v8_isolate, int index) {
 }
 
 
+void V8::CheckIsJust(bool is_just) {
+  Utils::ApiCheck(is_just, "v8::FromJust", "Maybe value is Nothing.");
+}
+
+
+void V8::ToLocalEmpty() {
+  Utils::ApiCheck(false, "v8::ToLocalChecked", "Empty MaybeLocal.");
+}
+
+
+void V8::InternalFieldOutOfBounds(int index) {
+  Utils::ApiCheck(0 <= index && index < kInternalFieldsInWeakCallback,
+                  "WeakCallbackInfo::GetInternalField",
+                  "Internal field out of bounds.");
+}
+
+
 // --- H a n d l e s ---
 
 
@@ -485,10 +622,14 @@ void HandleScope::Initialize(Isolate* isolate) {
   // We do not want to check the correct usage of the Locker class all over the
   // place, so we do it only here: Without a HandleScope, an embedder can do
   // almost nothing, so it is enough to check in this central place.
-  Utils::ApiCheck(!v8::Locker::IsActive() ||
-                  internal_isolate->thread_manager()->IsLockedByCurrentThread(),
-                  "HandleScope::HandleScope",
-                  "Entering the V8 API without proper locking in place");
+  // We make an exception if the serializer is enabled, which means that the
+  // Isolate is exclusively used to create a snapshot.
+  Utils::ApiCheck(
+      !v8::Locker::IsActive() ||
+          internal_isolate->thread_manager()->IsLockedByCurrentThread() ||
+          internal_isolate->serializer_enabled(),
+      "HandleScope::HandleScope",
+      "Entering the V8 API without proper locking in place");
   i::HandleScopeData* current = internal_isolate->handle_scope_data();
   isolate_ = internal_isolate;
   prev_next_ = current->next;
@@ -833,6 +974,7 @@ static Local<FunctionTemplate> FunctionTemplateNew(
   obj->set_length(length);
   obj->set_undetectable(false);
   obj->set_needs_access_check(false);
+  obj->set_accept_any_receiver(true);
   if (!signature.IsEmpty())
     obj->set_signature(*Utils::OpenHandle(*signature));
   return Utils::ToLocal(obj);
@@ -1006,6 +1148,15 @@ void FunctionTemplate::SetClassName(Handle<String> name) {
 }
 
 
+void FunctionTemplate::SetAcceptAnyReceiver(bool value) {
+  auto info = Utils::OpenHandle(this);
+  EnsureNotInstantiated(info, "v8::FunctionTemplate::SetAcceptAnyReceiver");
+  auto isolate = info->GetIsolate();
+  ENTER_V8(isolate);
+  info->set_accept_any_receiver(value);
+}
+
+
 void FunctionTemplate::SetHiddenPrototype(bool value) {
   auto info = Utils::OpenHandle(this);
   EnsureNotInstantiated(info, "v8::FunctionTemplate::SetHiddenPrototype");
@@ -1173,10 +1324,12 @@ void ObjectTemplate::SetAccessor(v8::Handle<Name> name,
 
 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) {
+static void ObjectTemplateSetNamedPropertyHandler(ObjectTemplate* templ,
+                                                  Getter getter, Setter setter,
+                                                  Query query, Deleter remover,
+                                                  Enumerator enumerator,
+                                                  Handle<Value> data,
+                                                  PropertyHandlerFlags flags) {
   i::Isolate* isolate = Utils::OpenHandle(templ)->GetIsolate();
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
@@ -1191,9 +1344,13 @@ static void ObjectTemplateSetNamedPropertyHandler(
   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_can_intercept_symbols(
+      !(static_cast<int>(flags) &
+        static_cast<int>(PropertyHandlerFlags::kOnlyInterceptStrings)));
   obj->set_all_can_read(static_cast<int>(flags) &
                         static_cast<int>(PropertyHandlerFlags::kAllCanRead));
+  obj->set_non_masking(static_cast<int>(flags) &
+                       static_cast<int>(PropertyHandlerFlags::kNonMasking));
 
   if (data.IsEmpty()) {
     data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate));
@@ -1207,9 +1364,9 @@ 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);
+  ObjectTemplateSetNamedPropertyHandler(
+      this, getter, setter, query, remover, enumerator, data,
+      PropertyHandlerFlags::kOnlyInterceptStrings);
 }
 
 
@@ -1217,7 +1374,7 @@ void ObjectTemplate::SetHandler(
     const NamedPropertyHandlerConfiguration& config) {
   ObjectTemplateSetNamedPropertyHandler(
       this, config.getter, config.setter, config.query, config.deleter,
-      config.enumerator, config.data, true, config.flags);
+      config.enumerator, config.data, config.flags);
 }
 
 
@@ -1373,9 +1530,36 @@ Local<Script> UnboundScript::BindToCurrentContext() {
       i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
   i::Handle<i::SharedFunctionInfo>
       function_info(i::SharedFunctionInfo::cast(*obj), obj->GetIsolate());
+  i::Isolate* isolate = obj->GetIsolate();
+
+  i::ScopeInfo* scope_info = function_info->scope_info();
+  i::Handle<i::JSReceiver> global(isolate->native_context()->global_object());
+  for (int i = 0; i < scope_info->StrongModeFreeVariableCount(); ++i) {
+    i::Handle<i::String> name_string(scope_info->StrongModeFreeVariableName(i));
+    i::ScriptContextTable::LookupResult result;
+    i::Handle<i::ScriptContextTable> script_context_table(
+        isolate->native_context()->script_context_table());
+    if (!i::ScriptContextTable::Lookup(script_context_table, name_string,
+                                       &result)) {
+      i::Handle<i::Name> name(scope_info->StrongModeFreeVariableName(i));
+      Maybe<bool> has = i::JSReceiver::HasProperty(global, name);
+      if (has.IsJust() && !has.FromJust()) {
+        i::PendingCompilationErrorHandler pending_error_handler_;
+        pending_error_handler_.ReportMessageAt(
+            scope_info->StrongModeFreeVariableStartPosition(i),
+            scope_info->StrongModeFreeVariableEndPosition(i),
+            "strong_unbound_global", name_string, i::kReferenceError);
+        i::Handle<i::Script> script(i::Script::cast(function_info->script()));
+        pending_error_handler_.ThrowPendingError(isolate, script);
+        isolate->ReportPendingMessages();
+        isolate->OptionalRescheduleException(true);
+        return Local<Script>();
+      }
+    }
+  }
   i::Handle<i::JSFunction> function =
       obj->GetIsolate()->factory()->NewFunctionFromSharedFunctionInfo(
-          function_info, obj->GetIsolate()->native_context());
+          function_info, isolate->native_context());
   return ToApiHandle<Script>(function);
 }
 
@@ -1384,15 +1568,12 @@ int UnboundScript::GetId() {
   i::Handle<i::HeapObject> obj =
       i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
   i::Isolate* isolate = obj->GetIsolate();
-  ON_BAILOUT(isolate, "v8::UnboundScript::GetId()", return -1);
   LOG_API(isolate, "v8::UnboundScript::GetId");
-  {
-    i::HandleScope scope(isolate);
-    i::Handle<i::SharedFunctionInfo> function_info(
-        i::SharedFunctionInfo::cast(*obj));
-    i::Handle<i::Script> script(i::Script::cast(function_info->script()));
-    return script->id()->value();
-  }
+  i::HandleScope scope(isolate);
+  i::Handle<i::SharedFunctionInfo> function_info(
+      i::SharedFunctionInfo::cast(*obj));
+  i::Handle<i::Script> script(i::Script::cast(function_info->script()));
+  return script->id()->value();
 }
 
 
@@ -1400,7 +1581,6 @@ int UnboundScript::GetLineNumber(int code_pos) {
   i::Handle<i::SharedFunctionInfo> obj =
       i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
   i::Isolate* isolate = obj->GetIsolate();
-  ON_BAILOUT(isolate, "v8::UnboundScript::GetLineNumber()", return -1);
   LOG_API(isolate, "UnboundScript::GetLineNumber");
   if (obj->script()->IsScript()) {
     i::Handle<i::Script> script(i::Script::cast(obj->script()));
@@ -1415,8 +1595,6 @@ Handle<Value> UnboundScript::GetScriptName() {
   i::Handle<i::SharedFunctionInfo> obj =
       i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
   i::Isolate* isolate = obj->GetIsolate();
-  ON_BAILOUT(isolate, "v8::UnboundScript::GetName()",
-             return Handle<String>());
   LOG_API(isolate, "UnboundScript::GetName");
   if (obj->script()->IsScript()) {
     i::Object* name = i::Script::cast(obj->script())->name();
@@ -1431,8 +1609,6 @@ Handle<Value> UnboundScript::GetSourceURL() {
   i::Handle<i::SharedFunctionInfo> obj =
       i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
   i::Isolate* isolate = obj->GetIsolate();
-  ON_BAILOUT(isolate, "v8::UnboundScript::GetSourceURL()",
-             return Handle<String>());
   LOG_API(isolate, "UnboundScript::GetSourceURL");
   if (obj->script()->IsScript()) {
     i::Object* url = i::Script::cast(obj->script())->source_url();
@@ -1447,8 +1623,6 @@ Handle<Value> UnboundScript::GetSourceMappingURL() {
   i::Handle<i::SharedFunctionInfo> obj =
       i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
   i::Isolate* isolate = obj->GetIsolate();
-  ON_BAILOUT(isolate, "v8::UnboundScript::GetSourceMappingURL()",
-             return Handle<String>());
   LOG_API(isolate, "UnboundScript::GetSourceMappingURL");
   if (obj->script()->IsScript()) {
     i::Object* url = i::Script::cast(obj->script())->source_mapping_url();
@@ -1459,26 +1633,28 @@ Handle<Value> UnboundScript::GetSourceMappingURL() {
 }
 
 
-Local<Value> Script::Run() {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this, true);
-  // If execution is terminating, Compile(..)->Run() requires this
-  // check.
-  if (obj.is_null()) return Local<Value>();
-  i::Isolate* isolate = i::Handle<i::HeapObject>::cast(obj)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Script::Run()", return Local<Value>());
-  LOG_API(isolate, "Script::Run");
-  ENTER_V8(isolate);
+MaybeLocal<Value> Script::Run(Local<Context> context) {
+  PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, "v8::Script::Run()", Value)
   i::AggregatingHistogramTimerScope timer(isolate->counters()->compile_lazy());
   i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(obj);
-  EXCEPTION_PREAMBLE(isolate);
+  auto fun = i::Handle<i::JSFunction>::cast(Utils::OpenHandle(this));
   i::Handle<i::Object> receiver(isolate->global_proxy(), isolate);
-  i::Handle<i::Object> result;
-  has_pending_exception = !i::Execution::Call(
-      isolate, fun, receiver, 0, NULL).ToHandle(&result);
-  EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<Value>());
-  return Utils::ToLocal(scope.CloseAndEscape(result));
+  Local<Value> result;
+  has_pending_exception =
+      !ToLocal<Value>(i::Execution::Call(isolate, fun, receiver, 0, NULL),
+                      &result);
+  RETURN_ON_FAILED_EXECUTION(Value);
+  RETURN_ESCAPED(result);
+}
+
+
+Local<Value> Script::Run() {
+  auto self = Utils::OpenHandle(this, true);
+  // If execution is terminating, Compile(..)->Run() requires this
+  // check.
+  if (self.is_null()) return Local<Value>();
+  auto context = ContextFromHeapObject(self);
+  RETURN_TO_LOCAL_UNCHECKED(Run(context), Value);
 }
 
 
@@ -1489,12 +1665,12 @@ Local<UnboundScript> Script::GetUnboundScript() {
 }
 
 
-Local<UnboundScript> ScriptCompiler::CompileUnboundInternal(
+MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal(
     Isolate* v8_isolate, Source* source, CompileOptions options,
     bool is_module) {
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-  ON_BAILOUT(isolate, "v8::ScriptCompiler::CompileUnbound()",
-             return Local<UnboundScript>());
+  PREPARE_FOR_EXECUTION_WITH_ISOLATE(
+      isolate, "v8::ScriptCompiler::CompileUnbound()", UnboundScript);
 
   // Support the old API for a transition period:
   // - kProduceToCache -> kProduceParserCache
@@ -1520,12 +1696,11 @@ Local<UnboundScript> ScriptCompiler::CompileUnboundInternal(
   }
 
   i::Handle<i::String> str = Utils::OpenHandle(*(source->source_string));
-  LOG_API(isolate, "ScriptCompiler::CompileUnbound");
-  ENTER_V8(isolate);
   i::SharedFunctionInfo* raw_result = NULL;
   { i::HandleScope scope(isolate);
     i::HistogramTimerScope total(isolate->counters()->compile_script(), true);
     i::Handle<i::Object> name_obj;
+    i::Handle<i::Object> source_map_url;
     int line_offset = 0;
     int column_offset = 0;
     bool is_embedder_debug_script = false;
@@ -1548,11 +1723,13 @@ Local<UnboundScript> ScriptCompiler::CompileUnboundInternal(
       is_embedder_debug_script =
           source->resource_is_embedder_debug_script->IsTrue();
     }
-    EXCEPTION_PREAMBLE(isolate);
+    if (!source->source_map_url.IsEmpty()) {
+      source_map_url = Utils::OpenHandle(*(source->source_map_url));
+    }
     i::Handle<i::SharedFunctionInfo> result = i::Compiler::CompileScript(
         str, name_obj, line_offset, column_offset, is_embedder_debug_script,
-        is_shared_cross_origin, isolate->native_context(), NULL, &script_data,
-        options, i::NOT_NATIVES_CODE, is_module);
+        is_shared_cross_origin, source_map_url, isolate->native_context(), NULL,
+        &script_data, options, i::NOT_NATIVES_CODE, is_module);
     has_pending_exception = result.is_null();
     if (has_pending_exception && script_data != NULL) {
       // This case won't happen during normal operation; we have compiled
@@ -1561,7 +1738,7 @@ Local<UnboundScript> ScriptCompiler::CompileUnboundInternal(
       delete script_data;
       script_data = NULL;
     }
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>());
+    RETURN_ON_FAILED_EXECUTION(UnboundScript);
     raw_result = *result;
 
     if ((options == kProduceParserCache || options == kProduceCodeCache) &&
@@ -1577,14 +1754,34 @@ Local<UnboundScript> ScriptCompiler::CompileUnboundInternal(
     delete script_data;
   }
   i::Handle<i::SharedFunctionInfo> result(raw_result, isolate);
-  return ToApiHandle<UnboundScript>(result);
+  RETURN_ESCAPED(ToApiHandle<UnboundScript>(result));
+}
+
+
+MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundScript(
+    Isolate* v8_isolate, Source* source, CompileOptions options) {
+  return CompileUnboundInternal(v8_isolate, source, options, false);
 }
 
 
 Local<UnboundScript> ScriptCompiler::CompileUnbound(Isolate* v8_isolate,
                                                     Source* source,
                                                     CompileOptions options) {
-  return CompileUnboundInternal(v8_isolate, source, options, false);
+  RETURN_TO_LOCAL_UNCHECKED(
+      CompileUnboundInternal(v8_isolate, source, options, false),
+      UnboundScript);
+}
+
+
+MaybeLocal<Script> ScriptCompiler::Compile(Local<Context> context,
+                                           Source* source,
+                                           CompileOptions options) {
+  auto isolate = context->GetIsolate();
+  auto maybe = CompileUnboundInternal(isolate, source, options, false);
+  Local<UnboundScript> result;
+  if (!maybe.ToLocal(&result)) return MaybeLocal<Script>();
+  v8::Context::Scope scope(context);
+  return result->BindToCurrentContext();
 }
 
 
@@ -1592,28 +1789,28 @@ Local<Script> ScriptCompiler::Compile(
     Isolate* v8_isolate,
     Source* source,
     CompileOptions options) {
-  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-  ON_BAILOUT(isolate, "v8::ScriptCompiler::Compile()", return Local<Script>());
-  LOG_API(isolate, "ScriptCompiler::CompileBound()");
-  ENTER_V8(isolate);
-  Local<UnboundScript> generic = CompileUnbound(v8_isolate, source, options);
-  if (generic.IsEmpty()) return Local<Script>();
+  auto context = v8_isolate->GetCurrentContext();
+  RETURN_TO_LOCAL_UNCHECKED(Compile(context, source, options), Script);
+}
+
+
+MaybeLocal<Script> ScriptCompiler::CompileModule(Local<Context> context,
+                                                 Source* source,
+                                                 CompileOptions options) {
+  CHECK(i::FLAG_harmony_modules);
+  auto isolate = context->GetIsolate();
+  auto maybe = CompileUnboundInternal(isolate, source, options, true);
+  Local<UnboundScript> generic;
+  if (!maybe.ToLocal(&generic)) return MaybeLocal<Script>();
+  v8::Context::Scope scope(context);
   return generic->BindToCurrentContext();
 }
 
 
 Local<Script> ScriptCompiler::CompileModule(Isolate* v8_isolate, Source* source,
                                             CompileOptions options) {
-  CHECK(i::FLAG_harmony_modules);
-  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-  ON_BAILOUT(isolate, "v8::ScriptCompiler::CompileModule()",
-             return Local<Script>());
-  LOG_API(isolate, "ScriptCompiler::CompileModule()");
-  ENTER_V8(isolate);
-  Local<UnboundScript> generic =
-      CompileUnboundInternal(v8_isolate, source, options, true);
-  if (generic.IsEmpty()) return Local<Script>();
-  return generic->BindToCurrentContext();
+  auto context = v8_isolate->GetCurrentContext();
+  RETURN_TO_LOCAL_UNCHECKED(CompileModule(context, source, options), Script);
 }
 
 
@@ -1656,64 +1853,52 @@ class IsIdentifierHelper {
 };
 
 
-Local<Function> ScriptCompiler::CompileFunctionInContext(
-    Isolate* v8_isolate, Source* source, Local<Context> v8_context,
-    size_t arguments_count, Local<String> arguments[],
-    size_t context_extension_count, Local<Object> context_extensions[]) {
-  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-  ON_BAILOUT(isolate, "v8::ScriptCompiler::CompileFunctionInContext()",
-             return Local<Function>());
-  LOG_API(isolate, "ScriptCompiler::CompileFunctionInContext()");
-  ENTER_V8(isolate);
-
+MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext(
+    Local<Context> v8_context, Source* source, size_t arguments_count,
+    Local<String> arguments[], size_t context_extension_count,
+    Local<Object> context_extensions[]) {
+  PREPARE_FOR_EXECUTION(
+      v8_context, "v8::ScriptCompiler::CompileFunctionInContext()", Function);
   i::Handle<i::String> source_string;
+  auto factory = isolate->factory();
   if (arguments_count) {
-    source_string =
-        Utils::OpenHandle(*v8::String::NewFromUtf8(v8_isolate, "(function("));
+    source_string = factory->NewStringFromStaticChars("(function(");
     for (size_t i = 0; i < arguments_count; ++i) {
       IsIdentifierHelper helper;
       if (!helper.Check(*Utils::OpenHandle(*arguments[i]))) {
         return Local<Function>();
       }
-      i::MaybeHandle<i::String> maybe_source =
-          isolate->factory()->NewConsString(source_string,
-                                            Utils::OpenHandle(*arguments[i]));
-      if (!maybe_source.ToHandle(&source_string)) {
-        return Local<Function>();
-      }
+      has_pending_exception =
+          !factory->NewConsString(source_string,
+                                  Utils::OpenHandle(*arguments[i]))
+               .ToHandle(&source_string);
+      RETURN_ON_FAILED_EXECUTION(Function);
       if (i + 1 == arguments_count) continue;
-      maybe_source = isolate->factory()->NewConsString(
-          source_string,
-          isolate->factory()->LookupSingleCharacterStringFromCode(','));
-      if (!maybe_source.ToHandle(&source_string)) {
-        return Local<Function>();
-      }
-    }
-    i::Handle<i::String> brackets =
-        Utils::OpenHandle(*v8::String::NewFromUtf8(v8_isolate, "){"));
-    i::MaybeHandle<i::String> maybe_source =
-        isolate->factory()->NewConsString(source_string, brackets);
-    if (!maybe_source.ToHandle(&source_string)) {
-      return Local<Function>();
+      has_pending_exception =
+          !factory->NewConsString(source_string,
+                                  factory->LookupSingleCharacterStringFromCode(
+                                      ',')).ToHandle(&source_string);
+      RETURN_ON_FAILED_EXECUTION(Function);
     }
+    auto brackets = factory->NewStringFromStaticChars("){");
+    has_pending_exception = !factory->NewConsString(source_string, brackets)
+                                 .ToHandle(&source_string);
+    RETURN_ON_FAILED_EXECUTION(Function);
   } else {
-    source_string =
-        Utils::OpenHandle(*v8::String::NewFromUtf8(v8_isolate, "(function(){"));
+    source_string = factory->NewStringFromStaticChars("(function(){");
   }
 
   int scope_position = source_string->length();
-  i::MaybeHandle<i::String> maybe_source = isolate->factory()->NewConsString(
-      source_string, Utils::OpenHandle(*source->source_string));
-  if (!maybe_source.ToHandle(&source_string)) {
-    return Local<Function>();
-  }
+  has_pending_exception =
+      !factory->NewConsString(source_string,
+                              Utils::OpenHandle(*source->source_string))
+           .ToHandle(&source_string);
+  RETURN_ON_FAILED_EXECUTION(Function);
   // Include \n in case the source contains a line end comment.
-  i::Handle<i::String> brackets =
-      Utils::OpenHandle(*v8::String::NewFromUtf8(v8_isolate, "\n})"));
-  maybe_source = isolate->factory()->NewConsString(source_string, brackets);
-  if (!maybe_source.ToHandle(&source_string)) {
-    return Local<Function>();
-  }
+  auto brackets = factory->NewStringFromStaticChars("\n})");
+  has_pending_exception =
+      !factory->NewConsString(source_string, brackets).ToHandle(&source_string);
+  RETURN_ON_FAILED_EXECUTION(Function);
 
   i::Handle<i::Context> context = Utils::OpenHandle(*v8_context);
   i::Handle<i::SharedFunctionInfo> outer_info(context->closure()->shared(),
@@ -1722,23 +1907,34 @@ Local<Function> ScriptCompiler::CompileFunctionInContext(
     i::Handle<i::JSObject> extension =
         Utils::OpenHandle(*context_extensions[i]);
     i::Handle<i::JSFunction> closure(context->closure(), isolate);
-    context = isolate->factory()->NewWithContext(closure, context, extension);
+    context = factory->NewWithContext(closure, context, extension);
   }
 
-  EXCEPTION_PREAMBLE(isolate);
-  i::MaybeHandle<i::JSFunction> maybe_fun = i::Compiler::GetFunctionFromEval(
-      source_string, outer_info, context, i::SLOPPY,
-      i::ONLY_SINGLE_FUNCTION_LITERAL, scope_position);
   i::Handle<i::JSFunction> fun;
-  has_pending_exception = !maybe_fun.ToHandle(&fun);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<Function>());
+  has_pending_exception =
+      !i::Compiler::GetFunctionFromEval(
+           source_string, outer_info, context, i::SLOPPY,
+           i::ONLY_SINGLE_FUNCTION_LITERAL, scope_position).ToHandle(&fun);
+  RETURN_ON_FAILED_EXECUTION(Function);
 
-  i::MaybeHandle<i::Object> result = i::Execution::Call(
-      isolate, fun, Utils::OpenHandle(*v8_context->Global()), 0, NULL);
-  i::Handle<i::Object> final_result;
-  has_pending_exception = !result.ToHandle(&final_result);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<Function>());
-  return Utils::ToLocal(i::Handle<i::JSFunction>::cast(final_result));
+  i::Handle<i::Object> result;
+  has_pending_exception =
+      !i::Execution::Call(isolate, fun,
+                          Utils::OpenHandle(*v8_context->Global()), 0,
+                          nullptr).ToHandle(&result);
+  RETURN_ON_FAILED_EXECUTION(Function);
+  RETURN_ESCAPED(Utils::ToLocal(i::Handle<i::JSFunction>::cast(result)));
+}
+
+
+Local<Function> ScriptCompiler::CompileFunctionInContext(
+    Isolate* v8_isolate, Source* source, Local<Context> v8_context,
+    size_t arguments_count, Local<String> arguments[],
+    size_t context_extension_count, Local<Object> context_extensions[]) {
+  RETURN_TO_LOCAL_UNCHECKED(
+      CompileFunctionInContext(v8_context, source, arguments_count, arguments,
+                               context_extension_count, context_extensions),
+      Function);
 }
 
 
@@ -1750,17 +1946,13 @@ ScriptCompiler::ScriptStreamingTask* ScriptCompiler::StartStreamingScript(
 }
 
 
-Local<Script> ScriptCompiler::Compile(Isolate* v8_isolate,
-                                      StreamedSource* v8_source,
-                                      Handle<String> full_source_string,
-                                      const ScriptOrigin& origin) {
-  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+MaybeLocal<Script> ScriptCompiler::Compile(Local<Context> context,
+                                           StreamedSource* v8_source,
+                                           Handle<String> full_source_string,
+                                           const ScriptOrigin& origin) {
+  PREPARE_FOR_EXECUTION(context, "v8::ScriptCompiler::Compile()", Script);
   i::StreamedSource* source = v8_source->impl();
-  ON_BAILOUT(isolate, "v8::ScriptCompiler::Compile()", return Local<Script>());
-  LOG_API(isolate, "ScriptCompiler::Compile()");
-  ENTER_V8(isolate);
-  i::SharedFunctionInfo* raw_result = NULL;
-
+  i::SharedFunctionInfo* raw_result = nullptr;
   {
     i::HandleScope scope(isolate);
     i::Handle<i::String> str = Utils::OpenHandle(*(full_source_string));
@@ -1784,38 +1976,50 @@ Local<Script> ScriptCompiler::Compile(Isolate* v8_isolate,
       script->set_is_embedder_debug_script(
           origin.ResourceIsEmbedderDebugScript()->IsTrue());
     }
-    source->info->set_script(script);
-    source->info->SetContext(isolate->native_context());
+    if (!origin.SourceMapUrl().IsEmpty()) {
+      script->set_source_mapping_url(
+          *Utils::OpenHandle(*(origin.SourceMapUrl())));
+    }
 
-    EXCEPTION_PREAMBLE(isolate);
+    source->info->set_script(script);
+    source->info->set_context(isolate->native_context());
 
     // Do the parsing tasks which need to be done on the main thread. This will
     // also handle parse errors.
-    source->parser->Internalize(source->info.get());
-    source->parser->HandleSourceURLComments(source->info.get());
+    source->parser->Internalize(isolate, script,
+                                source->info->function() == nullptr);
+    source->parser->HandleSourceURLComments(isolate, script);
 
-    i::Handle<i::SharedFunctionInfo> result =
-        i::Handle<i::SharedFunctionInfo>::null();
-    if (source->info->function() != NULL) {
+    i::Handle<i::SharedFunctionInfo> result;
+    if (source->info->function() != nullptr) {
       // Parsing has succeeded.
-      result =
-          i::Compiler::CompileStreamedScript(source->info.get(), str->length());
+      result = i::Compiler::CompileStreamedScript(script, source->info.get(),
+                                                  str->length());
     }
     has_pending_exception = result.is_null();
     if (has_pending_exception) isolate->ReportPendingMessages();
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>());
+    RETURN_ON_FAILED_EXECUTION(Script);
+
+    source->info->clear_script();  // because script goes out of scope.
+    raw_result = *result;          // TODO(titzer): use CloseAndEscape?
+  }
 
-    raw_result = *result;
-    // The Handle<Script> will go out of scope soon; make sure CompilationInfo
-    // doesn't point to it.
-    source->info->set_script(i::Handle<i::Script>());
-  }  // HandleScope goes out of scope.
   i::Handle<i::SharedFunctionInfo> result(raw_result, isolate);
   Local<UnboundScript> generic = ToApiHandle<UnboundScript>(result);
-  if (generic.IsEmpty()) {
-    return Local<Script>();
-  }
-  return generic->BindToCurrentContext();
+  if (generic.IsEmpty()) return Local<Script>();
+  Local<Script> bound = generic->BindToCurrentContext();
+  if (bound.IsEmpty()) return Local<Script>();
+  RETURN_ESCAPED(bound);
+}
+
+
+Local<Script> ScriptCompiler::Compile(Isolate* v8_isolate,
+                                      StreamedSource* v8_source,
+                                      Handle<String> full_source_string,
+                                      const ScriptOrigin& origin) {
+  auto context = v8_isolate->GetCurrentContext();
+  RETURN_TO_LOCAL_UNCHECKED(
+      Compile(context, v8_source, full_source_string, origin), Script);
 }
 
 
@@ -1826,19 +2030,23 @@ uint32_t ScriptCompiler::CachedDataVersionTag() {
 }
 
 
-Local<Script> Script::Compile(v8::Handle<String> source,
-                              v8::ScriptOrigin* origin) {
-  i::Handle<i::String> str = Utils::OpenHandle(*source);
+MaybeLocal<Script> Script::Compile(Local<Context> context,
+                                   Handle<String> source,
+                                   ScriptOrigin* origin) {
   if (origin) {
     ScriptCompiler::Source script_source(source, *origin);
-    return ScriptCompiler::Compile(
-        reinterpret_cast<v8::Isolate*>(str->GetIsolate()),
-        &script_source);
+    return ScriptCompiler::Compile(context, &script_source);
   }
   ScriptCompiler::Source script_source(source);
-  return ScriptCompiler::Compile(
-      reinterpret_cast<v8::Isolate*>(str->GetIsolate()),
-      &script_source);
+  return ScriptCompiler::Compile(context, &script_source);
+}
+
+
+Local<Script> Script::Compile(v8::Handle<String> source,
+                              v8::ScriptOrigin* origin) {
+  auto str = Utils::OpenHandle(*source);
+  auto context = ContextFromHeapObject(str);
+  RETURN_TO_LOCAL_UNCHECKED(Compile(context, source, origin), Script);
 }
 
 
@@ -1894,7 +2102,7 @@ v8::TryCatch::~TryCatch() {
     if (HasCaught() && capture_message_) {
       // If an exception was caught and rethrow_ is indicated, the saved
       // message, script, and location need to be restored to Isolate TLS
-      // for reuse.  capture_message_ needs to be disabled so that DoThrow()
+      // for reuse.  capture_message_ needs to be disabled so that Throw()
       // does not create a new message.
       isolate_->thread_local_top()->rethrowing_message_ = true;
       isolate_->RestorePendingMessageFromTryCatch(this);
@@ -1949,28 +2157,28 @@ v8::Local<Value> v8::TryCatch::Exception() const {
 }
 
 
+MaybeLocal<Value> v8::TryCatch::StackTrace(Local<Context> context) const {
+  if (!HasCaught()) return v8::Local<Value>();
+  i::Object* raw_obj = reinterpret_cast<i::Object*>(exception_);
+  if (!raw_obj->IsJSObject()) return v8::Local<Value>();
+  PREPARE_FOR_EXECUTION(context, "v8::TryCatch::StackTrace", Value);
+  i::Handle<i::JSObject> obj(i::JSObject::cast(raw_obj), isolate_);
+  i::Handle<i::String> name = isolate->factory()->stack_string();
+  Maybe<bool> maybe = i::JSReceiver::HasProperty(obj, name);
+  has_pending_exception = !maybe.IsJust();
+  RETURN_ON_FAILED_EXECUTION(Value);
+  if (!maybe.FromJust()) return v8::Local<Value>();
+  Local<Value> result;
+  has_pending_exception =
+      !ToLocal<Value>(i::Object::GetProperty(obj, name), &result);
+  RETURN_ON_FAILED_EXECUTION(Value);
+  RETURN_ESCAPED(result);
+}
+
+
 v8::Local<Value> v8::TryCatch::StackTrace() const {
-  if (HasCaught()) {
-    i::Object* raw_obj = reinterpret_cast<i::Object*>(exception_);
-    if (!raw_obj->IsJSObject()) return v8::Local<Value>();
-    i::HandleScope scope(isolate_);
-    i::Handle<i::JSObject> obj(i::JSObject::cast(raw_obj), isolate_);
-    i::Handle<i::String> name = isolate_->factory()->stack_string();
-    {
-      EXCEPTION_PREAMBLE(isolate_);
-      Maybe<bool> maybe = i::JSReceiver::HasProperty(obj, name);
-      has_pending_exception = !maybe.has_value;
-      EXCEPTION_BAILOUT_CHECK(isolate_, v8::Local<Value>());
-      if (!maybe.value) return v8::Local<Value>();
-    }
-    i::Handle<i::Object> value;
-    EXCEPTION_PREAMBLE(isolate_);
-    has_pending_exception = !i::Object::GetProperty(obj, name).ToHandle(&value);
-    EXCEPTION_BAILOUT_CHECK(isolate_, v8::Local<Value>());
-    return v8::Utils::ToLocal(scope.CloseAndEscape(value));
-  } else {
-    return v8::Local<Value>();
-  }
+  auto context = reinterpret_cast<v8::Isolate*>(isolate_)->GetCurrentContext();
+  RETURN_TO_LOCAL_UNCHECKED(StackTrace(context), Value);
 }
 
 
@@ -2000,9 +2208,6 @@ void v8::TryCatch::ResetInternal() {
   i::Object* the_hole = isolate_->heap()->the_hole_value();
   exception_ = the_hole;
   message_obj_ = the_hole;
-  message_script_ = the_hole;
-  message_start_pos_ = 0;
-  message_end_pos_ = 0;
 }
 
 
@@ -2021,7 +2226,6 @@ void v8::TryCatch::SetCaptureMessage(bool value) {
 
 Local<String> Message::Get() const {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Message::Get()", return Local<String>());
   ENTER_V8(isolate);
   EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
@@ -2033,24 +2237,11 @@ Local<String> Message::Get() const {
 
 ScriptOrigin Message::GetScriptOrigin() const {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  i::Handle<i::JSMessageObject> message =
-      i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
-  i::Handle<i::Object> script_wraper =
-      i::Handle<i::Object>(message->script(), isolate);
-  i::Handle<i::JSValue> script_value =
-      i::Handle<i::JSValue>::cast(script_wraper);
+  auto message = i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
+  auto script_wraper = i::Handle<i::Object>(message->script(), isolate);
+  auto script_value = i::Handle<i::JSValue>::cast(script_wraper);
   i::Handle<i::Script> script(i::Script::cast(script_value->value()));
-  i::Handle<i::Object> scriptName(i::Script::GetNameOrSourceURL(script));
-  v8::Isolate* v8_isolate =
-      reinterpret_cast<v8::Isolate*>(script->GetIsolate());
-  v8::ScriptOrigin origin(
-      Utils::ToLocal(scriptName),
-      v8::Integer::New(v8_isolate, script->line_offset()->value()),
-      v8::Integer::New(v8_isolate, script->column_offset()->value()),
-      v8::Boolean::New(v8_isolate, script->is_shared_cross_origin()),
-      v8::Integer::New(v8_isolate, script->id()->value()),
-      v8::Boolean::New(v8_isolate, script->is_embedder_debug_script()));
-  return origin;
+  return GetScriptOriginForScript(isolate, script);
 }
 
 
@@ -2063,12 +2254,10 @@ v8::Handle<v8::StackTrace> Message::GetStackTrace() const {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ENTER_V8(isolate);
   EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
-  i::Handle<i::JSMessageObject> message =
-      i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
+  auto message = i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
   i::Handle<i::Object> stackFramesObj(message->stack_frames(), isolate);
   if (!stackFramesObj->IsJSArray()) return v8::Handle<v8::StackTrace>();
-  i::Handle<i::JSArray> stackTrace =
-      i::Handle<i::JSArray>::cast(stackFramesObj);
+  auto stackTrace = i::Handle<i::JSArray>::cast(stackFramesObj);
   return scope.Escape(Utils::StackTraceToLocal(stackTrace));
 }
 
@@ -2092,107 +2281,102 @@ MUST_USE_RESULT static i::MaybeHandle<i::Object> CallV8HeapFunction(
 }
 
 
-int Message::GetLineNumber() const {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Message::GetLineNumber()", return kNoLineNumberInfo);
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-
-  EXCEPTION_PREAMBLE(isolate);
+Maybe<int> Message::GetLineNumber(Local<Context> context) const {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Message::GetLineNumber()", int);
   i::Handle<i::Object> result;
   has_pending_exception =
       !CallV8HeapFunction(isolate, "GetLineNumber", Utils::OpenHandle(this))
            .ToHandle(&result);
-  EXCEPTION_BAILOUT_CHECK(isolate, 0);
-  return static_cast<int>(result->Number());
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(int);
+  return Just(static_cast<int>(result->Number()));
+}
+
+
+int Message::GetLineNumber() const {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return GetLineNumber(context).FromMaybe(0);
 }
 
 
 int Message::GetStartPosition() const {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSMessageObject> message =
-      i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
-  return message->start_position();
+  auto self = Utils::OpenHandle(this);
+  return self->start_position();
 }
 
 
 int Message::GetEndPosition() const {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSMessageObject> message =
-      i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
-  return message->end_position();
+  auto self = Utils::OpenHandle(this);
+  return self->end_position();
+}
+
+
+Maybe<int> Message::GetStartColumn(Local<Context> context) const {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Message::GetStartColumn()",
+                                  int);
+  auto self = Utils::OpenHandle(this);
+  i::Handle<i::Object> start_col_obj;
+  has_pending_exception = !CallV8HeapFunction(isolate, "GetPositionInLine",
+                                              self).ToHandle(&start_col_obj);
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(int);
+  return Just(static_cast<int>(start_col_obj->Number()));
 }
 
 
 int Message::GetStartColumn() const {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Message::GetStartColumn()", return kNoColumnInfo);
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
-  EXCEPTION_PREAMBLE(isolate);
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  const int default_value = kNoColumnInfo;
+  return GetStartColumn(context).FromMaybe(default_value);
+}
+
+
+Maybe<int> Message::GetEndColumn(Local<Context> context) const {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Message::GetEndColumn()", int);
+  auto self = Utils::OpenHandle(this);
   i::Handle<i::Object> 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());
+  has_pending_exception = !CallV8HeapFunction(isolate, "GetPositionInLine",
+                                              self).ToHandle(&start_col_obj);
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(int);
+  int start = self->start_position();
+  int end = self->end_position();
+  return Just(static_cast<int>(start_col_obj->Number()) + (end - start));
 }
 
 
 int Message::GetEndColumn() const {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Message::GetEndColumn()", return kNoColumnInfo);
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
-  EXCEPTION_PREAMBLE(isolate);
-  i::Handle<i::Object> 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);
-  int start = message->start_position();
-  int end = message->end_position();
-  return static_cast<int>(start_col_obj->Number()) + (end - start);
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  const int default_value = kNoColumnInfo;
+  return GetEndColumn(context).FromMaybe(default_value);
 }
 
 
 bool Message::IsSharedCrossOrigin() const {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSMessageObject> message =
-      i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
-  i::Handle<i::JSValue> script =
-      i::Handle<i::JSValue>::cast(i::Handle<i::Object>(message->script(),
-                                                       isolate));
+  auto self = Utils::OpenHandle(this);
+  auto script = i::Handle<i::JSValue>::cast(
+      i::Handle<i::Object>(self->script(), isolate));
   return i::Script::cast(script->value())->is_shared_cross_origin();
 }
 
 
-Local<String> Message::GetSourceLine() const {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Message::GetSourceLine()", return Local<String>());
-  ENTER_V8(isolate);
-  EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
-  EXCEPTION_PREAMBLE(isolate);
+MaybeLocal<String> Message::GetSourceLine(Local<Context> context) const {
+  PREPARE_FOR_EXECUTION(context, "v8::Message::GetSourceLine()", String);
   i::Handle<i::Object> result;
   has_pending_exception =
       !CallV8HeapFunction(isolate, "GetSourceLine", Utils::OpenHandle(this))
            .ToHandle(&result);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::String>());
+  RETURN_ON_FAILED_EXECUTION(String);
+  Local<String> str;
   if (result->IsString()) {
-    return scope.Escape(Utils::ToLocal(i::Handle<i::String>::cast(result)));
-  } else {
-    return Local<String>();
+    str = Utils::ToLocal(i::Handle<i::String>::cast(result));
   }
+  RETURN_ESCAPED(str);
+}
+
+
+Local<String> Message::GetSourceLine() const {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(GetSourceLine(context), String)
 }
 
 
@@ -2209,24 +2393,19 @@ Local<StackFrame> StackTrace::GetFrame(uint32_t index) const {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ENTER_V8(isolate);
   EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
-  i::Handle<i::JSArray> self = Utils::OpenHandle(this);
-  i::Handle<i::Object> obj =
-      i::Object::GetElement(isolate, self, index).ToHandleChecked();
-  i::Handle<i::JSObject> jsobj = i::Handle<i::JSObject>::cast(obj);
+  auto self = Utils::OpenHandle(this);
+  auto obj = i::Object::GetElement(isolate, self, index).ToHandleChecked();
+  auto jsobj = i::Handle<i::JSObject>::cast(obj);
   return scope.Escape(Utils::StackFrameToLocal(jsobj));
 }
 
 
 int StackTrace::GetFrameCount() const {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ENTER_V8(isolate);
   return i::Smi::cast(Utils::OpenHandle(this)->length())->value();
 }
 
 
 Local<Array> StackTrace::AsArray() {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ENTER_V8(isolate);
   return Utils::ToLocal(Utils::OpenHandle(this));
 }
 
@@ -2419,21 +2598,25 @@ bool NativeWeakMap::Delete(Handle<Value> v8_key) {
 
 // --- J S O N ---
 
-Local<Value> JSON::Parse(Local<String> json_string) {
+MaybeLocal<Value> JSON::Parse(Isolate* v8_isolate, Local<String> json_string) {
+  auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+  PREPARE_FOR_EXECUTION_WITH_ISOLATE(isolate, "JSON::Parse", Value);
   i::Handle<i::String> string = Utils::OpenHandle(*json_string);
-  i::Isolate* isolate = string->GetIsolate();
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
   i::Handle<i::String> source = i::String::Flatten(string);
-  EXCEPTION_PREAMBLE(isolate);
-  i::MaybeHandle<i::Object> maybe_result =
-      source->IsSeqOneByteString() ? i::JsonParser<true>::Parse(source)
-                                   : i::JsonParser<false>::Parse(source);
-  i::Handle<i::Object> result;
-  has_pending_exception = !maybe_result.ToHandle(&result);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<Object>());
-  return Utils::ToLocal(
-      i::Handle<i::Object>::cast(scope.CloseAndEscape(result)));
+  auto maybe = source->IsSeqOneByteString()
+                   ? i::JsonParser<true>::Parse(source)
+                   : i::JsonParser<false>::Parse(source);
+  Local<Value> result;
+  has_pending_exception = !ToLocal<Value>(maybe, &result);
+  RETURN_ON_FAILED_EXECUTION(Value);
+  RETURN_ESCAPED(result);
+}
+
+
+Local<Value> JSON::Parse(Local<String> json_string) {
+  auto isolate = reinterpret_cast<v8::Isolate*>(
+      Utils::OpenHandle(*json_string)->GetIsolate());
+  RETURN_TO_LOCAL_UNCHECKED(Parse(isolate, json_string), Value);
 }
 
 
@@ -2591,7 +2774,7 @@ bool Value::IsUint32() const {
 static bool CheckConstructor(i::Isolate* isolate,
                              i::Handle<i::JSObject> obj,
                              const char* class_name) {
-  i::Handle<i::Object> constr(obj->map()->constructor(), isolate);
+  i::Handle<i::Object> constr(obj->map()->GetConstructor(), isolate);
   if (!constr->IsJSFunction()) return false;
   i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(constr);
   return func->shared()->native() && constr.is_identical_to(
@@ -2648,108 +2831,137 @@ bool Value::IsSetIterator() const {
 }
 
 
-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 = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToString");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToString(
-        isolate, obj).ToHandle(&str);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<String>());
-  }
-  return ToApiHandle<String>(str);
+MaybeLocal<String> Value::ToString(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsString()) return ToApiHandle<String>(obj);
+  PREPARE_FOR_EXECUTION(context, "ToString", String);
+  Local<String> result;
+  has_pending_exception =
+      !ToLocal<String>(i::Execution::ToString(isolate, obj), &result);
+  RETURN_ON_FAILED_EXECUTION(String);
+  RETURN_ESCAPED(result);
 }
 
 
-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 = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToDetailString");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToDetailString(
-        isolate, obj).ToHandle(&str);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<String>());
-  }
-  return ToApiHandle<String>(str);
+Local<String> Value::ToString(Isolate* isolate) const {
+  RETURN_TO_LOCAL_UNCHECKED(ToString(isolate->GetCurrentContext()), String);
 }
 
 
-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 = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToObject");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToObject(
-        isolate, obj).ToHandle(&val);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
-  }
-  return ToApiHandle<Object>(val);
+MaybeLocal<String> Value::ToDetailString(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsString()) return ToApiHandle<String>(obj);
+  PREPARE_FOR_EXECUTION(context, "ToDetailString", String);
+  Local<String> result;
+  has_pending_exception =
+      !ToLocal<String>(i::Execution::ToDetailString(isolate, obj), &result);
+  RETURN_ON_FAILED_EXECUTION(String);
+  RETURN_ESCAPED(result);
+}
+
+
+Local<String> Value::ToDetailString(Isolate* isolate) const {
+  RETURN_TO_LOCAL_UNCHECKED(ToDetailString(isolate->GetCurrentContext()),
+                            String);
+}
+
+
+MaybeLocal<Object> Value::ToObject(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsJSObject()) return ToApiHandle<Object>(obj);
+  PREPARE_FOR_EXECUTION(context, "ToObject", Object);
+  Local<Object> result;
+  has_pending_exception =
+      !ToLocal<Object>(i::Execution::ToObject(isolate, obj), &result);
+  RETURN_ON_FAILED_EXECUTION(Object);
+  RETURN_ESCAPED(result);
+}
+
+
+Local<v8::Object> Value::ToObject(Isolate* isolate) const {
+  RETURN_TO_LOCAL_UNCHECKED(ToObject(isolate->GetCurrentContext()), Object);
+}
+
+
+MaybeLocal<Boolean> Value::ToBoolean(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsBoolean()) return ToApiHandle<Boolean>(obj);
+  auto isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
+  auto val = isolate->factory()->ToBoolean(obj->BooleanValue());
+  return ToApiHandle<Boolean>(val);
 }
 
 
 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 = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToBoolean");
-    ENTER_V8(isolate);
-    i::Handle<i::Object> val =
-        isolate->factory()->ToBoolean(obj->BooleanValue());
-    return ToApiHandle<Boolean>(val);
-  }
+  return ToBoolean(v8_isolate->GetCurrentContext()).ToLocalChecked();
 }
 
 
-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 = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToNumber");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToNumber(
-        isolate, obj).ToHandle(&num);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<Number>());
-  }
-  return ToApiHandle<Number>(num);
+MaybeLocal<Number> Value::ToNumber(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsNumber()) return ToApiHandle<Number>(obj);
+  PREPARE_FOR_EXECUTION(context, "ToNumber", Number);
+  Local<Number> result;
+  has_pending_exception =
+      !ToLocal<Number>(i::Execution::ToNumber(isolate, obj), &result);
+  RETURN_ON_FAILED_EXECUTION(Number);
+  RETURN_ESCAPED(result);
 }
 
 
-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 = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToInteger");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToInteger(
-        isolate, obj).ToHandle(&num);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<Integer>());
-  }
-  return ToApiHandle<Integer>(num);
+Local<Number> Value::ToNumber(Isolate* isolate) const {
+  RETURN_TO_LOCAL_UNCHECKED(ToNumber(isolate->GetCurrentContext()), Number);
+}
+
+
+MaybeLocal<Integer> Value::ToInteger(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) return ToApiHandle<Integer>(obj);
+  PREPARE_FOR_EXECUTION(context, "ToInteger", Integer);
+  Local<Integer> result;
+  has_pending_exception =
+      !ToLocal<Integer>(i::Execution::ToInteger(isolate, obj), &result);
+  RETURN_ON_FAILED_EXECUTION(Integer);
+  RETURN_ESCAPED(result);
+}
+
+
+Local<Integer> Value::ToInteger(Isolate* isolate) const {
+  RETURN_TO_LOCAL_UNCHECKED(ToInteger(isolate->GetCurrentContext()), Integer);
+}
+
+
+MaybeLocal<Int32> Value::ToInt32(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) return ToApiHandle<Int32>(obj);
+  Local<Int32> result;
+  PREPARE_FOR_EXECUTION(context, "ToInt32", Int32);
+  has_pending_exception =
+      !ToLocal<Int32>(i::Execution::ToInt32(isolate, obj), &result);
+  RETURN_ON_FAILED_EXECUTION(Int32);
+  RETURN_ESCAPED(result);
+}
+
+
+Local<Int32> Value::ToInt32(Isolate* isolate) const {
+  RETURN_TO_LOCAL_UNCHECKED(ToInt32(isolate->GetCurrentContext()), Int32);
+}
+
+
+MaybeLocal<Uint32> Value::ToUint32(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) return ToApiHandle<Uint32>(obj);
+  Local<Uint32> result;
+  PREPARE_FOR_EXECUTION(context, "ToUInt32", Uint32);
+  has_pending_exception =
+      !ToLocal<Uint32>(i::Execution::ToUint32(isolate, obj), &result);
+  RETURN_ON_FAILED_EXECUTION(Uint32);
+  RETURN_ESCAPED(result);
+}
+
+
+Local<Uint32> Value::ToUint32(Isolate* isolate) const {
+  RETURN_TO_LOCAL_UNCHECKED(ToUint32(isolate->GetCurrentContext()), Uint32);
 }
 
 
@@ -2785,6 +2997,14 @@ void v8::Function::CheckCast(Value* that) {
 }
 
 
+void v8::Boolean::CheckCast(v8::Value* that) {
+  i::Handle<i::Object> obj = Utils::OpenHandle(that);
+  Utils::ApiCheck(obj->IsBoolean(),
+                  "v8::Boolean::Cast()",
+                  "Could not convert to boolean");
+}
+
+
 void v8::Name::CheckCast(v8::Value* that) {
   i::Handle<i::Object> obj = Utils::OpenHandle(that);
   Utils::ApiCheck(obj->IsName(),
@@ -2825,6 +3045,18 @@ void v8::Integer::CheckCast(v8::Value* that) {
 }
 
 
+void v8::Int32::CheckCast(v8::Value* that) {
+  Utils::ApiCheck(that->IsInt32(), "v8::Int32::Cast()",
+                  "Could not convert to 32-bit signed integer");
+}
+
+
+void v8::Uint32::CheckCast(v8::Value* that) {
+  Utils::ApiCheck(that->IsUint32(), "v8::Uint32::Cast()",
+                  "Could not convert to 32-bit unsigned integer");
+}
+
+
 void v8::Array::CheckCast(Value* that) {
   i::Handle<i::Object> obj = Utils::OpenHandle(that);
   Utils::ApiCheck(obj->IsJSArray(),
@@ -2958,100 +3190,113 @@ void v8::RegExp::CheckCast(v8::Value* that) {
 }
 
 
+Maybe<bool> Value::BooleanValue(Local<Context> context) const {
+  return Just(Utils::OpenHandle(this)->BooleanValue());
+}
+
+
 bool Value::BooleanValue() const {
   return Utils::OpenHandle(this)->BooleanValue();
 }
 
 
+Maybe<double> Value::NumberValue(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsNumber()) return Just(obj->Number());
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "NumberValue", double);
+  i::Handle<i::Object> num;
+  has_pending_exception = !i::Execution::ToNumber(isolate, obj).ToHandle(&num);
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(double);
+  return Just(num->Number());
+}
+
+
 double Value::NumberValue() const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsNumber()) return obj->Number();
+  return NumberValue(ContextFromHeapObject(obj))
+      .FromMaybe(std::numeric_limits<double>::quiet_NaN());
+}
+
+
+Maybe<int64_t> Value::IntegerValue(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
   i::Handle<i::Object> num;
   if (obj->IsNumber()) {
     num = obj;
   } else {
-    i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate();
-    LOG_API(isolate, "NumberValue");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToNumber(
-        isolate, obj).ToHandle(&num);
-    EXCEPTION_BAILOUT_CHECK(isolate, std::numeric_limits<double>::quiet_NaN());
+    PREPARE_FOR_EXECUTION_PRIMITIVE(context, "IntegerValue", int64_t);
+    has_pending_exception =
+        !i::Execution::ToInteger(isolate, obj).ToHandle(&num);
+    RETURN_ON_FAILED_EXECUTION_PRIMITIVE(int64_t);
   }
-  return num->Number();
+  return Just(num->IsSmi() ? static_cast<int64_t>(i::Smi::cast(*num)->value())
+                           : static_cast<int64_t>(num->Number()));
 }
 
 
 int64_t Value::IntegerValue() const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  i::Handle<i::Object> num;
+  auto obj = Utils::OpenHandle(this);
   if (obj->IsNumber()) {
-    num = obj;
-  } else {
-    i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate();
-    LOG_API(isolate, "IntegerValue");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToInteger(
-        isolate, obj).ToHandle(&num);
-    EXCEPTION_BAILOUT_CHECK(isolate, 0);
-  }
-  if (num->IsSmi()) {
-    return i::Smi::cast(*num)->value();
-  } else {
-    return static_cast<int64_t>(num->Number());
+    if (obj->IsSmi()) {
+      return i::Smi::cast(*obj)->value();
+    } else {
+      return static_cast<int64_t>(obj->Number());
+    }
   }
+  return IntegerValue(ContextFromHeapObject(obj)).FromMaybe(0);
 }
 
 
-Local<Int32> Value::ToInt32(Isolate* v8_isolate) const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+Maybe<int32_t> Value::Int32Value(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsNumber()) return Just(NumberToInt32(*obj));
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Int32Value", int32_t);
   i::Handle<i::Object> num;
-  if (obj->IsSmi()) {
-    num = obj;
-  } else {
-    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToInt32");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToInt32(isolate, obj).ToHandle(&num);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<Int32>());
-  }
-  return ToApiHandle<Int32>(num);
+  has_pending_exception = !i::Execution::ToInt32(isolate, obj).ToHandle(&num);
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(int32_t);
+  return Just(num->IsSmi() ? i::Smi::cast(*num)->value()
+                           : static_cast<int32_t>(num->Number()));
 }
 
 
-Local<Uint32> Value::ToUint32(Isolate* v8_isolate) const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+int32_t Value::Int32Value() const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsNumber()) return NumberToInt32(*obj);
+  return Int32Value(ContextFromHeapObject(obj)).FromMaybe(0);
+}
+
+
+Maybe<uint32_t> Value::Uint32Value(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsNumber()) return Just(NumberToUint32(*obj));
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Uint32Value", uint32_t);
   i::Handle<i::Object> num;
-  if (obj->IsSmi()) {
-    num = obj;
-  } else {
-    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToUInt32");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToUint32(
-        isolate, obj).ToHandle(&num);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<Uint32>());
-  }
-  return ToApiHandle<Uint32>(num);
+  has_pending_exception = !i::Execution::ToUint32(isolate, obj).ToHandle(&num);
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(uint32_t);
+  return Just(num->IsSmi() ? static_cast<uint32_t>(i::Smi::cast(*num)->value())
+                           : static_cast<uint32_t>(num->Number()));
 }
 
 
-Local<Uint32> Value::ToArrayIndex() const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  if (obj->IsSmi()) {
-    if (i::Smi::cast(*obj)->value() >= 0) return Utils::Uint32ToLocal(obj);
+uint32_t Value::Uint32Value() const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsNumber()) return NumberToUint32(*obj);
+  return Uint32Value(ContextFromHeapObject(obj)).FromMaybe(0);
+}
+
+
+MaybeLocal<Uint32> Value::ToArrayIndex(Local<Context> context) const {
+  auto self = Utils::OpenHandle(this);
+  if (self->IsSmi()) {
+    if (i::Smi::cast(*self)->value() >= 0) return Utils::Uint32ToLocal(self);
     return Local<Uint32>();
   }
-  i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate();
-  LOG_API(isolate, "ToArrayIndex");
-  ENTER_V8(isolate);
-  EXCEPTION_PREAMBLE(isolate);
+  PREPARE_FOR_EXECUTION(context, "ToArrayIndex", Uint32);
   i::Handle<i::Object> string_obj;
-  has_pending_exception = !i::Execution::ToString(
-      isolate, obj).ToHandle(&string_obj);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<Uint32>());
+  has_pending_exception =
+      !i::Execution::ToString(isolate, self).ToHandle(&string_obj);
+  RETURN_ON_FAILED_EXECUTION(Uint32);
   i::Handle<i::String> str = i::Handle<i::String>::cast(string_obj);
   uint32_t index;
   if (str->AsArrayIndex(&index)) {
@@ -3061,77 +3306,65 @@ Local<Uint32> Value::ToArrayIndex() const {
     } else {
       value = isolate->factory()->NewNumber(index);
     }
-    return Utils::Uint32ToLocal(value);
+    RETURN_ESCAPED(Utils::Uint32ToLocal(value));
   }
   return Local<Uint32>();
 }
 
 
-int32_t Value::Int32Value() const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  if (obj->IsNumber()) {
-    return NumberToInt32(*obj);
-  } else {
-    i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate();
-    LOG_API(isolate, "Int32Value (slow)");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    i::Handle<i::Object> num;
-    has_pending_exception = !i::Execution::ToInt32(isolate, obj).ToHandle(&num);
-    EXCEPTION_BAILOUT_CHECK(isolate, 0);
-    if (num->IsSmi()) {
-      return i::Smi::cast(*num)->value();
-    } else {
-      return static_cast<int32_t>(num->Number());
-    }
+Local<Uint32> Value::ToArrayIndex() const {
+  auto self = Utils::OpenHandle(this);
+  if (self->IsSmi()) {
+    if (i::Smi::cast(*self)->value() >= 0) return Utils::Uint32ToLocal(self);
+    return Local<Uint32>();
   }
+  auto context = ContextFromHeapObject(self);
+  RETURN_TO_LOCAL_UNCHECKED(ToArrayIndex(context), Uint32);
 }
 
 
-bool Value::Equals(Handle<Value> that) const {
-  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();
+Maybe<bool> Value::Equals(Local<Context> context, Handle<Value> that) const {
+  auto self = Utils::OpenHandle(this);
+  auto other = Utils::OpenHandle(*that);
+  if (self->IsSmi() && other->IsSmi()) {
+    return Just(self->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")) {
-    return false;
-  }
-  LOG_API(isolate, "Equals");
-  ENTER_V8(isolate);
-  // 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.
-  if (obj->IsJSObject() && other->IsJSObject()) {
-    return *obj == *other;
+  if (self->IsJSObject() && other->IsJSObject()) {
+    return Just(*self == *other);
   }
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Value::Equals()", bool);
   i::Handle<i::Object> args[] = { other };
-  EXCEPTION_PREAMBLE(isolate);
   i::Handle<i::Object> result;
   has_pending_exception =
-      !CallV8HeapFunction(isolate, "EQUALS", obj, arraysize(args), args)
+      !CallV8HeapFunction(isolate, "EQUALS", self, arraysize(args), args)
            .ToHandle(&result);
-  EXCEPTION_BAILOUT_CHECK(isolate, false);
-  return *result == i::Smi::FromInt(i::EQUAL);
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return Just(*result == i::Smi::FromInt(i::EQUAL));
+}
+
+
+bool Value::Equals(Handle<Value> that) const {
+  auto self = Utils::OpenHandle(this);
+  auto other = Utils::OpenHandle(*that);
+  if (self->IsSmi() && other->IsSmi()) {
+    return self->Number() == other->Number();
+  }
+  if (self->IsJSObject() && other->IsJSObject()) {
+    return *self == *other;
+  }
+  auto heap_object = self->IsSmi() ? other : self;
+  auto context = ContextFromHeapObject(heap_object);
+  return Equals(context, that).FromMaybe(false);
 }
 
 
 bool Value::StrictEquals(Handle<Value> that) const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this, true);
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
   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");
   // Must check HeapNumber first, since NaN !== NaN.
   if (obj->IsHeapNumber()) {
@@ -3157,89 +3390,71 @@ bool Value::StrictEquals(Handle<Value> that) const {
 
 
 bool Value::SameValue(Handle<Value> that) const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this, true);
-  if (!Utils::ApiCheck(!obj.is_null() && !that.IsEmpty(),
-                       "v8::Value::SameValue()",
-                       "Reading from empty handle")) {
-    return false;
-  }
-  i::Handle<i::Object> other = Utils::OpenHandle(*that);
-  return obj->SameValue(*other);
+  auto self = Utils::OpenHandle(this);
+  auto other = Utils::OpenHandle(*that);
+  return self->SameValue(*other);
 }
 
 
-uint32_t Value::Uint32Value() const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  if (obj->IsNumber()) {
-    return NumberToUint32(*obj);
-  } else {
-    i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate();
-    LOG_API(isolate, "Uint32Value");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    i::Handle<i::Object> num;
-    has_pending_exception = !i::Execution::ToUint32(
-        isolate, obj).ToHandle(&num);
-    EXCEPTION_BAILOUT_CHECK(isolate, 0);
-    if (num->IsSmi()) {
-      return i::Smi::cast(*num)->value();
-    } else {
-      return static_cast<uint32_t>(num->Number());
-    }
-  }
+Maybe<bool> v8::Object::Set(v8::Local<v8::Context> context,
+                            v8::Local<Value> key, v8::Local<Value> value) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::Set()", bool);
+  auto self = Utils::OpenHandle(this);
+  auto key_obj = Utils::OpenHandle(*key);
+  auto value_obj = Utils::OpenHandle(*value);
+  has_pending_exception =
+      i::Runtime::SetObjectProperty(isolate, self, key_obj, value_obj,
+                                    i::SLOPPY).is_null();
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return Just(true);
 }
 
 
 bool v8::Object::Set(v8::Handle<Value> key, v8::Handle<Value> value) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::Set()", return false);
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::Object> self = Utils::OpenHandle(this);
-  i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
-  i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
-  EXCEPTION_PREAMBLE(isolate);
-  has_pending_exception =
-      i::Runtime::SetObjectProperty(isolate, self, key_obj, value_obj,
-                                    i::SLOPPY).is_null();
-  EXCEPTION_BAILOUT_CHECK(isolate, false);
-  return true;
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return Set(context, key, value).FromMaybe(false);
 }
 
 
-bool v8::Object::Set(uint32_t index, v8::Handle<Value> value) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::Set()", return false);
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
-  EXCEPTION_PREAMBLE(isolate);
+Maybe<bool> v8::Object::Set(v8::Local<v8::Context> context, uint32_t index,
+                            v8::Local<Value> value) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::Set()", bool);
+  auto self = Utils::OpenHandle(this);
+  auto value_obj = Utils::OpenHandle(*value);
   has_pending_exception = i::JSObject::SetElement(
       self, index, value_obj, NONE, i::SLOPPY).is_null();
-  EXCEPTION_BAILOUT_CHECK(isolate, false);
-  return true;
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return Just(true);
 }
 
 
-bool v8::Object::ForceSet(v8::Handle<Value> key,
-                          v8::Handle<Value> value,
-                          v8::PropertyAttribute attribs) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::ForceSet()", return false);
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
-  i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
-  EXCEPTION_PREAMBLE(isolate);
+bool v8::Object::Set(uint32_t index, v8::Handle<Value> value) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return Set(context, index, value).FromMaybe(false);
+}
+
+
+Maybe<bool> v8::Object::ForceSet(v8::Local<v8::Context> context,
+                                 v8::Local<Value> key, v8::Local<Value> value,
+                                 v8::PropertyAttribute attribs) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::Set()", bool);
+  auto self = Utils::OpenHandle(this);
+  auto key_obj = Utils::OpenHandle(*key);
+  auto value_obj = Utils::OpenHandle(*value);
   has_pending_exception = i::Runtime::DefineObjectProperty(
       self,
       key_obj,
       value_obj,
       static_cast<PropertyAttributes>(attribs)).is_null();
-  EXCEPTION_BAILOUT_CHECK(isolate, false);
-  return true;
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return Just(true);
+}
+
+
+bool v8::Object::ForceSet(v8::Handle<Value> key, v8::Handle<Value> value,
+                          v8::PropertyAttribute attribs) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return ForceSet(context, key, value, attribs).FromMaybe(false);
 }
 
 
@@ -3249,6 +3464,8 @@ bool v8::Object::SetPrivate(v8::Handle<Private> key, v8::Handle<Value> value) {
 }
 
 
+namespace {
+
 i::MaybeHandle<i::Object> DeleteObjectProperty(
     i::Isolate* isolate, i::Handle<i::JSReceiver> receiver,
     i::Handle<i::Object> key, i::LanguageMode language_mode) {
@@ -3286,33 +3503,42 @@ i::MaybeHandle<i::Object> DeleteObjectProperty(
   return i::JSReceiver::DeleteProperty(receiver, name, language_mode);
 }
 
+}  // namespace
 
-Local<Value> v8::Object::Get(v8::Handle<Value> key) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::Get()", return Local<v8::Value>());
-  ENTER_V8(isolate);
-  i::Handle<i::Object> self = Utils::OpenHandle(this);
-  i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
-  EXCEPTION_PREAMBLE(isolate);
+
+MaybeLocal<Value> v8::Object::Get(Local<v8::Context> context,
+                                  Local<Value> key) {
+  PREPARE_FOR_EXECUTION(context, "v8::Object::Get()", Value);
+  auto self = Utils::OpenHandle(this);
+  auto key_obj = Utils::OpenHandle(*key);
   i::Handle<i::Object> result;
   has_pending_exception =
       !i::Runtime::GetObjectProperty(isolate, self, key_obj).ToHandle(&result);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
-  return Utils::ToLocal(result);
+  RETURN_ON_FAILED_EXECUTION(Value);
+  RETURN_ESCAPED(Utils::ToLocal(result));
 }
 
 
-Local<Value> v8::Object::Get(uint32_t index) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::Get()", return Local<v8::Value>());
-  ENTER_V8(isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  EXCEPTION_PREAMBLE(isolate);
+Local<Value> v8::Object::Get(v8::Handle<Value> key) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(Get(context, key), Value);
+}
+
+
+MaybeLocal<Value> v8::Object::Get(Local<Context> context, uint32_t index) {
+  PREPARE_FOR_EXECUTION(context, "v8::Object::Get()", Value);
+  auto self = Utils::OpenHandle(this);
   i::Handle<i::Object> result;
   has_pending_exception =
       !i::Object::GetElement(isolate, self, index).ToHandle(&result);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
-  return Utils::ToLocal(result);
+  RETURN_ON_FAILED_EXECUTION(Value);
+  RETURN_ESCAPED(Utils::ToLocal(result));
+}
+
+
+Local<Value> v8::Object::Get(uint32_t index) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(Get(context, index), Value);
 }
 
 
@@ -3321,88 +3547,93 @@ Local<Value> v8::Object::GetPrivate(v8::Handle<Private> key) {
 }
 
 
-PropertyAttribute v8::Object::GetPropertyAttributes(v8::Handle<Value> key) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::GetPropertyAttributes()",
-             return static_cast<PropertyAttribute>(NONE));
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
+Maybe<PropertyAttribute> v8::Object::GetPropertyAttributes(
+    Local<Context> context, Local<Value> key) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(
+      context, "v8::Object::GetPropertyAttributes()", PropertyAttribute);
+  auto self = Utils::OpenHandle(this);
+  auto key_obj = Utils::OpenHandle(*key);
   if (!key_obj->IsName()) {
-    EXCEPTION_PREAMBLE(isolate);
     has_pending_exception = !i::Execution::ToString(
         isolate, key_obj).ToHandle(&key_obj);
-    EXCEPTION_BAILOUT_CHECK(isolate, static_cast<PropertyAttribute>(NONE));
+    RETURN_ON_FAILED_EXECUTION_PRIMITIVE(PropertyAttribute);
   }
-  i::Handle<i::Name> key_name = i::Handle<i::Name>::cast(key_obj);
-  EXCEPTION_PREAMBLE(isolate);
-  Maybe<PropertyAttributes> result =
-      i::JSReceiver::GetPropertyAttributes(self, key_name);
-  has_pending_exception = !result.has_value;
-  EXCEPTION_BAILOUT_CHECK(isolate, static_cast<PropertyAttribute>(NONE));
-  if (result.value == ABSENT) return static_cast<PropertyAttribute>(NONE);
-  return static_cast<PropertyAttribute>(result.value);
+  auto key_name = i::Handle<i::Name>::cast(key_obj);
+  auto result = i::JSReceiver::GetPropertyAttributes(self, key_name);
+  has_pending_exception = result.IsNothing();
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(PropertyAttribute);
+  if (result.FromJust() == ABSENT) {
+    return Just(static_cast<PropertyAttribute>(NONE));
+  }
+  return Just(static_cast<PropertyAttribute>(result.FromJust()));
 }
 
 
-Local<Value> v8::Object::GetOwnPropertyDescriptor(Local<String> key) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::GetOwnPropertyDescriptor()",
-             return Local<Value>());
-  ENTER_V8(isolate);
-  i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
-  i::Handle<i::Name> key_name = Utils::OpenHandle(*key);
+PropertyAttribute v8::Object::GetPropertyAttributes(v8::Handle<Value> key) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return GetPropertyAttributes(context, key)
+      .FromMaybe(static_cast<PropertyAttribute>(NONE));
+}
+
+
+MaybeLocal<Value> v8::Object::GetOwnPropertyDescriptor(Local<Context> context,
+                                                       Local<String> key) {
+  PREPARE_FOR_EXECUTION(context, "v8::Object::GetOwnPropertyDescriptor()",
+                        Value);
+  auto obj = Utils::OpenHandle(this);
+  auto key_name = Utils::OpenHandle(*key);
   i::Handle<i::Object> args[] = { obj, key_name };
-  EXCEPTION_PREAMBLE(isolate);
   i::Handle<i::Object> 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);
+  RETURN_ON_FAILED_EXECUTION(Value);
+  RETURN_ESCAPED(Utils::ToLocal(result));
+}
+
+
+Local<Value> v8::Object::GetOwnPropertyDescriptor(Local<String> key) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(GetOwnPropertyDescriptor(context, key), Value);
 }
 
 
 Local<Value> v8::Object::GetPrototype() {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::GetPrototype()", return Local<v8::Value>());
-  ENTER_V8(isolate);
-  i::Handle<i::Object> self = Utils::OpenHandle(this);
+  auto isolate = Utils::OpenHandle(this)->GetIsolate();
+  auto self = Utils::OpenHandle(this);
   i::PrototypeIterator iter(isolate, self);
   return Utils::ToLocal(i::PrototypeIterator::GetCurrent(iter));
 }
 
 
-bool v8::Object::SetPrototype(Handle<Value> value) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::SetPrototype()", return false);
-  ENTER_V8(isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
+Maybe<bool> v8::Object::SetPrototype(Local<Context> context,
+                                     Local<Value> value) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::SetPrototype()", bool);
+  auto self = Utils::OpenHandle(this);
+  auto value_obj = Utils::OpenHandle(*value);
   // We do not allow exceptions thrown while setting the prototype
   // to propagate outside.
-  TryCatch try_catch;
-  EXCEPTION_PREAMBLE(isolate);
-  i::MaybeHandle<i::Object> result =
-      i::JSObject::SetPrototype(self, value_obj, false);
+  TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
+  auto result = i::JSObject::SetPrototype(self, value_obj, false);
   has_pending_exception = result.is_null();
-  EXCEPTION_BAILOUT_CHECK(isolate, false);
-  return true;
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return Just(true);
+}
+
+
+bool v8::Object::SetPrototype(Handle<Value> value) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return SetPrototype(context, value).FromMaybe(false);
 }
 
 
 Local<Object> v8::Object::FindInstanceInPrototypeChain(
     v8::Handle<FunctionTemplate> tmpl) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate,
-             "v8::Object::FindInstanceInPrototypeChain()",
-             return Local<v8::Object>());
-  ENTER_V8(isolate);
+  auto isolate = Utils::OpenHandle(this)->GetIsolate();
   i::PrototypeIterator iter(isolate, *Utils::OpenHandle(this),
                             i::PrototypeIterator::START_AT_RECEIVER);
-  i::FunctionTemplateInfo* tmpl_info = *Utils::OpenHandle(*tmpl);
+  auto tmpl_info = *Utils::OpenHandle(*tmpl);
   while (!tmpl_info->IsTemplateFor(iter.GetCurrent())) {
     iter.Advance();
     if (iter.IsAtEnd()) {
@@ -3414,59 +3645,55 @@ Local<Object> v8::Object::FindInstanceInPrototypeChain(
 }
 
 
-Local<Array> v8::Object::GetPropertyNames() {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::GetPropertyNames()",
-             return Local<v8::Array>());
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  EXCEPTION_PREAMBLE(isolate);
+MaybeLocal<Array> v8::Object::GetPropertyNames(Local<Context> context) {
+  PREPARE_FOR_EXECUTION(context, "v8::Object::GetPropertyNames()", Array);
+  auto self = Utils::OpenHandle(this);
   i::Handle<i::FixedArray> value;
   has_pending_exception = !i::JSReceiver::GetKeys(
       self, i::JSReceiver::INCLUDE_PROTOS).ToHandle(&value);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Array>());
+  RETURN_ON_FAILED_EXECUTION(Array);
   // Because we use caching to speed up enumeration it is important
   // to never change the result of the basic enumeration function so
   // we clone the result.
-  i::Handle<i::FixedArray> elms = isolate->factory()->CopyFixedArray(value);
-  i::Handle<i::JSArray> result =
-      isolate->factory()->NewJSArrayWithElements(elms);
-  return Utils::ToLocal(scope.CloseAndEscape(result));
+  auto elms = isolate->factory()->CopyFixedArray(value);
+  auto result = isolate->factory()->NewJSArrayWithElements(elms);
+  RETURN_ESCAPED(Utils::ToLocal(result));
 }
 
 
-Local<Array> v8::Object::GetOwnPropertyNames() {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::GetOwnPropertyNames()",
-             return Local<v8::Array>());
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  EXCEPTION_PREAMBLE(isolate);
+Local<Array> v8::Object::GetPropertyNames() {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(GetPropertyNames(context), Array);
+}
+
+
+MaybeLocal<Array> v8::Object::GetOwnPropertyNames(Local<Context> context) {
+  PREPARE_FOR_EXECUTION(context, "v8::Object::GetOwnPropertyNames()", Array);
+  auto self = Utils::OpenHandle(this);
   i::Handle<i::FixedArray> value;
   has_pending_exception = !i::JSReceiver::GetKeys(
       self, i::JSReceiver::OWN_ONLY).ToHandle(&value);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Array>());
+  RETURN_ON_FAILED_EXECUTION(Array);
   // Because we use caching to speed up enumeration it is important
   // to never change the result of the basic enumeration function so
   // we clone the result.
-  i::Handle<i::FixedArray> elms = isolate->factory()->CopyFixedArray(value);
-  i::Handle<i::JSArray> result =
-      isolate->factory()->NewJSArrayWithElements(elms);
-  return Utils::ToLocal(scope.CloseAndEscape(result));
+  auto elms = isolate->factory()->CopyFixedArray(value);
+  auto result = isolate->factory()->NewJSArrayWithElements(elms);
+  RETURN_ESCAPED(Utils::ToLocal(result));
 }
 
 
-Local<String> v8::Object::ObjectProtoToString() {
-  i::Isolate* i_isolate = Utils::OpenHandle(this)->GetIsolate();
-  Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
-  ON_BAILOUT(i_isolate, "v8::Object::ObjectProtoToString()",
-             return Local<v8::String>());
-  ENTER_V8(i_isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+Local<Array> v8::Object::GetOwnPropertyNames() {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(GetOwnPropertyNames(context), Array);
+}
+
 
-  i::Handle<i::Object> name(self->class_name(), i_isolate);
+MaybeLocal<String> v8::Object::ObjectProtoToString(Local<Context> context) {
+  auto self = Utils::OpenHandle(this);
+  auto isolate = self->GetIsolate();
+  auto v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
+  i::Handle<i::Object> name(self->class_name(), isolate);
   i::Handle<i::Object> tag;
 
   // Native implementation of Object.prototype.toString (v8natives.js):
@@ -3475,82 +3702,79 @@ Local<String> v8::Object::ObjectProtoToString() {
   //   return "[object " + c + "]";
 
   if (!name->IsString()) {
-    return v8::String::NewFromUtf8(isolate, "[object ]");
-  } else {
-    i::Handle<i::String> class_name = i::Handle<i::String>::cast(name);
-    if (i::String::Equals(class_name,
-                          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->IsString()) {
-          class_name = i::Handle<i::String>::cast(tag);
-        }
-      }
-      const char* prefix = "[object ";
-      Local<String> str = Utils::ToLocal(class_name);
-      const char* postfix = "]";
+    return v8::String::NewFromUtf8(v8_isolate, "[object ]");
+  }
+  auto class_name = i::Handle<i::String>::cast(name);
+  if (i::String::Equals(class_name, isolate->factory()->Arguments_string())) {
+    return v8::String::NewFromUtf8(v8_isolate, "[object Object]");
+  }
+  if (internal::FLAG_harmony_tostring) {
+    PREPARE_FOR_EXECUTION(context, "v8::Object::ObjectProtoToString()", String);
+    auto toStringTag = isolate->factory()->to_string_tag_symbol();
+    has_pending_exception = !i::Runtime::GetObjectProperty(
+                                 isolate, self, toStringTag).ToHandle(&tag);
+    RETURN_ON_FAILED_EXECUTION(String);
+    if (tag->IsString()) {
+      class_name = i::Handle<i::String>::cast(tag).EscapeFrom(&handle_scope);
+    }
+  }
+  const char* prefix = "[object ";
+  Local<String> str = Utils::ToLocal(class_name);
+  const char* postfix = "]";
 
-      int prefix_len = i::StrLength(prefix);
-      int str_len = str->Utf8Length();
-      int postfix_len = i::StrLength(postfix);
+  int prefix_len = i::StrLength(prefix);
+  int str_len = str->Utf8Length();
+  int postfix_len = i::StrLength(postfix);
 
-      int buf_len = prefix_len + str_len + postfix_len;
-      i::ScopedVector<char> buf(buf_len);
+  int buf_len = prefix_len + str_len + postfix_len;
+  i::ScopedVector<char> buf(buf_len);
 
-      // Write prefix.
-      char* ptr = buf.start();
-      i::MemCopy(ptr, prefix, prefix_len * v8::internal::kCharSize);
-      ptr += prefix_len;
+  // Write prefix.
+  char* ptr = buf.start();
+  i::MemCopy(ptr, prefix, prefix_len * v8::internal::kCharSize);
+  ptr += prefix_len;
 
-      // Write real content.
-      str->WriteUtf8(ptr, str_len);
-      ptr += str_len;
+  // Write real content.
+  str->WriteUtf8(ptr, str_len);
+  ptr += str_len;
 
-      // Write postfix.
-      i::MemCopy(ptr, postfix, postfix_len * v8::internal::kCharSize);
+  // Write postfix.
+  i::MemCopy(ptr, postfix, postfix_len * v8::internal::kCharSize);
 
-      // Copy the buffer into a heap-allocated string and return it.
-      Local<String> result = v8::String::NewFromUtf8(
-          isolate, buf.start(), String::kNormalString, buf_len);
-      return result;
-    }
-  }
+  // Copy the buffer into a heap-allocated string and return it.
+  return v8::String::NewFromUtf8(v8_isolate, buf.start(), String::kNormalString,
+                                 buf_len);
+}
+
+
+Local<String> v8::Object::ObjectProtoToString() {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(ObjectProtoToString(context), String);
 }
 
 
 Local<String> v8::Object::GetConstructorName() {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::GetConstructorName()",
-             return Local<v8::String>());
-  ENTER_V8(isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  auto self = Utils::OpenHandle(this);
   i::Handle<i::String> name(self->constructor_name());
   return Utils::ToLocal(name);
 }
 
 
-bool v8::Object::Delete(v8::Handle<Value> key) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::Delete()", return false);
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
-  EXCEPTION_PREAMBLE(isolate);
+Maybe<bool> v8::Object::Delete(Local<Context> context, Local<Value> key) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::Delete()", bool);
+  auto self = Utils::OpenHandle(this);
+  auto key_obj = Utils::OpenHandle(*key);
   i::Handle<i::Object> obj;
   has_pending_exception =
       !DeleteObjectProperty(isolate, self, key_obj, i::SLOPPY).ToHandle(&obj);
-  EXCEPTION_BAILOUT_CHECK(isolate, false);
-  return obj->IsTrue();
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return Just(obj->IsTrue());
+}
+
+
+bool v8::Object::Delete(v8::Handle<Value> key) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return Delete(context, key).FromMaybe(false);
 }
 
 
@@ -3559,14 +3783,11 @@ bool v8::Object::DeletePrivate(v8::Handle<Private> key) {
 }
 
 
-bool v8::Object::Has(v8::Handle<Value> key) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::Has()", return false);
-  ENTER_V8(isolate);
-  i::Handle<i::JSReceiver> self = Utils::OpenHandle(this);
-  i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
-  EXCEPTION_PREAMBLE(isolate);
-  Maybe<bool> maybe;
+Maybe<bool> v8::Object::Has(Local<Context> context, Local<Value> key) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::Get()", bool);
+  auto self = Utils::OpenHandle(this);
+  auto key_obj = Utils::OpenHandle(*key);
+  Maybe<bool> maybe = Nothing<bool>();
   // Check if the given key is an array index.
   uint32_t index;
   if (key_obj->ToArrayIndex(&index)) {
@@ -3578,10 +3799,15 @@ bool v8::Object::Has(v8::Handle<Value> key) {
       maybe = i::JSReceiver::HasProperty(self, name);
     }
   }
-  if (!maybe.has_value) has_pending_exception = true;
-  EXCEPTION_BAILOUT_CHECK(isolate, false);
-  DCHECK(maybe.has_value);
-  return maybe.value;
+  has_pending_exception = maybe.IsNothing();
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return maybe;
+}
+
+
+bool v8::Object::Has(v8::Handle<Value> key) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return Has(context, key).FromMaybe(false);
 }
 
 
@@ -3592,62 +3818,71 @@ bool v8::Object::HasPrivate(v8::Handle<Private> key) {
 }
 
 
-bool v8::Object::Delete(uint32_t index) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::DeleteProperty()",
-             return false);
-  ENTER_V8(isolate);
-  HandleScope scope(reinterpret_cast<Isolate*>(isolate));
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-
-  EXCEPTION_PREAMBLE(isolate);
+Maybe<bool> v8::Object::Delete(Local<Context> context, uint32_t index) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::DeleteProperty()",
+                                  bool);
+  auto self = Utils::OpenHandle(this);
   i::Handle<i::Object> obj;
   has_pending_exception =
       !i::JSReceiver::DeleteElement(self, index).ToHandle(&obj);
-  EXCEPTION_BAILOUT_CHECK(isolate, false);
-  return obj->IsTrue();
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return Just(obj->IsTrue());
+}
+
+
+bool v8::Object::Delete(uint32_t index) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return Delete(context, index).FromMaybe(false);
+}
+
+
+Maybe<bool> v8::Object::Has(Local<Context> context, uint32_t index) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::Get()", bool);
+  auto self = Utils::OpenHandle(this);
+  auto maybe = i::JSReceiver::HasElement(self, index);
+  has_pending_exception = maybe.IsNothing();
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return maybe;
 }
 
 
 bool v8::Object::Has(uint32_t index) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::HasProperty()", return false);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  EXCEPTION_PREAMBLE(isolate);
-  Maybe<bool> maybe = i::JSReceiver::HasElement(self, index);
-  has_pending_exception = !maybe.has_value;
-  EXCEPTION_BAILOUT_CHECK(isolate, false);
-  return maybe.value;
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return Has(context, index).FromMaybe(false);
 }
 
 
-template<typename Getter, typename Setter, typename Data>
-static inline bool ObjectSetAccessor(Object* obj,
-                                     Handle<Name> name,
-                                     Getter getter,
-                                     Setter setter,
-                                     Data data,
+template <typename Getter, typename Setter, typename Data>
+static Maybe<bool> ObjectSetAccessor(Local<Context> context, Object* obj,
+                                     Local<Name> name, Getter getter,
+                                     Setter setter, Data data,
                                      AccessControl settings,
                                      PropertyAttribute attributes) {
-  i::Isolate* isolate = Utils::OpenHandle(obj)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::SetAccessor()", return false);
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::SetAccessor()", bool);
   v8::Handle<AccessorSignature> signature;
-  i::Handle<i::AccessorInfo> info = MakeAccessorInfo(
-      name, getter, setter, data, settings, attributes, signature);
-  if (info.is_null()) return false;
+  auto info = MakeAccessorInfo(name, getter, setter, data, settings, attributes,
+                               signature);
+  if (info.is_null()) return Nothing<bool>();
   bool fast = Utils::OpenHandle(obj)->HasFastProperties();
   i::Handle<i::Object> result;
-  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-      isolate, result,
-      i::JSObject::SetAccessor(Utils::OpenHandle(obj), info),
-      false);
-  if (result->IsUndefined()) return false;
+  has_pending_exception =
+      !i::JSObject::SetAccessor(Utils::OpenHandle(obj), info).ToHandle(&result);
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  if (result->IsUndefined()) return Nothing<bool>();
   if (fast) {
     i::JSObject::MigrateSlowToFast(Utils::OpenHandle(obj), 0, "APISetAccessor");
   }
-  return true;
+  return Just(true);
+}
+
+
+Maybe<bool> Object::SetAccessor(Local<Context> context, Local<Name> name,
+                                AccessorNameGetterCallback getter,
+                                AccessorNameSetterCallback setter,
+                                MaybeLocal<Value> data, AccessControl settings,
+                                PropertyAttribute attribute) {
+  return ObjectSetAccessor(context, this, name, getter, setter,
+                           data.FromMaybe(Local<Value>()), settings, attribute);
 }
 
 
@@ -3657,8 +3892,9 @@ bool Object::SetAccessor(Handle<String> name,
                          v8::Handle<Value> data,
                          AccessControl settings,
                          PropertyAttribute attributes) {
-  return ObjectSetAccessor(
-      this, name, getter, setter, data, settings, attributes);
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return ObjectSetAccessor(context, this, name, getter, setter, data, settings,
+                           attributes).FromMaybe(false);
 }
 
 
@@ -3668,8 +3904,9 @@ bool Object::SetAccessor(Handle<Name> name,
                          v8::Handle<Value> data,
                          AccessControl settings,
                          PropertyAttribute attributes) {
-  return ObjectSetAccessor(
-      this, name, getter, setter, data, settings, attributes);
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return ObjectSetAccessor(context, this, name, getter, setter, data, settings,
+                           attributes).FromMaybe(false);
 }
 
 
@@ -3681,7 +3918,6 @@ void Object::SetAccessorProperty(Local<Name> name,
   // TODO(verwaest): Remove |settings|.
   DCHECK_EQ(v8::DEFAULT, settings);
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::SetAccessorProperty()", return);
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
   i::Handle<i::Object> getter_i = v8::Utils::OpenHandle(*getter);
@@ -3695,116 +3931,197 @@ void Object::SetAccessorProperty(Local<Name> name,
 }
 
 
+Maybe<bool> v8::Object::HasOwnProperty(Local<Context> context,
+                                       Local<Name> key) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::HasOwnProperty()",
+                                  bool);
+  auto self = Utils::OpenHandle(this);
+  auto key_val = Utils::OpenHandle(*key);
+  auto result = i::JSReceiver::HasOwnProperty(self, key_val);
+  has_pending_exception = result.IsNothing();
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return result;
+}
+
+
 bool v8::Object::HasOwnProperty(Handle<String> key) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::HasOwnProperty()",
-             return false);
-  EXCEPTION_PREAMBLE(isolate);
-  Maybe<bool> maybe = i::JSReceiver::HasOwnProperty(Utils::OpenHandle(this),
-                                                    Utils::OpenHandle(*key));
-  has_pending_exception = !maybe.has_value;
-  EXCEPTION_BAILOUT_CHECK(isolate, false);
-  return maybe.value;
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return HasOwnProperty(context, key).FromMaybe(false);
+}
+
+
+Maybe<bool> v8::Object::HasRealNamedProperty(Local<Context> context,
+                                             Local<Name> key) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::HasRealNamedProperty()",
+                                  bool);
+  auto self = Utils::OpenHandle(this);
+  auto key_val = Utils::OpenHandle(*key);
+  auto result = i::JSObject::HasRealNamedProperty(self, key_val);
+  has_pending_exception = result.IsNothing();
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return result;
 }
 
 
 bool v8::Object::HasRealNamedProperty(Handle<String> key) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::HasRealNamedProperty()",
-             return false);
-  EXCEPTION_PREAMBLE(isolate);
-  Maybe<bool> maybe = i::JSObject::HasRealNamedProperty(
-      Utils::OpenHandle(this), Utils::OpenHandle(*key));
-  has_pending_exception = !maybe.has_value;
-  EXCEPTION_BAILOUT_CHECK(isolate, false);
-  return maybe.value;
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return HasRealNamedProperty(context, key).FromMaybe(false);
+}
+
+
+Maybe<bool> v8::Object::HasRealIndexedProperty(Local<Context> context,
+                                               uint32_t index) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context,
+                                  "v8::Object::HasRealIndexedProperty()", bool);
+  auto self = Utils::OpenHandle(this);
+  auto result = i::JSObject::HasRealElementProperty(self, index);
+  has_pending_exception = result.IsNothing();
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return result;
 }
 
 
 bool v8::Object::HasRealIndexedProperty(uint32_t index) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::HasRealIndexedProperty()",
-             return false);
-  EXCEPTION_PREAMBLE(isolate);
-  Maybe<bool> maybe =
-      i::JSObject::HasRealElementProperty(Utils::OpenHandle(this), index);
-  has_pending_exception = !maybe.has_value;
-  EXCEPTION_BAILOUT_CHECK(isolate, false);
-  return maybe.value;
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return HasRealIndexedProperty(context, index).FromMaybe(false);
+}
+
+
+Maybe<bool> v8::Object::HasRealNamedCallbackProperty(Local<Context> context,
+                                                     Local<Name> key) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(
+      context, "v8::Object::HasRealNamedCallbackProperty()", bool);
+  auto self = Utils::OpenHandle(this);
+  auto key_val = Utils::OpenHandle(*key);
+  auto result = i::JSObject::HasRealNamedCallbackProperty(self, key_val);
+  has_pending_exception = result.IsNothing();
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return result;
 }
 
 
 bool v8::Object::HasRealNamedCallbackProperty(Handle<String> key) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate,
-             "v8::Object::HasRealNamedCallbackProperty()",
-             return false);
-  ENTER_V8(isolate);
-  EXCEPTION_PREAMBLE(isolate);
-  Maybe<bool> maybe = i::JSObject::HasRealNamedCallbackProperty(
-      Utils::OpenHandle(this), Utils::OpenHandle(*key));
-  has_pending_exception = !maybe.has_value;
-  EXCEPTION_BAILOUT_CHECK(isolate, false);
-  return maybe.value;
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return HasRealNamedCallbackProperty(context, key).FromMaybe(false);
 }
 
 
 bool v8::Object::HasNamedLookupInterceptor() {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::HasNamedLookupInterceptor()",
-             return false);
-  return Utils::OpenHandle(this)->HasNamedInterceptor();
+  auto self = Utils::OpenHandle(this);
+  return self->HasNamedInterceptor();
 }
 
 
 bool v8::Object::HasIndexedLookupInterceptor() {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::HasIndexedLookupInterceptor()",
-             return false);
-  return Utils::OpenHandle(this)->HasIndexedInterceptor();
+  auto self = Utils::OpenHandle(this);
+  return self->HasIndexedInterceptor();
 }
 
 
-static Local<Value> GetPropertyByLookup(i::LookupIterator* it) {
-  // If the property being looked up is a callback, it can throw an exception.
-  EXCEPTION_PREAMBLE(it->isolate());
-  i::Handle<i::Object> result;
-  has_pending_exception = !i::Object::GetProperty(it).ToHandle(&result);
-  EXCEPTION_BAILOUT_CHECK(it->isolate(), Local<Value>());
-
-  if (it->IsFound()) return Utils::ToLocal(result);
-  return Local<Value>();
+MaybeLocal<Value> v8::Object::GetRealNamedPropertyInPrototypeChain(
+    Local<Context> context, Local<Name> key) {
+  PREPARE_FOR_EXECUTION(
+      context, "v8::Object::GetRealNamedPropertyInPrototypeChain()", Value);
+  auto self = Utils::OpenHandle(this);
+  auto key_obj = Utils::OpenHandle(*key);
+  i::PrototypeIterator iter(isolate, self);
+  if (iter.IsAtEnd()) return MaybeLocal<Value>();
+  auto proto = i::PrototypeIterator::GetCurrent(iter);
+  i::LookupIterator it(self, key_obj, i::Handle<i::JSReceiver>::cast(proto),
+                       i::LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
+  if (!it.IsFound()) return MaybeLocal<Value>();
+  Local<Value> result;
+  has_pending_exception = !ToLocal<Value>(i::Object::GetProperty(&it), &result);
+  RETURN_ON_FAILED_EXECUTION(Value);
+  RETURN_ESCAPED(result);
 }
 
 
 Local<Value> v8::Object::GetRealNamedPropertyInPrototypeChain(
     Handle<String> key) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate,
-             "v8::Object::GetRealNamedPropertyInPrototypeChain()",
-             return Local<Value>());
-  ENTER_V8(isolate);
-  i::Handle<i::JSObject> self_obj = Utils::OpenHandle(this);
-  i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
-  i::PrototypeIterator iter(isolate, self_obj);
-  if (iter.IsAtEnd()) return Local<Value>();
-  i::Handle<i::Object> proto = i::PrototypeIterator::GetCurrent(iter);
-  i::LookupIterator it(self_obj, key_obj, i::Handle<i::JSReceiver>::cast(proto),
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(GetRealNamedPropertyInPrototypeChain(context, key),
+                            Value);
+}
+
+
+Maybe<PropertyAttribute>
+v8::Object::GetRealNamedPropertyAttributesInPrototypeChain(
+    Local<Context> context, Local<Name> key) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(
+      context, "v8::Object::GetRealNamedPropertyAttributesInPrototypeChain()",
+      PropertyAttribute);
+  auto self = Utils::OpenHandle(this);
+  auto key_obj = Utils::OpenHandle(*key);
+  i::PrototypeIterator iter(isolate, self);
+  if (iter.IsAtEnd()) return Nothing<PropertyAttribute>();
+  auto proto = i::PrototypeIterator::GetCurrent(iter);
+  i::LookupIterator it(self, key_obj, i::Handle<i::JSReceiver>::cast(proto),
                        i::LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
-  return GetPropertyByLookup(&it);
+  if (!it.IsFound()) return Nothing<PropertyAttribute>();
+  auto result = i::JSReceiver::GetPropertyAttributes(&it);
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(PropertyAttribute);
+  if (result.FromJust() == ABSENT) {
+    return Just(static_cast<PropertyAttribute>(NONE));
+  }
+  return Just<PropertyAttribute>(
+      static_cast<PropertyAttribute>(result.FromJust()));
+}
+
+
+Maybe<PropertyAttribute>
+v8::Object::GetRealNamedPropertyAttributesInPrototypeChain(Handle<String> key) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return GetRealNamedPropertyAttributesInPrototypeChain(context, key);
+}
+
+
+MaybeLocal<Value> v8::Object::GetRealNamedProperty(Local<Context> context,
+                                                   Local<Name> key) {
+  PREPARE_FOR_EXECUTION(
+      context, "v8::Object::GetRealNamedPropertyInPrototypeChain()", Value);
+  auto self = Utils::OpenHandle(this);
+  auto key_obj = Utils::OpenHandle(*key);
+  i::LookupIterator it(self, key_obj,
+                       i::LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
+  if (!it.IsFound()) return MaybeLocal<Value>();
+  Local<Value> result;
+  has_pending_exception = !ToLocal<Value>(i::Object::GetProperty(&it), &result);
+  RETURN_ON_FAILED_EXECUTION(Value);
+  RETURN_ESCAPED(result);
 }
 
 
 Local<Value> v8::Object::GetRealNamedProperty(Handle<String> key) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::GetRealNamedProperty()",
-             return Local<Value>());
-  ENTER_V8(isolate);
-  i::Handle<i::JSObject> self_obj = Utils::OpenHandle(this);
-  i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
-  i::LookupIterator it(self_obj, key_obj,
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(GetRealNamedProperty(context, key), Value);
+}
+
+
+Maybe<PropertyAttribute> v8::Object::GetRealNamedPropertyAttributes(
+    Local<Context> context, Local<Name> key) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(
+      context, "v8::Object::GetRealNamedPropertyAttributes()",
+      PropertyAttribute);
+  auto self = Utils::OpenHandle(this);
+  auto key_obj = Utils::OpenHandle(*key);
+  i::LookupIterator it(self, key_obj,
                        i::LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
-  return GetPropertyByLookup(&it);
+  if (!it.IsFound()) return Nothing<PropertyAttribute>();
+  auto result = i::JSReceiver::GetPropertyAttributes(&it);
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(PropertyAttribute);
+  if (result.FromJust() == ABSENT) {
+    return Just(static_cast<PropertyAttribute>(NONE));
+  }
+  return Just<PropertyAttribute>(
+      static_cast<PropertyAttribute>(result.FromJust()));
+}
+
+
+Maybe<PropertyAttribute> v8::Object::GetRealNamedPropertyAttributes(
+    Handle<String> key) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  return GetRealNamedPropertyAttributes(context, key);
 }
 
 
@@ -3813,7 +4130,6 @@ Local<Value> v8::Object::GetRealNamedProperty(Handle<String> key) {
 // the old map of this object will fail.
 void v8::Object::TurnOnAccessCheck() {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::TurnOnAccessCheck()", return);
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
   i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
@@ -3830,35 +4146,26 @@ void v8::Object::TurnOnAccessCheck() {
 
 
 Local<v8::Object> v8::Object::Clone() {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::Clone()", return Local<Object>());
+  auto self = Utils::OpenHandle(this);
+  auto isolate = self->GetIsolate();
   ENTER_V8(isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  EXCEPTION_PREAMBLE(isolate);
-  i::Handle<i::JSObject> result = isolate->factory()->CopyJSObject(self);
-  has_pending_exception = result.is_null();
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<Object>());
+  auto result = isolate->factory()->CopyJSObject(self);
+  CHECK(!result.is_null());
   return Utils::ToLocal(result);
 }
 
 
 Local<v8::Context> v8::Object::CreationContext() {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate,
-             "v8::Object::CreationContext()", return Local<v8::Context>());
-  ENTER_V8(isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  i::Context* context = self->GetCreationContext();
-  return Utils::ToLocal(i::Handle<i::Context>(context));
+  auto self = Utils::OpenHandle(this);
+  auto context = handle(self->GetCreationContext());
+  return Utils::ToLocal(context);
 }
 
 
 int v8::Object::GetIdentityHash() {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::GetIdentityHash()", return 0);
-  ENTER_V8(isolate);
+  auto isolate = Utils::OpenHandle(this)->GetIsolate();
   i::HandleScope scope(isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  auto self = Utils::OpenHandle(this);
   return i::JSReceiver::GetOrCreateIdentityHash(self)->value();
 }
 
@@ -3866,7 +4173,6 @@ int v8::Object::GetIdentityHash() {
 bool v8::Object::SetHiddenValue(v8::Handle<v8::String> key,
                                 v8::Handle<v8::Value> value) {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::SetHiddenValue()", return false);
   if (value.IsEmpty()) return DeleteHiddenValue(key);
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
@@ -3883,8 +4189,6 @@ bool v8::Object::SetHiddenValue(v8::Handle<v8::String> key,
 
 v8::Local<v8::Value> v8::Object::GetHiddenValue(v8::Handle<v8::String> key) {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::GetHiddenValue()",
-             return Local<v8::Value>());
   ENTER_V8(isolate);
   i::Handle<i::JSObject> self = Utils::OpenHandle(this);
   i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
@@ -3898,7 +4202,6 @@ v8::Local<v8::Value> v8::Object::GetHiddenValue(v8::Handle<v8::String> key) {
 
 bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::DeleteHiddenValue()", return false);
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
   i::Handle<i::JSObject> self = Utils::OpenHandle(this);
@@ -3947,8 +4250,8 @@ void PrepareExternalArrayElements(i::Handle<i::JSObject> object,
 
 
 void v8::Object::SetIndexedPropertiesToPixelData(uint8_t* data, int length) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::SetElementsToPixelData()", return);
+  auto self = Utils::OpenHandle(this);
+  auto isolate = self->GetIsolate();
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
   if (!Utils::ApiCheck(length >= 0 &&
@@ -3957,7 +4260,6 @@ void v8::Object::SetIndexedPropertiesToPixelData(uint8_t* data, int length) {
                        "length exceeds max acceptable value")) {
     return;
   }
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
   if (!Utils::ApiCheck(!self->IsJSArray(),
                        "v8::Object::SetIndexedPropertiesToPixelData()",
                        "JSArray is not supported")) {
@@ -3968,35 +4270,27 @@ void v8::Object::SetIndexedPropertiesToPixelData(uint8_t* data, int length) {
 
 
 bool v8::Object::HasIndexedPropertiesInPixelData() {
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  ON_BAILOUT(self->GetIsolate(), "v8::HasIndexedPropertiesInPixelData()",
-             return false);
+  auto self = Utils::OpenHandle(this);
   return self->HasExternalUint8ClampedElements();
 }
 
 
 uint8_t* v8::Object::GetIndexedPropertiesPixelData() {
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  ON_BAILOUT(self->GetIsolate(), "v8::GetIndexedPropertiesPixelData()",
-             return NULL);
+  auto self = Utils::OpenHandle(this);
   if (self->HasExternalUint8ClampedElements()) {
     return i::ExternalUint8ClampedArray::cast(self->elements())->
         external_uint8_clamped_pointer();
-  } else {
-    return NULL;
   }
+  return nullptr;
 }
 
 
 int v8::Object::GetIndexedPropertiesPixelDataLength() {
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  ON_BAILOUT(self->GetIsolate(), "v8::GetIndexedPropertiesPixelDataLength()",
-             return -1);
+  auto self = Utils::OpenHandle(this);
   if (self->HasExternalUint8ClampedElements()) {
     return i::ExternalUint8ClampedArray::cast(self->elements())->length();
-  } else {
-    return -1;
   }
+  return -1;
 }
 
 
@@ -4004,8 +4298,8 @@ void v8::Object::SetIndexedPropertiesToExternalArrayData(
     void* data,
     ExternalArrayType array_type,
     int length) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::SetIndexedPropertiesToExternalArrayData()", return);
+  auto self = Utils::OpenHandle(this);
+  auto isolate = self->GetIsolate();
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
   if (!Utils::ApiCheck(length >= 0 && length <= i::ExternalArray::kMaxLength,
@@ -4013,7 +4307,6 @@ void v8::Object::SetIndexedPropertiesToExternalArrayData(
                        "length exceeds max acceptable value")) {
     return;
   }
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
   if (!Utils::ApiCheck(!self->IsJSArray(),
                        "v8::Object::SetIndexedPropertiesToExternalArrayData()",
                        "JSArray is not supported")) {
@@ -4024,32 +4317,22 @@ void v8::Object::SetIndexedPropertiesToExternalArrayData(
 
 
 bool v8::Object::HasIndexedPropertiesInExternalArrayData() {
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  ON_BAILOUT(self->GetIsolate(),
-             "v8::HasIndexedPropertiesInExternalArrayData()",
-             return false);
+  auto self = Utils::OpenHandle(this);
   return self->HasExternalArrayElements();
 }
 
 
 void* v8::Object::GetIndexedPropertiesExternalArrayData() {
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  ON_BAILOUT(self->GetIsolate(),
-             "v8::GetIndexedPropertiesExternalArrayData()",
-             return NULL);
+  auto self = Utils::OpenHandle(this);
   if (self->HasExternalArrayElements()) {
     return i::ExternalArray::cast(self->elements())->external_pointer();
-  } else {
-    return NULL;
   }
+  return nullptr;
 }
 
 
 ExternalArrayType v8::Object::GetIndexedPropertiesExternalArrayDataType() {
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  ON_BAILOUT(self->GetIsolate(),
-             "v8::GetIndexedPropertiesExternalArrayDataType()",
-             return static_cast<ExternalArrayType>(-1));
+  auto self = Utils::OpenHandle(this);
   switch (self->elements()->map()->instance_type()) {
 #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size)            \
     case i::EXTERNAL_##TYPE##_ARRAY_TYPE:                                     \
@@ -4063,101 +4346,99 @@ ExternalArrayType v8::Object::GetIndexedPropertiesExternalArrayDataType() {
 
 
 int v8::Object::GetIndexedPropertiesExternalArrayDataLength() {
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  ON_BAILOUT(self->GetIsolate(),
-             "v8::GetIndexedPropertiesExternalArrayDataLength()",
-             return 0);
+  auto self = Utils::OpenHandle(this);
   if (self->HasExternalArrayElements()) {
     return i::ExternalArray::cast(self->elements())->length();
-  } else {
-    return -1;
   }
+  return -1;
 }
 
 
 bool v8::Object::IsCallable() {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::IsCallable()", return false);
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
-  return obj->IsCallable();
+  auto self = Utils::OpenHandle(this);
+  return self->IsCallable();
 }
 
 
-Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Value> recv,
-                                        int argc,
-                                        v8::Handle<v8::Value> argv[]) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::CallAsFunction()",
-             return Local<v8::Value>());
-  LOG_API(isolate, "Object::CallAsFunction");
-  ENTER_V8(isolate);
+MaybeLocal<Value> Object::CallAsFunction(Local<Context> context,
+                                         Handle<Value> recv, int argc,
+                                         Handle<Value> argv[]) {
+  PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, "v8::Object::CallAsFunction()",
+                                      Value);
   i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
-  i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv);
+  auto self = Utils::OpenHandle(this);
+  auto recv_obj = Utils::OpenHandle(*recv);
   STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
   i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
-  i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>();
-  if (obj->IsJSFunction()) {
-    fun = i::Handle<i::JSFunction>::cast(obj);
+  i::Handle<i::JSFunction> fun;
+  if (self->IsJSFunction()) {
+    fun = i::Handle<i::JSFunction>::cast(self);
   } else {
-    EXCEPTION_PREAMBLE(isolate);
     i::Handle<i::Object> delegate;
-    has_pending_exception = !i::Execution::TryGetFunctionDelegate(
-        isolate, obj).ToHandle(&delegate);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
+    has_pending_exception = !i::Execution::TryGetFunctionDelegate(isolate, self)
+                                 .ToHandle(&delegate);
+    RETURN_ON_FAILED_EXECUTION(Value);
     fun = i::Handle<i::JSFunction>::cast(delegate);
-    recv_obj = obj;
+    recv_obj = self;
   }
-  EXCEPTION_PREAMBLE(isolate);
-  i::Handle<i::Object> returned;
-  has_pending_exception = !i::Execution::Call(
-      isolate, fun, recv_obj, argc, args, true).ToHandle(&returned);
-  EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<Value>());
-  return Utils::ToLocal(scope.CloseAndEscape(returned));
+  Local<Value> result;
+  has_pending_exception =
+      !ToLocal<Value>(
+          i::Execution::Call(isolate, fun, recv_obj, argc, args, true),
+          &result);
+  RETURN_ON_FAILED_EXECUTION(Value);
+  RETURN_ESCAPED(result);
 }
 
 
-Local<v8::Value> Object::CallAsConstructor(int argc,
-                                           v8::Handle<v8::Value> argv[]) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::CallAsConstructor()",
-             return Local<v8::Object>());
-  LOG_API(isolate, "Object::CallAsConstructor");
-  ENTER_V8(isolate);
+Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Value> recv, int argc,
+                                        v8::Handle<v8::Value> argv[]) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  Local<Value>* argv_cast = reinterpret_cast<Local<Value>*>(argv);
+  RETURN_TO_LOCAL_UNCHECKED(CallAsFunction(context, recv, argc, argv_cast),
+                            Value);
+}
+
+
+MaybeLocal<Value> Object::CallAsConstructor(Local<Context> context, int argc,
+                                            Local<Value> argv[]) {
+  PREPARE_FOR_EXECUTION_WITH_CALLBACK(context,
+                                      "v8::Object::CallAsConstructor()", Value);
   i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+  auto self = Utils::OpenHandle(this);
   STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
   i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
-  if (obj->IsJSFunction()) {
-    i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(obj);
-    EXCEPTION_PREAMBLE(isolate);
-    i::Handle<i::Object> returned;
-    has_pending_exception = !i::Execution::New(
-        fun, argc, args).ToHandle(&returned);
-    EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<v8::Object>());
-    return Utils::ToLocal(scope.CloseAndEscape(
-        i::Handle<i::JSObject>::cast(returned)));
-  }
-  EXCEPTION_PREAMBLE(isolate);
+  if (self->IsJSFunction()) {
+    auto fun = i::Handle<i::JSFunction>::cast(self);
+    Local<Value> result;
+    has_pending_exception =
+        !ToLocal<Value>(i::Execution::New(fun, argc, args), &result);
+    RETURN_ON_FAILED_EXECUTION(Value);
+    RETURN_ESCAPED(result);
+  }
   i::Handle<i::Object> delegate;
   has_pending_exception = !i::Execution::TryGetConstructorDelegate(
-      isolate, obj).ToHandle(&delegate);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
+                               isolate, self).ToHandle(&delegate);
+  RETURN_ON_FAILED_EXECUTION(Value);
   if (!delegate->IsUndefined()) {
-    i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(delegate);
-    EXCEPTION_PREAMBLE(isolate);
-    i::Handle<i::Object> returned;
-    has_pending_exception = !i::Execution::Call(
-        isolate, fun, obj, argc, args).ToHandle(&returned);
-    EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<v8::Object>());
+    auto fun = i::Handle<i::JSFunction>::cast(delegate);
+    Local<Value> result;
+    has_pending_exception =
+        !ToLocal<Value>(i::Execution::Call(isolate, fun, self, argc, args),
+                        &result);
+    RETURN_ON_FAILED_EXECUTION(Value);
     DCHECK(!delegate->IsUndefined());
-    return Utils::ToLocal(scope.CloseAndEscape(returned));
+    RETURN_ESCAPED(result);
   }
-  return Local<v8::Object>();
+  return MaybeLocal<Value>();
+}
+
+
+Local<v8::Value> Object::CallAsConstructor(int argc,
+                                           v8::Handle<v8::Value> argv[]) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  Local<Value>* argv_cast = reinterpret_cast<Local<Value>*>(argv);
+  RETURN_TO_LOCAL_UNCHECKED(CallAsConstructor(context, argc, argv_cast), Value);
 }
 
 
@@ -4179,52 +4460,56 @@ Local<v8::Object> Function::NewInstance() const {
 }
 
 
-Local<v8::Object> Function::NewInstance(int argc,
-                                        v8::Handle<v8::Value> argv[]) const {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Function::NewInstance()",
-             return Local<v8::Object>());
-  LOG_API(isolate, "Function::NewInstance");
-  ENTER_V8(isolate);
+MaybeLocal<Object> Function::NewInstance(Local<Context> context, int argc,
+                                         v8::Handle<v8::Value> argv[]) const {
+  PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, "v8::Function::NewInstance()",
+                                      Object);
   i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate);
-  EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
-  i::Handle<i::JSFunction> function = Utils::OpenHandle(this);
+  auto self = Utils::OpenHandle(this);
   STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
   i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
-  EXCEPTION_PREAMBLE(isolate);
-  i::Handle<i::Object> returned;
-  has_pending_exception = !i::Execution::New(
-      function, argc, args).ToHandle(&returned);
-  EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<v8::Object>());
-  return scope.Escape(Utils::ToLocal(i::Handle<i::JSObject>::cast(returned)));
+  Local<Object> result;
+  has_pending_exception =
+      !ToLocal<Object>(i::Execution::New(self, argc, args), &result);
+  RETURN_ON_FAILED_EXECUTION(Object);
+  RETURN_ESCAPED(result);
 }
 
 
-Local<v8::Value> Function::Call(v8::Handle<v8::Value> recv, int argc,
-                                v8::Handle<v8::Value> argv[]) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Function::Call()", return Local<v8::Value>());
-  LOG_API(isolate, "Function::Call");
-  ENTER_V8(isolate);
+Local<v8::Object> Function::NewInstance(int argc,
+                                        v8::Handle<v8::Value> argv[]) const {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(NewInstance(context, argc, argv), Object);
+}
+
+
+MaybeLocal<v8::Value> Function::Call(Local<Context> context,
+                                     v8::Handle<v8::Value> recv, int argc,
+                                     v8::Handle<v8::Value> argv[]) {
+  PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, "v8::Function::Call()", Value);
   i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate);
-  i::HandleScope scope(isolate);
-  i::Handle<i::JSFunction> fun = Utils::OpenHandle(this);
+  auto self = Utils::OpenHandle(this);
   i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv);
   STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
   i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
-  EXCEPTION_PREAMBLE(isolate);
-  i::Handle<i::Object> returned;
-  has_pending_exception = !i::Execution::Call(
-      isolate, fun, recv_obj, argc, args, true).ToHandle(&returned);
-  EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<Object>());
-  return Utils::ToLocal(scope.CloseAndEscape(returned));
+  Local<Value> result;
+  has_pending_exception =
+      !ToLocal<Value>(
+          i::Execution::Call(isolate, self, recv_obj, argc, args, true),
+          &result);
+  RETURN_ON_FAILED_EXECUTION(Value);
+  RETURN_ESCAPED(result);
+}
+
+
+Local<v8::Value> Function::Call(v8::Handle<v8::Value> recv, int argc,
+                                v8::Handle<v8::Value> argv[]) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(Call(context, recv, argc, argv), Value);
 }
 
 
 void Function::SetName(v8::Handle<v8::String> name) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ENTER_V8(isolate);
-  USE(isolate);
   i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
   func->shared()->set_name(*Utils::OpenHandle(*name));
 }
@@ -4246,22 +4531,16 @@ Handle<Value> Function::GetInferredName() const {
 
 Handle<Value> Function::GetDisplayName() const {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Function::GetDisplayName()",
-             return ToApiHandle<Primitive>(
-                 isolate->factory()->undefined_value()));
   ENTER_V8(isolate);
   i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
   i::Handle<i::String> property_name =
-      isolate->factory()->InternalizeOneByteString(
-          STATIC_CHAR_VECTOR("displayName"));
-
+      isolate->factory()->NewStringFromStaticChars("displayName");
   i::Handle<i::Object> value =
       i::JSObject::GetDataProperty(func, property_name);
   if (value->IsString()) {
     i::Handle<i::String> name = i::Handle<i::String>::cast(value);
     if (name->length() > 0) return Utils::ToLocal(name);
   }
-
   return ToApiHandle<Primitive>(isolate->factory()->undefined_value());
 }
 
@@ -4270,16 +4549,7 @@ ScriptOrigin Function::GetScriptOrigin() const {
   i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
   if (func->shared()->script()->IsScript()) {
     i::Handle<i::Script> script(i::Script::cast(func->shared()->script()));
-    i::Handle<i::Object> scriptName = i::Script::GetNameOrSourceURL(script);
-    v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(func->GetIsolate());
-    v8::ScriptOrigin origin(
-        Utils::ToLocal(scriptName),
-        v8::Integer::New(isolate, script->line_offset()->value()),
-        v8::Integer::New(isolate, script->column_offset()->value()),
-        v8::Boolean::New(isolate, script->is_shared_cross_origin()),
-        v8::Integer::New(isolate, script->id()->value()),
-        v8::Boolean::New(isolate, script->is_embedder_debug_script()));
-    return origin;
+    return GetScriptOriginForScript(func->GetIsolate(), script);
   }
   return v8::ScriptOrigin(Handle<Value>());
 }
@@ -4339,11 +4609,7 @@ Local<v8::Value> Function::GetBoundFunction() const {
 
 
 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);
+  auto self = Utils::OpenHandle(this);
   return static_cast<int>(self->Hash());
 }
 
@@ -5169,6 +5435,9 @@ void v8::V8::ShutdownPlatform() {
 
 bool v8::V8::Initialize() {
   i::V8::Initialize();
+#ifdef V8_USE_EXTERNAL_STARTUP_DATA
+  i::ReadNatives();
+#endif
   return true;
 }
 
@@ -5195,6 +5464,9 @@ void v8::V8::SetArrayBufferAllocator(
 
 bool v8::V8::Dispose() {
   i::V8::TearDown();
+#ifdef V8_USE_EXTERNAL_STARTUP_DATA
+  i::DisposeNatives();
+#endif
   return true;
 }
 
@@ -5289,7 +5561,6 @@ Local<Context> v8::Context::New(
     v8::Handle<Value> global_object) {
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(external_isolate);
   LOG_API(isolate, "Context::New");
-  ON_BAILOUT(isolate, "v8::Context::New()", return Local<Context>());
   i::HandleScope scope(isolate);
   ExtensionConfiguration no_extensions;
   if (extensions == NULL) extensions = &no_extensions;
@@ -5302,8 +5573,6 @@ Local<Context> v8::Context::New(
 
 void v8::Context::SetSecurityToken(Handle<Value> token) {
   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);
 }
@@ -5311,8 +5580,6 @@ void v8::Context::SetSecurityToken(Handle<Value> token) {
 
 void v8::Context::UseDefaultSecurityToken() {
   i::Handle<i::Context> env = Utils::OpenHandle(this);
-  i::Isolate* isolate = env->GetIsolate();
-  ENTER_V8(isolate);
   env->set_security_token(env->global_object());
 }
 
@@ -5377,44 +5644,45 @@ void Context::SetErrorMessageForCodeGenerationFromStrings(
 }
 
 
+MaybeLocal<v8::Object> ObjectTemplate::NewInstance(Local<Context> context) {
+  PREPARE_FOR_EXECUTION(context, "v8::ObjectTemplate::NewInstance()", Object);
+  auto self = Utils::OpenHandle(this);
+  Local<Object> result;
+  has_pending_exception =
+      !ToLocal<Object>(i::ApiNatives::InstantiateObject(self), &result);
+  RETURN_ON_FAILED_EXECUTION(Object);
+  RETURN_ESCAPED(result);
+}
+
+
 Local<v8::Object> ObjectTemplate::NewInstance() {
-  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;
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(NewInstance(context), Object);
+}
+
+
+MaybeLocal<v8::Function> FunctionTemplate::GetFunction(Local<Context> context) {
+  PREPARE_FOR_EXECUTION(context, "v8::FunctionTemplate::GetFunction()",
+                        Function);
+  auto self = Utils::OpenHandle(this);
+  Local<Function> result;
   has_pending_exception =
-      !i::ApiNatives::InstantiateObject(info).ToHandle(&obj);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
-  return Utils::ToLocal(i::Handle<i::JSObject>::cast(obj));
+      !ToLocal<Function>(i::ApiNatives::InstantiateFunction(self), &result);
+  RETURN_ON_FAILED_EXECUTION(Function);
+  RETURN_ESCAPED(result);
 }
 
 
 Local<v8::Function> FunctionTemplate::GetFunction() {
-  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::ApiNatives::InstantiateFunction(info).ToHandle(&obj);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Function>());
-  return Utils::ToLocal(i::Handle<i::JSFunction>::cast(obj));
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(GetFunction(context), Function);
 }
 
 
 bool FunctionTemplate::HasInstance(v8::Handle<v8::Value> value) {
-  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 info->IsTemplateFor(obj);
+  auto self = Utils::OpenHandle(this);
+  auto obj = Utils::OpenHandle(*value);
+  return self->IsTemplateFor(*obj);
 }
 
 
@@ -5456,9 +5724,9 @@ inline int StringLength(const uint16_t* string) {
 
 MUST_USE_RESULT
 inline i::MaybeHandle<i::String> NewString(i::Factory* factory,
-                                           String::NewStringType type,
+                                           v8::NewStringType type,
                                            i::Vector<const char> string) {
-  if (type == String::kInternalizedString) {
+  if (type == v8::NewStringType::kInternalized) {
     return factory->InternalizeUtf8String(string);
   }
   return factory->NewStringFromUtf8(string);
@@ -5467,9 +5735,9 @@ inline i::MaybeHandle<i::String> NewString(i::Factory* factory,
 
 MUST_USE_RESULT
 inline i::MaybeHandle<i::String> NewString(i::Factory* factory,
-                                           String::NewStringType type,
+                                           v8::NewStringType type,
                                            i::Vector<const uint8_t> string) {
-  if (type == String::kInternalizedString) {
+  if (type == v8::NewStringType::kInternalized) {
     return factory->InternalizeOneByteString(string);
   }
   return factory->NewStringFromOneByte(string);
@@ -5478,36 +5746,32 @@ inline i::MaybeHandle<i::String> NewString(i::Factory* factory,
 
 MUST_USE_RESULT
 inline i::MaybeHandle<i::String> NewString(i::Factory* factory,
-                                           String::NewStringType type,
+                                           v8::NewStringType type,
                                            i::Vector<const uint16_t> string) {
-  if (type == String::kInternalizedString) {
+  if (type == v8::NewStringType::kInternalized) {
     return factory->InternalizeTwoByteString(string);
   }
   return factory->NewStringFromTwoByte(string);
 }
 
 
-template<typename Char>
-inline Local<String> NewString(Isolate* v8_isolate,
-                               const char* location,
-                               const char* env,
-                               const Char* data,
-                               String::NewStringType type,
-                               int length) {
+STATIC_ASSERT(v8::String::kMaxLength == i::String::kMaxLength);
+
+
+template <typename Char>
+inline MaybeLocal<String> NewString(Isolate* v8_isolate, const char* location,
+                                    const char* env, const Char* data,
+                                    v8::NewStringType type, int length) {
   i::Isolate* isolate = reinterpret_cast<internal::Isolate*>(v8_isolate);
-  ON_BAILOUT(isolate, location, return Local<String>());
-  LOG_API(isolate, env);
-  if (length == 0) {
-    return String::Empty(v8_isolate);
-  }
+  if (length == 0) return String::Empty(v8_isolate);
+  // TODO(dcarney): throw a context free exception.
+  if (length > i::String::kMaxLength) return MaybeLocal<String>();
   ENTER_V8(isolate);
-  if (length == -1) length = StringLength(data);
-  EXCEPTION_PREAMBLE(isolate);
-  i::Handle<i::String> result;
-  has_pending_exception =
-      !NewString(isolate->factory(), type, i::Vector<const Char>(data, length))
-           .ToHandle(&result);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<String>());
+  LOG_API(isolate, env);
+  if (length < 0) length = StringLength(data);
+  i::Handle<i::String> result =
+      NewString(isolate->factory(), type, i::Vector<const Char>(data, length))
+          .ToHandleChecked();
   return Utils::ToLocal(result);
 }
 
@@ -5518,12 +5782,17 @@ Local<String> String::NewFromUtf8(Isolate* isolate,
                                   const char* data,
                                   NewStringType type,
                                   int length) {
-  return NewString(isolate,
-                   "v8::String::NewFromUtf8()",
-                   "String::NewFromUtf8",
-                   data,
-                   type,
-                   length);
+  RETURN_TO_LOCAL_UNCHECKED(
+      NewString(isolate, "v8::String::NewFromUtf8()", "String::NewFromUtf8",
+                data, static_cast<v8::NewStringType>(type), length),
+      String);
+}
+
+
+MaybeLocal<String> String::NewFromUtf8(Isolate* isolate, const char* data,
+                                       v8::NewStringType type, int length) {
+  return NewString(isolate, "v8::String::NewFromUtf8()", "String::NewFromUtf8",
+                   data, type, length);
 }
 
 
@@ -5531,12 +5800,18 @@ Local<String> String::NewFromOneByte(Isolate* isolate,
                                      const uint8_t* data,
                                      NewStringType type,
                                      int length) {
-  return NewString(isolate,
-                   "v8::String::NewFromOneByte()",
-                   "String::NewFromOneByte",
-                   data,
-                   type,
-                   length);
+  RETURN_TO_LOCAL_UNCHECKED(
+      NewString(isolate, "v8::String::NewFromOneByte()",
+                "String::NewFromOneByte", data,
+                static_cast<v8::NewStringType>(type), length),
+      String);
+}
+
+
+MaybeLocal<String> String::NewFromOneByte(Isolate* isolate, const uint8_t* data,
+                                          v8::NewStringType type, int length) {
+  return NewString(isolate, "v8::String::NewFromOneByte()",
+                   "String::NewFromOneByte", data, type, length);
 }
 
 
@@ -5544,20 +5819,27 @@ Local<String> String::NewFromTwoByte(Isolate* isolate,
                                      const uint16_t* data,
                                      NewStringType type,
                                      int length) {
-  return NewString(isolate,
-                   "v8::String::NewFromTwoByte()",
-                   "String::NewFromTwoByte",
-                   data,
-                   type,
-                   length);
+  RETURN_TO_LOCAL_UNCHECKED(
+      NewString(isolate, "v8::String::NewFromTwoByte()",
+                "String::NewFromTwoByte", data,
+                static_cast<v8::NewStringType>(type), length),
+      String);
+}
+
+
+MaybeLocal<String> String::NewFromTwoByte(Isolate* isolate,
+                                          const uint16_t* data,
+                                          v8::NewStringType type, int length) {
+  return NewString(isolate, "v8::String::NewFromTwoByte()",
+                   "String::NewFromTwoByte", data, type, length);
 }
 
 
 Local<String> v8::String::Concat(Handle<String> left, Handle<String> right) {
   i::Handle<i::String> left_string = Utils::OpenHandle(*left);
   i::Isolate* isolate = left_string->GetIsolate();
-  LOG_API(isolate, "String::New(char)");
   ENTER_V8(isolate);
+  LOG_API(isolate, "v8::String::Concat");
   i::Handle<i::String> right_string = Utils::OpenHandle(*right);
   // If we are steering towards a range error, do not wait for the error to be
   // thrown, and return the null handle instead.
@@ -5570,35 +5852,54 @@ Local<String> v8::String::Concat(Handle<String> left, Handle<String> right) {
 }
 
 
-static i::MaybeHandle<i::String> NewExternalStringHandle(
-    i::Isolate* isolate, v8::String::ExternalStringResource* resource) {
-  return isolate->factory()->NewExternalStringFromTwoByte(resource);
+MaybeLocal<String> v8::String::NewExternalTwoByte(
+    Isolate* isolate, v8::String::ExternalStringResource* resource) {
+  CHECK(resource && resource->data());
+  // TODO(dcarney): throw a context free exception.
+  if (resource->length() > static_cast<size_t>(i::String::kMaxLength)) {
+    return MaybeLocal<String>();
+  }
+  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+  ENTER_V8(i_isolate);
+  LOG_API(i_isolate, "String::NewExternalTwoByte");
+  i::Handle<i::String> string = i_isolate->factory()
+                                    ->NewExternalStringFromTwoByte(resource)
+                                    .ToHandleChecked();
+  i_isolate->heap()->external_string_table()->AddString(*string);
+  return Utils::ToLocal(string);
 }
 
 
-static i::MaybeHandle<i::String> NewExternalOneByteStringHandle(
-    i::Isolate* isolate, v8::String::ExternalOneByteStringResource* resource) {
-  return isolate->factory()->NewExternalStringFromOneByte(resource);
+Local<String> v8::String::NewExternal(
+    Isolate* isolate, v8::String::ExternalStringResource* resource) {
+  RETURN_TO_LOCAL_UNCHECKED(NewExternalTwoByte(isolate, resource), String);
 }
 
 
-Local<String> v8::String::NewExternal(
-    Isolate* isolate,
-    v8::String::ExternalStringResource* resource) {
+MaybeLocal<String> v8::String::NewExternalOneByte(
+    Isolate* isolate, v8::String::ExternalOneByteStringResource* resource) {
+  CHECK(resource && resource->data());
+  // TODO(dcarney): throw a context free exception.
+  if (resource->length() > static_cast<size_t>(i::String::kMaxLength)) {
+    return MaybeLocal<String>();
+  }
   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
-  LOG_API(i_isolate, "String::NewExternal");
   ENTER_V8(i_isolate);
-  CHECK(resource && resource->data());
-  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>());
+  LOG_API(i_isolate, "String::NewExternalOneByte");
+  i::Handle<i::String> string = i_isolate->factory()
+                                    ->NewExternalStringFromOneByte(resource)
+                                    .ToHandleChecked();
   i_isolate->heap()->external_string_table()->AddString(*string);
   return Utils::ToLocal(string);
 }
 
 
+Local<String> v8::String::NewExternal(
+    Isolate* isolate, v8::String::ExternalOneByteStringResource* resource) {
+  RETURN_TO_LOCAL_UNCHECKED(NewExternalOneByte(isolate, resource), String);
+}
+
+
 bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) {
   i::Handle<i::String> obj = Utils::OpenHandle(this);
   i::Isolate* isolate = obj->GetIsolate();
@@ -5625,22 +5926,6 @@ bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) {
 }
 
 
-Local<String> v8::String::NewExternal(
-    Isolate* isolate, v8::String::ExternalOneByteStringResource* resource) {
-  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
-  LOG_API(i_isolate, "String::NewExternal");
-  ENTER_V8(i_isolate);
-  CHECK(resource && resource->data());
-  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);
-}
-
-
 bool v8::String::MakeExternal(
     v8::String::ExternalOneByteStringResource* resource) {
   i::Handle<i::String> obj = Utils::OpenHandle(this);
@@ -5780,20 +6065,23 @@ Local<v8::Symbol> v8::SymbolObject::ValueOf() const {
 }
 
 
-Local<v8::Value> v8::Date::New(Isolate* isolate, double time) {
-  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
-  LOG_API(i_isolate, "Date::New");
+MaybeLocal<v8::Value> v8::Date::New(Local<Context> context, double time) {
   if (std::isnan(time)) {
     // Introduce only canonical NaN value into the VM, to avoid signaling NaNs.
     time = std::numeric_limits<double>::quiet_NaN();
   }
-  ENTER_V8(i_isolate);
-  EXCEPTION_PREAMBLE(i_isolate);
-  i::Handle<i::Object> obj;
-  has_pending_exception = !i::Execution::NewDate(
-      i_isolate, time).ToHandle(&obj);
-  EXCEPTION_BAILOUT_CHECK(i_isolate, Local<v8::Value>());
-  return Utils::ToLocal(obj);
+  PREPARE_FOR_EXECUTION(context, "Date::New", Value);
+  Local<Value> result;
+  has_pending_exception =
+      !ToLocal<Value>(i::Execution::NewDate(isolate, time), &result);
+  RETURN_ON_FAILED_EXECUTION(Value);
+  RETURN_ESCAPED(result);
+}
+
+
+Local<v8::Value> v8::Date::New(Isolate* isolate, double time) {
+  auto context = isolate->GetCurrentContext();
+  RETURN_TO_LOCAL_UNCHECKED(New(context, time), Value);
 }
 
 
@@ -5808,13 +6096,9 @@ double v8::Date::ValueOf() const {
 
 void v8::Date::DateTimeConfigurationChangeNotification(Isolate* isolate) {
   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
-  ON_BAILOUT(i_isolate, "v8::Date::DateTimeConfigurationChangeNotification()",
-             return);
   LOG_API(i_isolate, "Date::DateTimeConfigurationChangeNotification");
   ENTER_V8(i_isolate);
-
   i_isolate->date_cache()->ResetDateCache();
-
   if (!i_isolate->eternal_handles()->Exists(
           i::EternalHandles::DATE_CACHE_VERSION)) {
     return;
@@ -5843,18 +6127,24 @@ static i::Handle<i::String> RegExpFlagsToString(RegExp::Flags flags) {
 }
 
 
-Local<v8::RegExp> v8::RegExp::New(Handle<String> pattern,
-                                  Flags flags) {
-  i::Isolate* isolate = Utils::OpenHandle(*pattern)->GetIsolate();
-  LOG_API(isolate, "RegExp::New");
-  ENTER_V8(isolate);
-  EXCEPTION_PREAMBLE(isolate);
-  i::Handle<i::JSRegExp> obj;
-  has_pending_exception = !i::Execution::NewJSRegExp(
-      Utils::OpenHandle(*pattern),
-      RegExpFlagsToString(flags)).ToHandle(&obj);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::RegExp>());
-  return Utils::ToLocal(i::Handle<i::JSRegExp>::cast(obj));
+MaybeLocal<v8::RegExp> v8::RegExp::New(Local<Context> context,
+                                       Handle<String> pattern, Flags flags) {
+  PREPARE_FOR_EXECUTION(context, "RegExp::New", RegExp);
+  Local<v8::RegExp> result;
+  has_pending_exception =
+      !ToLocal<RegExp>(i::Execution::NewJSRegExp(Utils::OpenHandle(*pattern),
+                                                 RegExpFlagsToString(flags)),
+                       &result);
+  RETURN_ON_FAILED_EXECUTION(RegExp);
+  RETURN_ESCAPED(result);
+}
+
+
+Local<v8::RegExp> v8::RegExp::New(Handle<String> pattern, Flags flags) {
+  auto isolate =
+      reinterpret_cast<Isolate*>(Utils::OpenHandle(*pattern)->GetIsolate());
+  auto context = isolate->GetCurrentContext();
+  RETURN_TO_LOCAL_UNCHECKED(New(context, pattern, flags), RegExp);
 }
 
 
@@ -5904,55 +6194,46 @@ uint32_t v8::Array::Length() const {
 }
 
 
-Local<Object> Array::CloneElementAt(uint32_t index) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Array::CloneElementAt()", return Local<Object>());
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  if (!self->HasFastObjectElements()) {
-    return Local<Object>();
-  }
+MaybeLocal<Object> Array::CloneElementAt(Local<Context> context,
+                                         uint32_t index) {
+  PREPARE_FOR_EXECUTION(context, "v8::Array::CloneElementAt()", Object);
+  auto self = Utils::OpenHandle(this);
+  if (!self->HasFastObjectElements()) return Local<Object>();
   i::FixedArray* elms = i::FixedArray::cast(self->elements());
   i::Object* paragon = elms->get(index);
-  if (!paragon->IsJSObject()) {
-    return Local<Object>();
-  }
+  if (!paragon->IsJSObject()) return Local<Object>();
   i::Handle<i::JSObject> paragon_handle(i::JSObject::cast(paragon));
-  EXCEPTION_PREAMBLE(isolate);
-  ENTER_V8(isolate);
-  i::Handle<i::JSObject> result =
-      isolate->factory()->CopyJSObject(paragon_handle);
-  has_pending_exception = result.is_null();
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<Object>());
-  return Utils::ToLocal(result);
+  Local<Object> result;
+  has_pending_exception = ToLocal<Object>(
+      isolate->factory()->CopyJSObject(paragon_handle), &result);
+  RETURN_ON_FAILED_EXECUTION(Object);
+  RETURN_ESCAPED(result);
 }
 
 
-bool Value::IsPromise() const {
-  i::Handle<i::Object> val = Utils::OpenHandle(this);
-  if (!val->IsJSObject()) return false;
-  i::Handle<i::JSObject> obj = i::Handle<i::JSObject>::cast(val);
-  i::Isolate* isolate = obj->GetIsolate();
-  LOG_API(isolate, "IsPromise");
-  ENTER_V8(isolate);
-  EXCEPTION_PREAMBLE(isolate);
-  i::Handle<i::Object> argv[] = { obj };
-  i::Handle<i::Object> b;
-  has_pending_exception = !i::Execution::Call(
-      isolate,
-      isolate->is_promise(),
-      isolate->factory()->undefined_value(),
-      arraysize(argv), argv,
-      false).ToHandle(&b);
-  EXCEPTION_BAILOUT_CHECK(isolate, false);
-  return b->BooleanValue();
+Local<Object> Array::CloneElementAt(uint32_t index) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(CloneElementAt(context, index), Object);
 }
 
 
-Local<Promise::Resolver> Promise::Resolver::New(Isolate* v8_isolate) {
-  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-  LOG_API(isolate, "Promise::Resolver::New");
-  ENTER_V8(isolate);
-  EXCEPTION_PREAMBLE(isolate);
+bool Value::IsPromise() const {
+  auto self = Utils::OpenHandle(this);
+  if (!self->IsJSObject()) return false;
+  auto js_object = i::Handle<i::JSObject>::cast(self);
+  // Promises can't have access checks.
+  if (js_object->map()->is_access_check_needed()) return false;
+  auto isolate = js_object->GetIsolate();
+  // TODO(dcarney): this should just be read from the symbol registry so as not
+  // to be context dependent.
+  auto key = isolate->promise_status();
+  // Shouldn't be possible to throw here.
+  return i::JSObject::HasRealNamedProperty(js_object, key).FromJust();
+}
+
+
+MaybeLocal<Promise::Resolver> Promise::Resolver::New(Local<Context> context) {
+  PREPARE_FOR_EXECUTION(context, "Promise::Resolver::New", Resolver);
   i::Handle<i::Object> result;
   has_pending_exception = !i::Execution::Call(
       isolate,
@@ -5960,8 +6241,14 @@ Local<Promise::Resolver> Promise::Resolver::New(Isolate* v8_isolate) {
       isolate->factory()->undefined_value(),
       0, NULL,
       false).ToHandle(&result);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<Promise::Resolver>());
-  return Local<Promise::Resolver>::Cast(Utils::ToLocal(result));
+  RETURN_ON_FAILED_EXECUTION(Promise::Resolver);
+  RETURN_ESCAPED(Local<Promise::Resolver>::Cast(Utils::ToLocal(result)));
+}
+
+
+Local<Promise::Resolver> Promise::Resolver::New(Isolate* isolate) {
+  RETURN_TO_LOCAL_UNCHECKED(New(isolate->GetCurrentContext()),
+                            Promise::Resolver);
 }
 
 
@@ -5971,94 +6258,107 @@ Local<Promise> Promise::Resolver::GetPromise() {
 }
 
 
-void Promise::Resolver::Resolve(Handle<Value> value) {
-  i::Handle<i::JSObject> promise = Utils::OpenHandle(this);
-  i::Isolate* isolate = promise->GetIsolate();
-  LOG_API(isolate, "Promise::Resolver::Resolve");
-  ENTER_V8(isolate);
-  EXCEPTION_PREAMBLE(isolate);
-  i::Handle<i::Object> argv[] = { promise, Utils::OpenHandle(*value) };
+Maybe<bool> Promise::Resolver::Resolve(Local<Context> context,
+                                       Handle<Value> value) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Promise::Resolver::Resolve", bool);
+  auto self = Utils::OpenHandle(this);
+  i::Handle<i::Object> argv[] = {self, Utils::OpenHandle(*value)};
   has_pending_exception = i::Execution::Call(
       isolate,
       isolate->promise_resolve(),
       isolate->factory()->undefined_value(),
       arraysize(argv), argv,
       false).is_null();
-  EXCEPTION_BAILOUT_CHECK(isolate, /* void */ ;);
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return Just(true);
 }
 
 
-void Promise::Resolver::Reject(Handle<Value> value) {
-  i::Handle<i::JSObject> promise = Utils::OpenHandle(this);
-  i::Isolate* isolate = promise->GetIsolate();
-  LOG_API(isolate, "Promise::Resolver::Reject");
-  ENTER_V8(isolate);
-  EXCEPTION_PREAMBLE(isolate);
-  i::Handle<i::Object> argv[] = { promise, Utils::OpenHandle(*value) };
+void Promise::Resolver::Resolve(Handle<Value> value) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  Resolve(context, value);
+}
+
+
+Maybe<bool> Promise::Resolver::Reject(Local<Context> context,
+                                      Handle<Value> value) {
+  PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Promise::Resolver::Resolve", bool);
+  auto self = Utils::OpenHandle(this);
+  i::Handle<i::Object> argv[] = {self, Utils::OpenHandle(*value)};
   has_pending_exception = i::Execution::Call(
       isolate,
       isolate->promise_reject(),
       isolate->factory()->undefined_value(),
       arraysize(argv), argv,
       false).is_null();
-  EXCEPTION_BAILOUT_CHECK(isolate, /* void */ ;);
+  RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+  return Just(true);
+}
+
+
+void Promise::Resolver::Reject(Handle<Value> value) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  Reject(context, value);
+}
+
+
+MaybeLocal<Promise> Promise::Chain(Local<Context> context,
+                                   Handle<Function> handler) {
+  PREPARE_FOR_EXECUTION(context, "Promise::Chain", Promise);
+  auto self = Utils::OpenHandle(this);
+  i::Handle<i::Object> argv[] = {Utils::OpenHandle(*handler)};
+  i::Handle<i::Object> result;
+  has_pending_exception =
+      !i::Execution::Call(isolate, isolate->promise_chain(), self,
+                          arraysize(argv), argv, false).ToHandle(&result);
+  RETURN_ON_FAILED_EXECUTION(Promise);
+  RETURN_ESCAPED(Local<Promise>::Cast(Utils::ToLocal(result)));
 }
 
 
 Local<Promise> Promise::Chain(Handle<Function> handler) {
-  i::Handle<i::JSObject> promise = Utils::OpenHandle(this);
-  i::Isolate* isolate = promise->GetIsolate();
-  LOG_API(isolate, "Promise::Chain");
-  ENTER_V8(isolate);
-  EXCEPTION_PREAMBLE(isolate);
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(Chain(context, handler), Promise);
+}
+
+
+MaybeLocal<Promise> Promise::Catch(Local<Context> context,
+                                   Handle<Function> handler) {
+  PREPARE_FOR_EXECUTION(context, "Promise::Catch", Promise);
+  auto self = Utils::OpenHandle(this);
   i::Handle<i::Object> argv[] = { Utils::OpenHandle(*handler) };
   i::Handle<i::Object> result;
-  has_pending_exception = !i::Execution::Call(
-      isolate,
-      isolate->promise_chain(),
-      promise,
-      arraysize(argv), argv,
-      false).ToHandle(&result);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<Promise>());
-  return Local<Promise>::Cast(Utils::ToLocal(result));
+  has_pending_exception =
+      !i::Execution::Call(isolate, isolate->promise_catch(), self,
+                          arraysize(argv), argv, false).ToHandle(&result);
+  RETURN_ON_FAILED_EXECUTION(Promise);
+  RETURN_ESCAPED(Local<Promise>::Cast(Utils::ToLocal(result)));
 }
 
 
 Local<Promise> Promise::Catch(Handle<Function> handler) {
-  i::Handle<i::JSObject> promise = Utils::OpenHandle(this);
-  i::Isolate* isolate = promise->GetIsolate();
-  LOG_API(isolate, "Promise::Catch");
-  ENTER_V8(isolate);
-  EXCEPTION_PREAMBLE(isolate);
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(Catch(context, handler), Promise);
+}
+
+
+MaybeLocal<Promise> Promise::Then(Local<Context> context,
+                                  Handle<Function> handler) {
+  PREPARE_FOR_EXECUTION(context, "Promise::Then", Promise);
+  auto self = Utils::OpenHandle(this);
   i::Handle<i::Object> argv[] = { Utils::OpenHandle(*handler) };
   i::Handle<i::Object> result;
-  has_pending_exception = !i::Execution::Call(
-      isolate,
-      isolate->promise_catch(),
-      promise,
-      arraysize(argv), argv,
-      false).ToHandle(&result);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<Promise>());
-  return Local<Promise>::Cast(Utils::ToLocal(result));
+  has_pending_exception =
+      !i::Execution::Call(isolate, isolate->promise_then(), self,
+                          arraysize(argv), argv, false).ToHandle(&result);
+  RETURN_ON_FAILED_EXECUTION(Promise);
+  RETURN_ESCAPED(Local<Promise>::Cast(Utils::ToLocal(result)));
 }
 
 
 Local<Promise> Promise::Then(Handle<Function> handler) {
-  i::Handle<i::JSObject> promise = Utils::OpenHandle(this);
-  i::Isolate* isolate = promise->GetIsolate();
-  LOG_API(isolate, "Promise::Then");
-  ENTER_V8(isolate);
-  EXCEPTION_PREAMBLE(isolate);
-  i::Handle<i::Object> argv[] = { Utils::OpenHandle(*handler) };
-  i::Handle<i::Object> result;
-  has_pending_exception = !i::Execution::Call(
-      isolate,
-      isolate->promise_then(),
-      promise,
-      arraysize(argv), argv,
-      false).ToHandle(&result);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<Promise>());
-  return Local<Promise>::Cast(Utils::ToLocal(result));
+  auto context = ContextFromHeapObject(Utils::OpenHandle(this));
+  RETURN_TO_LOCAL_UNCHECKED(Then(context, handler), Promise);
 }
 
 
@@ -6083,14 +6383,19 @@ bool v8::ArrayBuffer::IsNeuterable() const {
 
 
 v8::ArrayBuffer::Contents v8::ArrayBuffer::Externalize() {
-  i::Handle<i::JSArrayBuffer> obj = Utils::OpenHandle(this);
-  Utils::ApiCheck(!obj->is_external(),
-                  "v8::ArrayBuffer::Externalize",
+  i::Handle<i::JSArrayBuffer> self = Utils::OpenHandle(this);
+  Utils::ApiCheck(!self->is_external(), "v8::ArrayBuffer::Externalize",
                   "ArrayBuffer already externalized");
-  obj->set_is_external(true);
-  size_t byte_length = static_cast<size_t>(obj->byte_length()->Number());
+  self->set_is_external(true);
+  return GetContents();
+}
+
+
+v8::ArrayBuffer::Contents v8::ArrayBuffer::GetContents() {
+  i::Handle<i::JSArrayBuffer> self = Utils::OpenHandle(this);
+  size_t byte_length = static_cast<size_t>(self->byte_length()->Number());
   Contents contents;
-  contents.data_ = obj->backing_store();
+  contents.data_ = self->backing_store();
   contents.byte_length_ = byte_length;
   return contents;
 }
@@ -6128,13 +6433,16 @@ Local<ArrayBuffer> v8::ArrayBuffer::New(Isolate* isolate, size_t byte_length) {
 
 
 Local<ArrayBuffer> v8::ArrayBuffer::New(Isolate* isolate, void* data,
-                                        size_t byte_length) {
+                                        size_t byte_length,
+                                        ArrayBufferCreationMode mode) {
   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   LOG_API(i_isolate, "v8::ArrayBuffer::New(void*, size_t)");
   ENTER_V8(i_isolate);
   i::Handle<i::JSArrayBuffer> obj =
       i_isolate->factory()->NewJSArrayBuffer();
-  i::Runtime::SetupArrayBuffer(i_isolate, obj, true, data, byte_length);
+  i::Runtime::SetupArrayBuffer(i_isolate, obj,
+                               mode == ArrayBufferCreationMode::kExternalized,
+                               data, byte_length);
   return Utils::ToLocal(obj);
 }
 
@@ -6154,6 +6462,48 @@ Local<ArrayBuffer> v8::ArrayBufferView::Buffer() {
 }
 
 
+size_t v8::ArrayBufferView::CopyContents(void* dest, size_t byte_length) {
+  i::Handle<i::JSArrayBufferView> obj = Utils::OpenHandle(this);
+  i::Isolate* isolate = obj->GetIsolate();
+  size_t byte_offset = i::NumberToSize(isolate, obj->byte_offset());
+  size_t bytes_to_copy =
+      i::Min(byte_length, i::NumberToSize(isolate, obj->byte_length()));
+  if (bytes_to_copy) {
+    i::DisallowHeapAllocation no_gc;
+    const char* source = nullptr;
+    if (obj->IsJSDataView()) {
+      i::Handle<i::JSDataView> data_view(i::JSDataView::cast(*obj));
+      i::Handle<i::JSArrayBuffer> buffer(
+          i::JSArrayBuffer::cast(data_view->buffer()));
+      source = reinterpret_cast<char*>(buffer->backing_store());
+    } else {
+      DCHECK(obj->IsJSTypedArray());
+      i::Handle<i::JSTypedArray> typed_array(i::JSTypedArray::cast(*obj));
+      if (typed_array->buffer()->IsSmi()) {
+        i::Handle<i::FixedTypedArrayBase> fixed_array(
+            i::FixedTypedArrayBase::cast(typed_array->elements()));
+        source = reinterpret_cast<char*>(fixed_array->DataPtr());
+      } else {
+        i::Handle<i::JSArrayBuffer> buffer(
+            i::JSArrayBuffer::cast(typed_array->buffer()));
+        source = reinterpret_cast<char*>(buffer->backing_store());
+      }
+    }
+    memcpy(dest, source + byte_offset, bytes_to_copy);
+  }
+  return bytes_to_copy;
+}
+
+
+bool v8::ArrayBufferView::HasBuffer() const {
+  i::Handle<i::JSArrayBufferView> obj = Utils::OpenHandle(this);
+  if (obj->IsJSDataView()) return true;
+  DCHECK(obj->IsJSTypedArray());
+  i::Handle<i::JSTypedArray> typed_array(i::JSTypedArray::cast(*obj));
+  return !typed_array->buffer()->IsSmi();
+}
+
+
 size_t v8::ArrayBufferView::ByteOffset() {
   i::Handle<i::JSArrayBufferView> obj = Utils::OpenHandle(this);
   return static_cast<size_t>(obj->byte_offset()->Number());
@@ -6518,10 +6868,6 @@ void Isolate::RequestInterrupt(InterruptCallback callback, void* data) {
 }
 
 
-void Isolate::ClearInterrupt() {
-}
-
-
 void Isolate::RequestGarbageCollectionForTesting(GarbageCollectionType type) {
   CHECK(i::FLAG_expose_gc);
   if (type == kMinorGarbageCollection) {
@@ -6544,8 +6890,13 @@ Isolate* Isolate::GetCurrent() {
 
 
 Isolate* Isolate::New(const Isolate::CreateParams& params) {
-  i::Isolate* isolate = new i::Isolate(params.enable_serializer);
+  i::Isolate* isolate = new i::Isolate(false);
   Isolate* v8_isolate = reinterpret_cast<Isolate*>(isolate);
+  if (params.snapshot_blob != NULL) {
+    isolate->set_snapshot_blob(params.snapshot_blob);
+  } else {
+    isolate->set_snapshot_blob(i::Snapshot::DefaultSnapshotBlob());
+  }
   if (params.entry_hook) {
     isolate->set_function_entry_hook(params.entry_hook);
   }
@@ -6554,12 +6905,30 @@ Isolate* Isolate::New(const Isolate::CreateParams& params) {
     isolate->logger()->SetCodeEventHandler(kJitCodeEventDefault,
                                            params.code_event_handler);
   }
+  if (params.counter_lookup_callback) {
+    v8_isolate->SetCounterFunction(params.counter_lookup_callback);
+  }
+
+  if (params.create_histogram_callback) {
+    v8_isolate->SetCreateHistogramFunction(params.create_histogram_callback);
+  }
+
+  if (params.add_histogram_sample_callback) {
+    v8_isolate->SetAddHistogramSampleFunction(
+        params.add_histogram_sample_callback);
+  }
   SetResourceConstraints(isolate, params.constraints);
   // 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)) {
     // If the isolate has a function entry hook, it needs to re-build all its
     // code stubs with entry hooks embedded, so don't deserialize a snapshot.
+    if (i::Snapshot::EmbedsScript(isolate)) {
+      // If the snapshot embeds a script, we cannot initialize the isolate
+      // without the snapshot as a fallback. This is unlikely to happen though.
+      V8_Fatal(__FILE__, __LINE__,
+               "Initializing isolate from custom startup snapshot failed");
+    }
     isolate->Init(NULL);
   }
   return v8_isolate;
@@ -6835,7 +7204,6 @@ bool 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());
@@ -6850,7 +7218,6 @@ bool Isolate::AddMessageListener(MessageCallback that, Handle<Value> data) {
 
 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());
@@ -6968,21 +7335,12 @@ String::Value::~Value() {
   Local<Value> Exception::NAME(v8::Handle<v8::String> raw_message) {          \
     i::Isolate* isolate = i::Isolate::Current();                              \
     LOG_API(isolate, #NAME);                                                  \
-    ON_BAILOUT(isolate, "v8::Exception::" #NAME "()", return Local<Value>()); \
     ENTER_V8(isolate);                                                        \
     i::Object* error;                                                         \
     {                                                                         \
       i::HandleScope scope(isolate);                                          \
       i::Handle<i::String> message = Utils::OpenHandle(*raw_message);         \
-      i::Handle<i::Object> result;                                            \
-      EXCEPTION_PREAMBLE(isolate);                                            \
-      i::MaybeHandle<i::Object> maybe_result =                                \
-          isolate->factory()->New##NAME(message);                             \
-      has_pending_exception = !maybe_result.ToHandle(&result);                \
-      /* TODO(yangguo): crbug/403509. Return empty handle instead. */         \
-      EXCEPTION_BAILOUT_CHECK(                                                \
-          isolate, v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate)));   \
-      error = *result;                                                        \
+      error = *isolate->factory()->New##NAME(message);                        \
     }                                                                         \
     i::Handle<i::Object> result(error, isolate);                              \
     return Utils::ToLocal(result);                                            \
@@ -7022,7 +7380,6 @@ Local<StackTrace> Exception::GetStackTrace(Handle<Value> exception) {
 
 bool Debug::SetDebugEventListener(EventCallback that, Handle<Value> data) {
   i::Isolate* isolate = i::Isolate::Current();
-  ON_BAILOUT(isolate, "v8::Debug::SetDebugEventListener()", return false);
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
   i::Handle<i::Object> foreign = isolate->factory()->undefined_value();
@@ -7075,52 +7432,54 @@ void Debug::SendCommand(Isolate* isolate,
 }
 
 
-Local<Value> Debug::Call(v8::Handle<v8::Function> fun,
-                         v8::Handle<v8::Value> data) {
-  i::Isolate* isolate = i::Isolate::Current();
-  ON_BAILOUT(isolate, "v8::Debug::Call()", return Local<Value>());
-  ENTER_V8(isolate);
-  i::MaybeHandle<i::Object> maybe_result;
-  EXCEPTION_PREAMBLE(isolate);
+MaybeLocal<Value> Debug::Call(Local<Context> context,
+                              v8::Handle<v8::Function> fun,
+                              v8::Handle<v8::Value> data) {
+  PREPARE_FOR_EXECUTION(context, "v8::Debug::Call()", Value);
+  i::Handle<i::Object> data_obj;
   if (data.IsEmpty()) {
-    maybe_result = isolate->debug()->Call(
-        Utils::OpenHandle(*fun), isolate->factory()->undefined_value());
+    data_obj = isolate->factory()->undefined_value();
   } else {
-    maybe_result = isolate->debug()->Call(
-        Utils::OpenHandle(*fun), Utils::OpenHandle(*data));
+    data_obj = Utils::OpenHandle(*data);
   }
-  i::Handle<i::Object> result;
-  has_pending_exception = !maybe_result.ToHandle(&result);
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
-  return Utils::ToLocal(result);
+  Local<Value> result;
+  has_pending_exception =
+      !ToLocal<Value>(isolate->debug()->Call(Utils::OpenHandle(*fun), data_obj),
+                      &result);
+  RETURN_ON_FAILED_EXECUTION(Value);
+  RETURN_ESCAPED(result);
 }
 
 
-Local<Value> Debug::GetMirror(v8::Handle<v8::Value> obj) {
-  i::Isolate* isolate = i::Isolate::Current();
-  ON_BAILOUT(isolate, "v8::Debug::GetMirror()", return Local<Value>());
-  ENTER_V8(isolate);
-  v8::EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
+Local<Value> Debug::Call(v8::Handle<v8::Function> fun,
+                         v8::Handle<v8::Value> data) {
+  auto context = ContextFromHeapObject(Utils::OpenHandle(*fun));
+  RETURN_TO_LOCAL_UNCHECKED(Call(context, fun, data), Value);
+}
+
+
+MaybeLocal<Value> Debug::GetMirror(Local<Context> context,
+                                   v8::Handle<v8::Value> obj) {
+  PREPARE_FOR_EXECUTION(context, "v8::Debug::GetMirror()", Value);
   i::Debug* isolate_debug = isolate->debug();
-  EXCEPTION_PREAMBLE(isolate);
   has_pending_exception = !isolate_debug->Load();
-  v8::Local<v8::Value> result;
-  if (!has_pending_exception) {
-    i::Handle<i::JSObject> debug(
-        isolate_debug->debug_context()->global_object());
-    i::Handle<i::String> name = isolate->factory()->InternalizeOneByteString(
-        STATIC_CHAR_VECTOR("MakeMirror"));
-    i::Handle<i::Object> fun_obj =
-        i::Object::GetProperty(debug, name).ToHandleChecked();
-    i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(fun_obj);
-    v8::Handle<v8::Function> v8_fun = Utils::ToLocal(fun);
-    const int kArgc = 1;
-    v8::Handle<v8::Value> argv[kArgc] = { obj };
-    result = v8_fun->Call(Utils::ToLocal(debug), kArgc, argv);
-    has_pending_exception = result.IsEmpty();
-  }
-  EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
-  return scope.Escape(result);
+  RETURN_ON_FAILED_EXECUTION(Value);
+  i::Handle<i::JSObject> debug(isolate_debug->debug_context()->global_object());
+  auto name = isolate->factory()->NewStringFromStaticChars("MakeMirror");
+  auto fun_obj = i::Object::GetProperty(debug, name).ToHandleChecked();
+  auto v8_fun = Utils::ToLocal(i::Handle<i::JSFunction>::cast(fun_obj));
+  const int kArgc = 1;
+  v8::Handle<v8::Value> argv[kArgc] = {obj};
+  Local<Value> result;
+  has_pending_exception = !v8_fun->Call(context, Utils::ToLocal(debug), kArgc,
+                                        argv).ToLocal(&result);
+  RETURN_ON_FAILED_EXECUTION(Value);
+  RETURN_ESCAPED(result);
+}
+
+
+Local<Value> Debug::GetMirror(v8::Handle<v8::Value> obj) {
+  RETURN_TO_LOCAL_UNCHECKED(GetMirror(Local<Context>(), obj), Value);
 }
 
 
@@ -7211,7 +7570,7 @@ unsigned CpuProfileNode::GetHitCount() const {
 
 
 unsigned CpuProfileNode::GetCallUid() const {
-  return reinterpret_cast<const i::ProfileNode*>(this)->entry()->GetCallUid();
+  return reinterpret_cast<const i::ProfileNode*>(this)->function_id();
 }
 
 
@@ -7297,11 +7656,6 @@ void CpuProfiler::StartProfiling(Handle<String> title, bool record_samples) {
 }
 
 
-void CpuProfiler::StartCpuProfiling(Handle<String> title, bool record_samples) {
-  StartProfiling(title, record_samples);
-}
-
-
 CpuProfile* CpuProfiler::StopProfiling(Handle<String> title) {
   return reinterpret_cast<CpuProfile*>(
       reinterpret_cast<i::CpuProfiler*>(this)->StopProfiling(
@@ -7309,11 +7663,6 @@ CpuProfile* CpuProfiler::StopProfiling(Handle<String> title) {
 }
 
 
-const CpuProfile* CpuProfiler::StopCpuProfiling(Handle<String> title) {
-  return StopProfiling(title);
-}
-
-
 void CpuProfiler::SetIdle(bool is_idle) {
   i::Isolate* isolate = reinterpret_cast<i::CpuProfiler*>(this)->isolate();
   v8::StateTag state = isolate->current_vm_state();
@@ -7394,13 +7743,6 @@ SnapshotObjectId HeapGraphNode::GetId() const {
 }
 
 
-int HeapGraphNode::GetSelfSize() const {
-  size_t size = ToInternal(this)->self_size();
-  CHECK(size <= static_cast<size_t>(internal::kMaxInt));
-  return static_cast<int>(size);
-}
-
-
 size_t HeapGraphNode::GetShallowSize() const {
   return ToInternal(this)->self_size();
 }
@@ -7434,18 +7776,6 @@ void HeapSnapshot::Delete() {
 }
 
 
-unsigned HeapSnapshot::GetUid() const {
-  return ToInternal(this)->uid();
-}
-
-
-Handle<String> HeapSnapshot::GetTitle() const {
-  i::Isolate* isolate = i::Isolate::Current();
-  return ToApiHandle<String>(
-      isolate->factory()->InternalizeUtf8String(ToInternal(this)->title()));
-}
-
-
 const HeapGraphNode* HeapSnapshot::GetRoot() const {
   return reinterpret_cast<const HeapGraphNode*>(ToInternal(this)->root());
 }
@@ -7522,12 +7852,10 @@ void HeapProfiler::ClearObjectIds() {
 
 
 const HeapSnapshot* HeapProfiler::TakeHeapSnapshot(
-    Handle<String> title,
-    ActivityControl* control,
-    ObjectNameResolver* resolver) {
+    ActivityControl* control, ObjectNameResolver* resolver) {
   return reinterpret_cast<const HeapSnapshot*>(
-      reinterpret_cast<i::HeapProfiler*>(this)->TakeSnapshot(
-          *Utils::OpenHandle(*title), control, resolver));
+      reinterpret_cast<i::HeapProfiler*>(this)
+          ->TakeSnapshot(control, resolver));
 }
 
 
@@ -7542,8 +7870,10 @@ void HeapProfiler::StopTrackingHeapObjects() {
 }
 
 
-SnapshotObjectId HeapProfiler::GetHeapStats(OutputStream* stream) {
-  return reinterpret_cast<i::HeapProfiler*>(this)->PushHeapObjectsStats(stream);
+SnapshotObjectId HeapProfiler::GetHeapStats(OutputStream* stream,
+                                            int64_t* timestamp_us) {
+  i::HeapProfiler* heap_profiler = reinterpret_cast<i::HeapProfiler*>(this);
+  return heap_profiler->PushHeapObjectsStats(stream, timestamp_us);
 }
 
 
index d9e3bba..7fce3e3 100644 (file)
@@ -319,6 +319,18 @@ inline v8::Local<T> ToApiHandle(
 }
 
 
+template <class T>
+inline bool ToLocal(v8::internal::MaybeHandle<v8::internal::Object> maybe,
+                    Local<T>* local) {
+  v8::internal::Handle<v8::internal::Object> handle;
+  if (maybe.ToHandle(&handle)) {
+    *local = Utils::Convert<v8::internal::Object, T>(handle);
+    return true;
+  }
+  return false;
+}
+
+
 // Implementations of ToLocal
 
 #define MAKE_TO_LOCAL(Name, From, To)                                       \
index 876cd3d..0b5ced5 100644 (file)
@@ -121,7 +121,7 @@ Address RelocInfo::target_address_address() {
   if (FLAG_enable_ool_constant_pool ||
       Assembler::IsMovW(Memory::int32_at(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.
+    // serializer and expects the address to reside within the code object.
     return reinterpret_cast<Address>(pc_);
   } else {
     DCHECK(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc_)));
@@ -184,12 +184,24 @@ void RelocInfo::set_target_object(Object* target,
 }
 
 
-Address RelocInfo::target_reference() {
+Address RelocInfo::target_external_reference() {
   DCHECK(rmode_ == EXTERNAL_REFERENCE);
   return Assembler::target_address_at(pc_, host_);
 }
 
 
+Address RelocInfo::target_internal_reference() {
+  DCHECK(rmode_ == INTERNAL_REFERENCE);
+  return Memory::Address_at(pc_);
+}
+
+
+Address RelocInfo::target_internal_reference_address() {
+  DCHECK(rmode_ == INTERNAL_REFERENCE);
+  return reinterpret_cast<Address>(pc_);
+}
+
+
 Address RelocInfo::target_runtime_entry(Assembler* origin) {
   DCHECK(IsRuntimeEntry(rmode_));
   return target_address();
@@ -298,11 +310,14 @@ Object** RelocInfo::call_object_address() {
 
 
 void RelocInfo::WipeOut() {
-  DCHECK(IsEmbeddedObject(rmode_) ||
-         IsCodeTarget(rmode_) ||
-         IsRuntimeEntry(rmode_) ||
-         IsExternalReference(rmode_));
-  Assembler::set_target_address_at(pc_, host_, NULL);
+  DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
+         IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
+         IsInternalReference(rmode_));
+  if (IsInternalReference(rmode_)) {
+    Memory::Address_at(pc_) = NULL;
+  } else {
+    Assembler::set_target_address_at(pc_, host_, NULL);
+  }
 }
 
 
@@ -333,6 +348,8 @@ void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
     visitor->VisitCell(this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     visitor->VisitExternalReference(this);
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
+    visitor->VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     visitor->VisitCodeAgeSequence(this);
   } else if (((RelocInfo::IsJSReturn(mode) &&
@@ -358,6 +375,8 @@ void RelocInfo::Visit(Heap* heap) {
     StaticVisitor::VisitCell(heap, this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     StaticVisitor::VisitExternalReference(this);
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
+    StaticVisitor::VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     StaticVisitor::VisitCodeAgeSequence(heap, this);
   } else if (heap->isolate()->debug()->has_break_points() &&
@@ -534,6 +553,12 @@ void Assembler::deserialization_set_special_target_at(
 }
 
 
+void Assembler::deserialization_set_target_internal_reference_at(
+    Address pc, Address target, RelocInfo::Mode mode) {
+  Memory::Address_at(pc) = target;
+}
+
+
 bool Assembler::is_constant_pool_load(Address pc) {
   if (CpuFeatures::IsSupported(ARMv7)) {
     return !Assembler::IsMovW(Memory::int32_at(pc)) ||
index 7a091d0..2e300da 100644 (file)
@@ -42,7 +42,6 @@
 #include "src/base/bits.h"
 #include "src/base/cpu.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
 
 namespace v8 {
 namespace internal {
@@ -246,27 +245,6 @@ bool RelocInfo::IsInConstantPool() {
 }
 
 
-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-arm-inl.h for inlined constructors
@@ -1011,7 +989,7 @@ static bool fits_shifter(uint32_t imm32,
                          Instr* instr) {
   // imm32 must be unsigned.
   for (int rot = 0; rot < 16; rot++) {
-    uint32_t imm8 = (imm32 << 2*rot) | (imm32 >> (32 - 2*rot));
+    uint32_t imm8 = base::bits::RotateLeft32(imm32, 2 * rot);
     if ((imm8 <= 0xff)) {
       *rotate_imm = rot;
       *immed_8 = imm8;
@@ -3324,7 +3302,7 @@ Instr Assembler::PatchMovwImmediate(Instr instruction, uint32_t immediate) {
 int Assembler::DecodeShiftImm(Instr instr) {
   int rotate = Instruction::RotateValue(instr) * 2;
   int immed8 = Instruction::Immed8Value(instr);
-  return (immed8 >> rotate) | (immed8 << (32 - rotate));
+  return base::bits::RotateRight32(immed8, rotate);
 }
 
 
index 7d1e0bd..fb02740 100644 (file)
@@ -45,7 +45,7 @@
 
 #include "src/arm/constants-arm.h"
 #include "src/assembler.h"
-#include "src/serialize.h"
+#include "src/compiler.h"
 
 namespace v8 {
 namespace internal {
@@ -794,6 +794,11 @@ class Assembler : public AssemblerBase {
   inline static void deserialization_set_special_target_at(
       Address constant_pool_entry, Code* code, Address target);
 
+  // This sets the internal reference at the pc.
+  inline static void deserialization_set_target_internal_reference_at(
+      Address pc, Address target,
+      RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
+
   // Here we are patching the address in the constant pool, not the actual call
   // instruction.  The address in the constant pool is the same size as a
   // pointer.
@@ -823,6 +828,8 @@ class Assembler : public AssemblerBase {
   static const int kPcLoadDelta = 8;
 
   static const int kJSReturnSequenceInstructions = 4;
+  static const int kJSReturnSequenceLength =
+      kJSReturnSequenceInstructions * kInstrSize;
   static const int kDebugBreakSlotInstructions = 3;
   static const int kDebugBreakSlotLength =
       kDebugBreakSlotInstructions * kInstrSize;
@@ -1400,7 +1407,7 @@ class Assembler : public AssemblerBase {
 
   // Record a deoptimization reason that can be used by a log or cpu profiler.
   // Use --trace-deopt to enable.
-  void RecordDeoptReason(const int reason, const int raw_position);
+  void RecordDeoptReason(const int reason, const SourcePosition position);
 
   // Record the emission of a constant pool.
   //
index d13d4ff..40531ca 100644 (file)
@@ -929,7 +929,9 @@ static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
   // Push function as parameter to the runtime call.
   __ Push(r1);
   // Whether to compile in a background thread.
-  __ Push(masm->isolate()->factory()->ToBoolean(concurrent));
+  __ LoadRoot(
+      ip, concurrent ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex);
+  __ push(ip);
 
   __ CallRuntime(Runtime::kCompileOptimized, 2);
   // Restore receiver.
@@ -1334,50 +1336,99 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
 }
 
 
-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;
+static void Generate_CheckStackOverflow(MacroAssembler* masm,
+                                        const int calleeOffset) {
+  // 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(r2, Heap::kRealStackLimitRootIndex);
+  // Make r2 the space we have left. The stack might already be overflowed
+  // here which will cause r2 to become negative.
+  __ sub(r2, sp, r2);
+  // Check if the arguments will overflow the stack.
+  __ cmp(r2, Operand::PointerOffsetFromSmiKey(r0));
+  __ b(gt, &okay);  // Signed comparison.
+
+  // Out of stack space.
+  __ ldr(r1, MemOperand(fp, calleeOffset));
+  __ Push(r1, r0);
+  __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+
+  __ bind(&okay);
+}
+
+
+static void Generate_PushAppliedArguments(MacroAssembler* masm,
+                                          const int argumentsOffset,
+                                          const int indexOffset,
+                                          const int limitOffset) {
+  Label entry, loop;
+  __ ldr(r0, MemOperand(fp, indexOffset));
+  __ b(&entry);
+
+  // Load the current argument from the arguments array and push it to the
+  // stack.
+  // r0: current argument index
+  __ bind(&loop);
+  __ ldr(r1, MemOperand(fp, argumentsOffset));
+  __ Push(r1, r0);
+
+  // Call the runtime to access the property in the arguments array.
+  __ CallRuntime(Runtime::kGetProperty, 2);
+  __ push(r0);
+
+  // Use inline caching to access the arguments.
+  __ ldr(r0, MemOperand(fp, indexOffset));
+  __ add(r0, r0, Operand(1 << kSmiTagSize));
+  __ str(r0, MemOperand(fp, indexOffset));
+
+  // Test if the copy loop has finished copying all the elements from the
+  // arguments object.
+  __ bind(&entry);
+  __ ldr(r1, MemOperand(fp, limitOffset));
+  __ cmp(r0, r1);
+  __ b(ne, &loop);
+
+  // On exit, the pushed arguments count is in r0, untagged
+  __ SmiUntag(r0);
+}
+
+
+// Used by FunctionApply and ReflectApply
+static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
+  const int kFormalParameters = targetIsArgument ? 3 : 2;
+  const int kStackSize = kFormalParameters + 1;
 
   {
     FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL);
+    const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize;
+    const int kReceiverOffset = kArgumentsOffset + kPointerSize;
+    const int kFunctionOffset = kReceiverOffset + kPointerSize;
 
     __ ldr(r0, MemOperand(fp, kFunctionOffset));  // get the function
     __ push(r0);
-    __ ldr(r0, MemOperand(fp, kArgsOffset));  // get the args array
+    __ ldr(r0, MemOperand(fp, kArgumentsOffset));  // get the args array
     __ push(r0);
-    __ 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(r2, Heap::kRealStackLimitRootIndex);
-    // Make r2 the space we have left. The stack might already be overflowed
-    // here which will cause r2 to become negative.
-    __ sub(r2, sp, r2);
-    // Check if the arguments will overflow the stack.
-    __ cmp(r2, Operand::PointerOffsetFromSmiKey(r0));
-    __ b(gt, &okay);  // Signed comparison.
-
-    // Out of stack space.
-    __ ldr(r1, MemOperand(fp, kFunctionOffset));
-    __ Push(r1, r0);
-    __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
-    // End of stack check.
+    if (targetIsArgument) {
+      __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION);
+    } else {
+      __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
+    }
+
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
 
     // Push current limit and index.
-    __ bind(&okay);
+    const int kIndexOffset =
+        StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
+    const int kLimitOffset =
+        StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
     __ push(r0);  // limit
     __ mov(r1, Operand::Zero());  // initial index
     __ push(r1);
 
     // Get the receiver.
-    __ ldr(r0, MemOperand(fp, kRecvOffset));
+    __ ldr(r0, MemOperand(fp, kReceiverOffset));
 
     // Check that the function is a JS function (otherwise it must be a proxy).
     Label push_receiver;
@@ -1434,44 +1485,19 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
     __ push(r0);
 
     // Copy all arguments from the array to the stack.
-    Label entry, loop;
-    __ ldr(r0, MemOperand(fp, kIndexOffset));
-    __ b(&entry);
-
-    // Load the current argument from the arguments array and push it to the
-    // stack.
-    // r0: current argument index
-    __ bind(&loop);
-    __ ldr(r1, MemOperand(fp, kArgsOffset));
-    __ Push(r1, r0);
-
-    // Call the runtime to access the property in the arguments array.
-    __ CallRuntime(Runtime::kGetProperty, 2);
-    __ push(r0);
-
-    // Use inline caching to access the arguments.
-    __ ldr(r0, MemOperand(fp, kIndexOffset));
-    __ add(r0, r0, Operand(1 << kSmiTagSize));
-    __ str(r0, MemOperand(fp, kIndexOffset));
-
-    // Test if the copy loop has finished copying all the elements from the
-    // arguments object.
-    __ bind(&entry);
-    __ ldr(r1, MemOperand(fp, kLimitOffset));
-    __ cmp(r0, r1);
-    __ b(ne, &loop);
+    Generate_PushAppliedArguments(
+        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
 
     // Call the function.
     Label call_proxy;
     ParameterCount actual(r0);
-    __ SmiUntag(r0);
     __ ldr(r1, MemOperand(fp, kFunctionOffset));
     __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
     __ b(ne, &call_proxy);
     __ InvokeFunction(r1, actual, CALL_FUNCTION, NullCallWrapper());
 
     frame_scope.GenerateLeaveFrame();
-    __ add(sp, sp, Operand(3 * kPointerSize));
+    __ add(sp, sp, Operand(kStackSize * kPointerSize));
     __ Jump(lr);
 
     // Call the function proxy.
@@ -1485,11 +1511,91 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
 
     // Tear down the internal frame and remove function, receiver and args.
   }
-  __ add(sp, sp, Operand(3 * kPointerSize));
+  __ add(sp, sp, Operand(kStackSize * kPointerSize));
   __ Jump(lr);
 }
 
 
+static void Generate_ConstructHelper(MacroAssembler* masm) {
+  const int kFormalParameters = 3;
+  const int kStackSize = kFormalParameters + 1;
+
+  {
+    FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL);
+    const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize;
+    const int kArgumentsOffset = kNewTargetOffset + kPointerSize;
+    const int kFunctionOffset = kArgumentsOffset + kPointerSize;
+
+    // If newTarget is not supplied, set it to constructor
+    Label validate_arguments;
+    __ ldr(r0, MemOperand(fp, kNewTargetOffset));
+    __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
+    __ b(ne, &validate_arguments);
+    __ ldr(r0, MemOperand(fp, kFunctionOffset));
+    __ str(r0, MemOperand(fp, kNewTargetOffset));
+
+    // Validate arguments
+    __ bind(&validate_arguments);
+    __ ldr(r0, MemOperand(fp, kFunctionOffset));  // get the function
+    __ push(r0);
+    __ ldr(r0, MemOperand(fp, kArgumentsOffset));  // get the args array
+    __ push(r0);
+    __ ldr(r0, MemOperand(fp, kNewTargetOffset));  // get the new.target
+    __ push(r0);
+    __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION);
+
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
+
+    // Push current limit and index.
+    const int kIndexOffset =
+        StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
+    const int kLimitOffset =
+        StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
+    __ push(r0);  // limit
+    __ mov(r1, Operand::Zero());  // initial index
+    __ push(r1);
+    // Push newTarget and callee functions
+    __ ldr(r0, MemOperand(fp, kNewTargetOffset));
+    __ push(r0);
+    __ ldr(r0, MemOperand(fp, kFunctionOffset));
+    __ push(r0);
+
+    // Copy all arguments from the array to the stack.
+    Generate_PushAppliedArguments(
+        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
+
+    // Use undefined feedback vector
+    __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
+    __ ldr(r1, MemOperand(fp, kFunctionOffset));
+
+    // Call the function.
+    CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
+    __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
+
+    __ Drop(1);
+
+    // Leave internal frame.
+  }
+  __ add(sp, sp, Operand(kStackSize * kPointerSize));
+  __ Jump(lr);
+}
+
+
+void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+  Generate_ApplyHelper(masm, false);
+}
+
+
+void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
+  Generate_ApplyHelper(masm, true);
+}
+
+
+void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
+  Generate_ConstructHelper(masm);
+}
+
+
 static void ArgumentAdaptorStackCheck(MacroAssembler* masm,
                                       Label* stack_overflow) {
   // ----------- S t a t e -------------
index 9188b58..52bc197 100644 (file)
@@ -12,6 +12,7 @@
 #include "src/codegen.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
@@ -1018,13 +1019,12 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   __ CompareRoot(r0, Heap::kExceptionRootIndex);
   __ b(eq, &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;
+    ExternalReference pending_exception_address(
+        Isolate::kPendingExceptionAddress, isolate());
     __ mov(r2, Operand(pending_exception_address));
     __ ldr(r2, MemOperand(r2));
     __ CompareRoot(r2, Heap::kTheHoleValueRootIndex);
@@ -1045,25 +1045,53 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // Handling of exception.
   __ bind(&exception_returned);
 
-  // Retrieve the pending exception.
-  __ mov(r2, Operand(pending_exception_address));
-  __ ldr(r0, MemOperand(r2));
-
-  // Clear the pending exception.
-  __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
-  __ str(r3, MemOperand(r2));
-
-  // Special handling of termination exceptions which are uncatchable
-  // by javascript code.
-  Label throw_termination_exception;
-  __ CompareRoot(r0, Heap::kTerminationExceptionRootIndex);
-  __ b(eq, &throw_termination_exception);
-
-  // Handle normal exception.
-  __ Throw(r0);
+  ExternalReference pending_handler_context_address(
+      Isolate::kPendingHandlerContextAddress, isolate());
+  ExternalReference pending_handler_code_address(
+      Isolate::kPendingHandlerCodeAddress, isolate());
+  ExternalReference pending_handler_offset_address(
+      Isolate::kPendingHandlerOffsetAddress, isolate());
+  ExternalReference pending_handler_fp_address(
+      Isolate::kPendingHandlerFPAddress, isolate());
+  ExternalReference pending_handler_sp_address(
+      Isolate::kPendingHandlerSPAddress, isolate());
+
+  // Ask the runtime for help to determine the handler. This will set r0 to
+  // contain the current pending exception, don't clobber it.
+  ExternalReference find_handler(Runtime::kFindExceptionHandler, isolate());
+  {
+    FrameScope scope(masm, StackFrame::MANUAL);
+    __ PrepareCallCFunction(3, 0, r0);
+    __ mov(r0, Operand(0));
+    __ mov(r1, Operand(0));
+    __ mov(r2, Operand(ExternalReference::isolate_address(isolate())));
+    __ CallCFunction(find_handler, 3);
+  }
 
-  __ bind(&throw_termination_exception);
-  __ ThrowUncatchable(r0);
+  // Retrieve the handler context, SP and FP.
+  __ mov(cp, Operand(pending_handler_context_address));
+  __ ldr(cp, MemOperand(cp));
+  __ mov(sp, Operand(pending_handler_sp_address));
+  __ ldr(sp, MemOperand(sp));
+  __ mov(fp, Operand(pending_handler_fp_address));
+  __ ldr(fp, MemOperand(fp));
+
+  // If the handler is a JS frame, restore the context to the frame. Note that
+  // the context will be set to (cp == 0) for non-JS frames.
+  __ cmp(cp, Operand(0));
+  __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
+
+  // Compute the handler entry address and jump to it.
+  ConstantPoolUnavailableScope constant_pool_unavailable(masm);
+  __ mov(r1, Operand(pending_handler_code_address));
+  __ ldr(r1, MemOperand(r1));
+  __ mov(r2, Operand(pending_handler_offset_address));
+  __ ldr(r2, MemOperand(r2));
+  if (FLAG_enable_ool_constant_pool) {
+    __ ldr(pp, FieldMemOperand(r1, Code::kConstantPoolOffset));
+  }
+  __ add(r1, r1, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ add(pc, r1, r2);
 }
 
 
@@ -1152,7 +1180,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
     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
+    // fp will be invalid because the PushStackHandler below sets it to 0 to
     // signal the existence of the JSEntry frame.
     __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
                                          isolate())));
@@ -1161,11 +1189,10 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ LoadRoot(r0, 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.
+  // Invoke: Link this frame into the handler chain.
   __ bind(&invoke);
   // Must preserve r0-r4, r5-r6 are available.
-  __ PushTryHandler(StackHandler::JS_ENTRY, 0);
+  __ PushStackHandler();
   // If an exception not caught by another handler occurs, this handler
   // returns control to the code after the bl(&invoke) above, which
   // restores all kCalleeSaved registers (including cp and fp) to their
@@ -1202,7 +1229,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ Call(ip);
 
   // Unlink this frame from the handler chain.
-  __ PopTryHandler();
+  __ PopStackHandler();
 
   __ bind(&exit);  // r0 holds result
   // Check if the current stack frame is marked as the outermost JS frame.
@@ -1479,7 +1506,7 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
   __ Ret();
 
   StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
+  char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&miss);
   PropertyAccessCompiler::TailCallBuiltin(
@@ -1819,8 +1846,12 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
   __ bind(&adaptor_frame);
   __ ldr(r1, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
   if (has_new_target()) {
+    __ cmp(r1, Operand(Smi::FromInt(0)));
+    Label skip_decrement;
+    __ b(eq, &skip_decrement);
     // Subtract 1 from smi-tagged arguments count.
     __ sub(r1, r1, Operand(2));
+    __ bind(&skip_decrement);
   }
   __ str(r1, MemOperand(sp, 0));
   __ add(r3, r2, Operand::PointerOffsetFromSmiKey(r1));
@@ -1930,7 +1961,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   // 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);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 #else  // V8_INTERPRETED_REGEXP
 
   // Stack frame on entry.
@@ -2200,18 +2231,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   __ cmp(r0, r1);
   __ b(eq, &runtime);
 
-  __ str(r1, MemOperand(r2, 0));  // Clear pending exception.
-
-  // Check if the exception is a termination. If so, throw as uncatchable.
-  __ CompareRoot(r0, Heap::kTerminationExceptionRootIndex);
-
-  Label termination_exception;
-  __ b(eq, &termination_exception);
-
-  __ Throw(r0);
-
-  __ bind(&termination_exception);
-  __ ThrowUncatchable(r0);
+  // For exception, throw the exception again.
+  __ TailCallRuntime(Runtime::kRegExpExecReThrow, 4, 1);
 
   __ bind(&failure);
   // For failure and exception return null.
@@ -2306,7 +2327,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
 
   // Do the runtime call to execute the regexp.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 
   // Deferred code for string handling.
   // (6) Not a long external string?  If yes, go to (8).
@@ -2883,7 +2904,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
 
 
 void StringCharCodeAtGenerator::GenerateSlow(
-    MacroAssembler* masm,
+    MacroAssembler* masm, EmbedMode embed_mode,
     const RuntimeCallHelper& call_helper) {
   __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
 
@@ -2896,8 +2917,13 @@ void StringCharCodeAtGenerator::GenerateSlow(
               index_not_number_,
               DONT_DO_SMI_CHECK);
   call_helper.BeforeCall(masm);
-  __ push(object_);
-  __ push(index_);  // Consumed by runtime conversion function.
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ Push(VectorLoadICDescriptor::VectorRegister(),
+            VectorLoadICDescriptor::SlotRegister(), object_, index_);
+  } else {
+    // index_ is consumed by runtime conversion function.
+    __ Push(object_, index_);
+  }
   if (index_flags_ == STRING_INDEX_IS_NUMBER) {
     __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
   } else {
@@ -2908,7 +2934,12 @@ void StringCharCodeAtGenerator::GenerateSlow(
   // Save the conversion result before the pop instructions below
   // have a chance to overwrite it.
   __ Move(index_, r0);
-  __ pop(object_);
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ Pop(VectorLoadICDescriptor::VectorRegister(),
+           VectorLoadICDescriptor::SlotRegister(), object_);
+  } else {
+    __ pop(object_);
+  }
   // Reload the instance type.
   __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
   __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
@@ -3221,7 +3252,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
 
   // Just jump to runtime to create the sub string.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kSubString, 3, 1);
+  __ TailCallRuntime(Runtime::kSubStringRT, 3, 1);
 
   __ bind(&single_char);
   // r0: original string
@@ -3408,7 +3439,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
   // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
   // tagged as a small integer.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+  __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
 }
 
 
@@ -3689,7 +3720,7 @@ void CompareICStub::GenerateStrings(MacroAssembler* masm) {
   if (equality) {
     __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
   } else {
-    __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+    __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
   }
 
   __ bind(&miss);
@@ -4298,15 +4329,15 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
 
 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorLoadStub stub(isolate(), state());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawLoadStub stub(isolate(), state());
+  stub.GenerateForTrampoline(masm);
 }
 
 
 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorKeyedLoadStub stub(isolate());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawKeyedLoadStub stub(isolate());
+  stub.GenerateForTrampoline(masm);
 }
 
 
@@ -4324,6 +4355,237 @@ void CallIC_ArrayTrampolineStub::Generate(MacroAssembler* masm) {
 }
 
 
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+                             Register key, Register vector, Register slot,
+                             Register feedback, Register scratch1,
+                             Register scratch2, Register scratch3,
+                             bool is_polymorphic, Label* miss) {
+  // feedback initially contains the feedback array
+  Label next_loop, prepare_next;
+  Label load_smi_map, compare_map;
+  Label start_polymorphic;
+
+  Register receiver_map = scratch1;
+  Register cached_map = scratch2;
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &load_smi_map);
+  __ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ bind(&compare_map);
+  __ ldr(cached_map,
+         FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+  __ ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ cmp(receiver_map, cached_map);
+  __ b(ne, &start_polymorphic);
+  // found, now call handler.
+  Register handler = feedback;
+  __ ldr(handler, FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+  __ add(pc, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+
+  Register length = scratch3;
+  __ bind(&start_polymorphic);
+  __ ldr(length, FieldMemOperand(feedback, FixedArray::kLengthOffset));
+  if (!is_polymorphic) {
+    // If the IC could be monomorphic we have to make sure we don't go past the
+    // end of the feedback array.
+    __ cmp(length, Operand(Smi::FromInt(2)));
+    __ b(eq, miss);
+  }
+
+  Register too_far = length;
+  Register pointer_reg = feedback;
+
+  // +-----+------+------+-----+-----+ ... ----+
+  // | map | len  | wm0  | h0  | wm1 |      hN |
+  // +-----+------+------+-----+-----+ ... ----+
+  //                 0      1     2        len-1
+  //                              ^              ^
+  //                              |              |
+  //                         pointer_reg      too_far
+  //                         aka feedback     scratch3
+  // also need receiver_map (aka scratch1)
+  // use cached_map (scratch2) to look in the weak map values.
+  __ add(too_far, feedback, Operand::PointerOffsetFromSmiKey(length));
+  __ add(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ add(pointer_reg, feedback,
+         Operand(FixedArray::OffsetOfElementAt(2) - kHeapObjectTag));
+
+  __ bind(&next_loop);
+  __ ldr(cached_map, MemOperand(pointer_reg));
+  __ ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ cmp(receiver_map, cached_map);
+  __ b(ne, &prepare_next);
+  __ ldr(handler, MemOperand(pointer_reg, kPointerSize));
+  __ add(pc, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+  __ bind(&prepare_next);
+  __ add(pointer_reg, pointer_reg, Operand(kPointerSize * 2));
+  __ cmp(pointer_reg, too_far);
+  __ b(lt, &next_loop);
+
+  // We exhausted our array of map handler pairs.
+  __ jmp(miss);
+
+  __ bind(&load_smi_map);
+  __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
+  __ jmp(&compare_map);
+}
+
+
+static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+                                  Register key, Register vector, Register slot,
+                                  Register weak_cell, Register scratch,
+                                  Label* miss) {
+  // feedback initially contains the feedback array
+  Label compare_smi_map;
+  Register receiver_map = scratch;
+  Register cached_map = weak_cell;
+
+  // Move the weak map into the weak_cell register.
+  __ ldr(cached_map, FieldMemOperand(weak_cell, WeakCell::kValueOffset));
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &compare_smi_map);
+  __ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ cmp(cached_map, receiver_map);
+  __ b(ne, miss);
+
+  Register handler = weak_cell;
+  __ add(handler, vector, Operand::PointerOffsetFromSmiKey(slot));
+  __ ldr(handler,
+         FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ add(pc, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+  // In microbenchmarks, it made sense to unroll this code so that the call to
+  // the handler is duplicated for a HeapObject receiver and a Smi receiver.
+  __ bind(&compare_smi_map);
+  __ CompareRoot(weak_cell, Heap::kHeapNumberMapRootIndex);
+  __ b(ne, miss);
+  __ add(handler, vector, Operand::PointerOffsetFromSmiKey(slot));
+  __ ldr(handler,
+         FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ add(pc, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // r1
+  Register name = VectorLoadICDescriptor::NameRegister();          // r2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // r3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // r0
+  Register feedback = r4;
+  Register scratch1 = r5;
+
+  __ add(feedback, vector, Operand::PointerOffsetFromSmiKey(slot));
+  __ ldr(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ ldr(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ CompareRoot(scratch1, Heap::kWeakCellMapRootIndex);
+  __ b(ne, &try_array);
+  HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback, scratch1,
+                        &miss);
+
+  // Is it a fixed array?
+  __ bind(&try_array);
+  __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex);
+  __ b(ne, &not_array);
+  HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, r8,
+                   r9, true, &miss);
+
+  __ bind(&not_array);
+  __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+  __ b(ne, &miss);
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, code_flags,
+                                               false, receiver, name, feedback,
+                                               scratch1, r8, r9);
+
+  __ bind(&miss);
+  LoadIC::GenerateMiss(masm);
+}
+
+
+void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // r1
+  Register key = VectorLoadICDescriptor::NameRegister();           // r2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // r3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // r0
+  Register feedback = r4;
+  Register scratch1 = r5;
+
+  __ add(feedback, vector, Operand::PointerOffsetFromSmiKey(slot));
+  __ ldr(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ ldr(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ CompareRoot(scratch1, Heap::kWeakCellMapRootIndex);
+  __ b(ne, &try_array);
+  HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, scratch1,
+                        &miss);
+
+  __ bind(&try_array);
+  // Is it a fixed array?
+  __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex);
+  __ b(ne, &not_array);
+
+  // We have a polymorphic element handler.
+  Label polymorphic, try_poly_name;
+  __ bind(&polymorphic);
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, r8,
+                   r9, true, &miss);
+
+  __ bind(&not_array);
+  // Is it generic?
+  __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+  __ b(ne, &try_poly_name);
+  Handle<Code> megamorphic_stub =
+      KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+  __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET);
+
+  __ bind(&try_poly_name);
+  // We might have a name in feedback, and a fixed array in the next slot.
+  __ cmp(key, feedback);
+  __ b(ne, &miss);
+  // If the name comparison succeeded, we know we have a fixed array with
+  // at least one map/handler pair.
+  __ add(feedback, vector, Operand::PointerOffsetFromSmiKey(slot));
+  __ ldr(feedback,
+         FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, r8,
+                   r9, false, &miss);
+
+  __ bind(&miss);
+  KeyedLoadIC::GenerateMiss(masm);
+}
+
+
 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
   if (masm->isolate()->function_entry_hook() != NULL) {
     ProfileEntryHookStub stub(masm->isolate());
@@ -4788,7 +5050,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
   }
 
   Label promote_scheduled_exception;
-  Label exception_handled;
   Label delete_allocated_handles;
   Label leave_exit_frame;
   Label return_value_loaded;
@@ -4810,15 +5071,8 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
   __ cmp(r5, ip);
   __ b(ne, &delete_allocated_handles);
 
-  // Check if the function scheduled an exception.
+  // Leave the API exit frame.
   __ bind(&leave_exit_frame);
-  __ LoadRoot(r4, Heap::kTheHoleValueRootIndex);
-  __ mov(ip, Operand(ExternalReference::scheduled_exception_address(isolate)));
-  __ ldr(r5, MemOperand(ip));
-  __ cmp(r4, r5);
-  __ b(ne, &promote_scheduled_exception);
-  __ bind(&exception_handled);
-
   bool restore_context = context_restore_operand != NULL;
   if (restore_context) {
     __ ldr(cp, *context_restore_operand);
@@ -4830,15 +5084,19 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
     __ mov(r4, Operand(stack_space));
   }
   __ LeaveExitFrame(false, r4, !restore_context, stack_space_operand != NULL);
+
+  // Check if the function scheduled an exception.
+  __ LoadRoot(r4, Heap::kTheHoleValueRootIndex);
+  __ mov(ip, Operand(ExternalReference::scheduled_exception_address(isolate)));
+  __ ldr(r5, MemOperand(ip));
+  __ cmp(r4, r5);
+  __ b(ne, &promote_scheduled_exception);
+
   __ mov(pc, lr);
 
+  // Re-throw by promoting a scheduled exception.
   __ bind(&promote_scheduled_exception);
-  {
-    FrameScope frame(masm, StackFrame::INTERNAL);
-    __ CallExternalReference(
-        ExternalReference(Runtime::kPromoteScheduledException, isolate), 0);
-  }
-  __ jmp(&exception_handled);
+  __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
 
   // HandleScope limit has changed. Delete allocated extensions.
   __ bind(&delete_allocated_handles);
index 4a34070..4bbfd37 100644 (file)
@@ -45,6 +45,18 @@ void CpuFeatures::FlushICache(void* start, size_t size) {
   register uint32_t end asm("r1") = beg + size;
   register uint32_t flg asm("r2") = 0;
 
+#ifdef __clang__
+  // This variant of the asm avoids a constant pool entry, which can be
+  // problematic when LTO'ing. It is also slightly shorter.
+  register uint32_t scno asm("r7") = __ARM_NR_cacheflush;
+
+  asm volatile("svc 0\n"
+               :
+               : "r"(beg), "r"(end), "r"(flg), "r"(scno)
+               : "memory");
+#else
+  // Use a different variant of the asm with GCC because some versions doesn't
+  // support r7 as an asm input.
   asm volatile(
     // This assembly works for both ARM and Thumb targets.
 
@@ -62,6 +74,7 @@ void CpuFeatures::FlushICache(void* start, size_t size) {
     : "r" (beg), "r" (end), "r" (flg), [scno] "i" (__ARM_NR_cacheflush)
     : "memory");
 #endif
+#endif
 }
 
 } }  // namespace v8::internal
index c910057..d9c25c6 100644 (file)
 namespace v8 {
 namespace internal {
 
-bool BreakLocationIterator::IsDebugBreakAtReturn() {
-  return Debug::IsDebugBreakAtReturn(rinfo());
-}
-
-
-void BreakLocationIterator::SetDebugBreakAtReturn() {
+void BreakLocation::SetDebugBreakAtReturn() {
   // Patch the code changing the return from JS function sequence from
   //   mov sp, fp
   //   ldmia sp!, {fp, lr}
@@ -28,7 +23,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
   //   blx ip
   //   <debug break return code entry point address>
   //   bkpt 0
-  CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
+  CodePatcher patcher(pc(), Assembler::kJSReturnSequenceInstructions);
   patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0));
   patcher.masm()->blx(v8::internal::ip);
   patcher.Emit(
@@ -37,29 +32,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
 }
 
 
-// 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() {
+void BreakLocation::SetDebugBreakAtSlot() {
   DCHECK(IsDebugBreakSlot());
   // Patch the code changing the debug break slot code from
   //   mov r2, r2
@@ -69,7 +42,7 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
   //   ldr ip, [pc, #0]
   //   blx ip
   //   <debug break slot code entry point address>
-  CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
+  CodePatcher patcher(pc(), Assembler::kDebugBreakSlotInstructions);
   patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0));
   patcher.masm()->blx(v8::internal::ip);
   patcher.Emit(
@@ -77,13 +50,6 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
 }
 
 
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
-  DCHECK(IsDebugBreakSlot());
-  rinfo()->PatchCode(original_rinfo()->pc(),
-                     Assembler::kDebugBreakSlotInstructions);
-}
-
-
 #define __ ACCESS_MASM(masm)
 
 
index be05344..9359768 100644 (file)
@@ -135,7 +135,7 @@ bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
 
 // This code tries to be close to ia32 code so that any changes can be
 // easily ported.
-void Deoptimizer::EntryGenerator::Generate() {
+void Deoptimizer::TableEntryGenerator::Generate() {
   GeneratePrologue();
 
   // Save all general purpose registers before messing with them.
index 4e631b0..19f8c2f 100644 (file)
@@ -33,6 +33,7 @@
 #if V8_TARGET_ARCH_ARM
 
 #include "src/arm/constants-arm.h"
+#include "src/base/bits.h"
 #include "src/base/platform/platform.h"
 #include "src/disasm.h"
 #include "src/macro-assembler.h"
@@ -226,7 +227,7 @@ void Decoder::PrintShiftRm(Instruction* instr) {
 void Decoder::PrintShiftImm(Instruction* instr) {
   int rotate = instr->RotateValue() * 2;
   int immed8 = instr->Immed8Value();
-  int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
+  int imm = base::bits::RotateRight32(immed8, rotate);
   out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "#%d", imm);
 }
 
index ce65e88..3720a2b 100644 (file)
@@ -152,11 +152,6 @@ inline Object* JavaScriptFrame::function_slot_object() const {
 }
 
 
-inline void StackHandler::SetFp(Address slot, Address fp) {
-  Memory::Address_at(slot) = fp;
-}
-
-
 } }  // namespace v8::internal
 
 #endif  // V8_ARM_FRAMES_ARM_H_
index 5b56e43..6ee8eb1 100644 (file)
@@ -107,7 +107,8 @@ class JumpPatchSite BASE_EMBEDDED {
 void FullCodeGenerator::Generate() {
   CompilationInfo* info = info_;
   handler_table_ =
-      isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
+      Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray(
+          HandlerTable::LengthForRange(function()->handler_count()), TENURED));
 
   profiling_counter_ = isolate()->factory()->NewCell(
       Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
@@ -195,7 +196,7 @@ void FullCodeGenerator::Generate() {
     // 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_script_scope()) {
+    if (info->scope()->is_script_scope()) {
       __ push(r1);
       __ Push(info->scope()->GetScopeInfo(info->isolate()));
       __ CallRuntime(Runtime::kNewScriptContext, 2);
@@ -240,6 +241,11 @@ void FullCodeGenerator::Generate() {
     }
   }
 
+  ArgumentsAccessStub::HasNewTarget has_new_target =
+      IsSubclassConstructor(info->function()->kind())
+          ? ArgumentsAccessStub::HAS_NEW_TARGET
+          : ArgumentsAccessStub::NO_NEW_TARGET;
+
   // Possibly allocate RestParameters
   int rest_index;
   Variable* rest_param = scope()->rest_parameter(&rest_index);
@@ -248,6 +254,11 @@ void FullCodeGenerator::Generate() {
 
     int num_parameters = info->scope()->num_parameters();
     int offset = num_parameters * kPointerSize;
+    if (has_new_target == ArgumentsAccessStub::HAS_NEW_TARGET) {
+      --num_parameters;
+      ++rest_index;
+    }
+
     __ add(r3, fp, Operand(StandardFrameConstants::kCallerSPOffset + offset));
     __ mov(r2, Operand(Smi::FromInt(num_parameters)));
     __ mov(r1, Operand(Smi::FromInt(rest_index)));
@@ -281,10 +292,6 @@ void FullCodeGenerator::Generate() {
     //   function, receiver address, parameter count.
     // The stub will rewrite receiever and parameter count if the previous
     // stack frame was an arguments adapter frame.
-    ArgumentsAccessStub::HasNewTarget has_new_target =
-        IsSubclassConstructor(info->function()->kind())
-            ? ArgumentsAccessStub::HAS_NEW_TARGET
-            : ArgumentsAccessStub::NO_NEW_TARGET;
     ArgumentsAccessStub::Type type;
     if (is_strict(language_mode()) || !is_simple_parameter_list()) {
       type = ArgumentsAccessStub::NEW_STRICT;
@@ -1529,7 +1536,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
                Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
       }
-      CallLoadIC(CONTEXTUAL);
+      CallGlobalLoadIC(var->name());
       context()->Plug(r0);
       break;
     }
@@ -2177,7 +2184,6 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
 
       // 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"
       __ ldr(r3, MemOperand(sp, 1 * kPointerSize));          // iter
       __ Push(load_name, r3, r0);                       // "throw", iter, except
@@ -2188,16 +2194,17 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       // re-boxing.
       __ bind(&l_try);
       __ pop(r0);                                        // result
-      __ PushTryHandler(StackHandler::CATCH, expr->index());
-      const int handler_size = StackHandlerConstants::kSize;
+      EnterTryBlock(expr->index(), &l_catch);
+      const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ push(r0);                                       // result
       __ jmp(&l_suspend);
       __ bind(&l_continuation);
       __ jmp(&l_resume);
       __ bind(&l_suspend);
-      const int generator_object_depth = kPointerSize + handler_size;
+      const int generator_object_depth = kPointerSize + try_block_size;
       __ ldr(r0, MemOperand(sp, generator_object_depth));
       __ push(r0);                                       // g
+      __ Push(Smi::FromInt(expr->index()));              // handler-index
       DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
       __ mov(r1, Operand(Smi::FromInt(l_continuation.pos())));
       __ str(r1, FieldMemOperand(r0, JSGeneratorObject::kContinuationOffset));
@@ -2205,12 +2212,12 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       __ mov(r1, cp);
       __ RecordWriteField(r0, JSGeneratorObject::kContextOffset, r1, r2,
                           kLRHasBeenSaved, kDontSaveFPRegs);
-      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 2);
       __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
       __ pop(r0);                                      // result
       EmitReturnSequence();
       __ bind(&l_resume);                              // received in r0
-      __ PopTryHandler();
+      ExitTryBlock(expr->index());
 
       // receiver = iter; f = 'next'; arg = received;
       __ bind(&l_next);
@@ -2570,6 +2577,16 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
     }
     __ push(scratch);
     EmitPropertyKey(property, lit->GetIdForProperty(i));
+
+    // The static prototype property is read only. We handle the non computed
+    // property name case in the parser. Since this is the only case where we
+    // need to check for an own read only property we special case this so we do
+    // not need to do this for every property.
+    if (property->is_static() && property->is_computed_name()) {
+      __ CallRuntime(Runtime::kThrowIfStaticPrototype, 1);
+      __ push(r0);
+    }
+
     VisitForStackValue(value);
     EmitSetHomeObjectIfNeeded(value, 2);
 
@@ -2713,25 +2730,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
     __ ldr(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(r0);
-      __ mov(r0, Operand(var->name()));
-      __ Push(cp, r0);  // Context and name.
-      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
-    } else {
-      DCHECK(var->IsStackAllocated() || var->IsContextSlot());
-      Label skip;
-      MemOperand location = VarOperand(var, r1);
-      __ ldr(r2, location);
-      __ CompareRoot(r2, Heap::kTheHoleValueRootIndex);
-      __ b(ne, &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());
@@ -2748,6 +2746,21 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
     __ bind(&assign);
     EmitStoreToStackLocalOrContextSlot(var, location);
 
+  } else if (var->mode() == CONST && op != Token::INIT_CONST) {
+    // Assignment to const variable needs a write barrier.
+    DCHECK(!var->IsLookupSlot());
+    DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+    Label const_error;
+    MemOperand location = VarOperand(var, r1);
+    __ ldr(r3, location);
+    __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
+    __ b(ne, &const_error);
+    __ mov(r3, Operand(var->name()));
+    __ push(r3);
+    __ CallRuntime(Runtime::kThrowReferenceError, 1);
+    __ bind(&const_error);
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
   } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
     if (var->IsLookupSlot()) {
       // Assignment to var.
@@ -2769,8 +2782,33 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
-  } else if (IsSignallingAssignmentToConst(var, op, language_mode())) {
-    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
+  } else if (op == Token::INIT_CONST_LEGACY) {
+    // Const initializers need a write barrier.
+    DCHECK(var->mode() == CONST_LEGACY);
+    DCHECK(!var->IsParameter());  // No const parameters.
+    if (var->IsLookupSlot()) {
+      __ push(r0);
+      __ mov(r0, Operand(var->name()));
+      __ Push(cp, r0);  // Context and name.
+      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
+    } else {
+      DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+      Label skip;
+      MemOperand location = VarOperand(var, r1);
+      __ ldr(r2, location);
+      __ CompareRoot(r2, Heap::kTheHoleValueRootIndex);
+      __ b(ne, &skip);
+      EmitStoreToStackLocalOrContextSlot(var, location);
+      __ bind(&skip);
+    }
+
+  } else {
+    DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT_CONST_LEGACY);
+    if (is_strict(language_mode())) {
+      __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+    }
+    // Silently ignore store in sloppy mode.
   }
 }
 
@@ -2900,7 +2938,8 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
     }
     // Push undefined as receiver. This is patched in the method prologue if it
     // is a sloppy mode method.
-    __ Push(isolate()->factory()->undefined_value());
+    __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+    __ push(ip);
   } else {
     // Load the function from the receiver.
     DCHECK(callee->IsProperty());
@@ -3260,7 +3299,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
 
 
 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
-  if (!ValidateSuperCall(expr)) return;
   Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
   GetVar(result_register(), new_target_var);
   __ Push(result_register());
@@ -3764,8 +3802,9 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 
   // Check if the constructor in the map is a JS function.
-  __ ldr(r0, FieldMemOperand(r0, Map::kConstructorOffset));
-  __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
+  Register instance_type = r2;
+  __ GetMapConstructor(r0, r0, r1, instance_type);
+  __ cmp(instance_type, Operand(JS_FUNCTION_TYPE));
   __ b(ne, &non_function_constructor);
 
   // r0 now contains the constructor function. Grab the
@@ -4062,7 +4101,7 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
   __ jmp(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&done);
   context()->Plug(result);
@@ -4109,7 +4148,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
   __ jmp(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&done);
   context()->Plug(result);
@@ -4284,7 +4323,7 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
   __ bind(&not_found);
   // Call runtime to perform the lookup.
   __ Push(cache, key);
-  __ CallRuntime(Runtime::kGetFromCache, 2);
+  __ CallRuntime(Runtime::kGetFromCacheRT, 2);
 
   __ bind(&done);
   context()->Plug(r0);
@@ -4570,18 +4609,11 @@ void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
 
 
 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()) {
+    Comment cmnt(masm_, "[ CallRuntime");
     // Push the builtins object as the receiver.
     Register receiver = LoadDescriptor::ReceiverRegister();
     __ ldr(receiver, GlobalObjectOperand());
@@ -4604,7 +4636,6 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     __ str(r0, 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));
     }
@@ -4619,15 +4650,29 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
 
     context()->DropAndPlug(1, r0);
+
   } else {
-    // Push the arguments ("left-to-right").
-    for (int i = 0; i < arg_count; i++) {
-      VisitForStackValue(args->at(i));
-    }
+    const Runtime::Function* function = expr->function();
+    switch (function->function_id) {
+#define CALL_INTRINSIC_GENERATOR(Name)     \
+  case Runtime::kInline##Name: {           \
+    Comment cmnt(masm_, "[ Inline" #Name); \
+    return Emit##Name(expr);               \
+  }
+      FOR_EACH_FULL_CODE_INTRINSIC(CALL_INTRINSIC_GENERATOR)
+#undef CALL_INTRINSIC_GENERATOR
+      default: {
+        Comment cmnt(masm_, "[ CallRuntime for unhandled intrinsic");
+        // 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(r0);
+        // Call the C runtime function.
+        __ CallRuntime(expr->function(), arg_count);
+        context()->Plug(r0);
+      }
+    }
   }
 }
 
@@ -5273,20 +5318,6 @@ void FullCodeGenerator::EnterFinallyBlock() {
   __ mov(ip, Operand(pending_message_obj));
   __ ldr(r1, MemOperand(ip));
   __ push(r1);
-
-  ExternalReference has_pending_message =
-      ExternalReference::address_of_has_pending_message(isolate());
-  __ mov(ip, Operand(has_pending_message));
-  STATIC_ASSERT(sizeof(bool) == 1);   // NOLINT(runtime/sizeof)
-  __ ldrb(r1, MemOperand(ip));
-  __ SmiTag(r1);
-  __ push(r1);
-
-  ExternalReference pending_message_script =
-      ExternalReference::address_of_pending_message_script(isolate());
-  __ mov(ip, Operand(pending_message_script));
-  __ ldr(r1, MemOperand(ip));
-  __ push(r1);
 }
 
 
@@ -5294,20 +5325,6 @@ void FullCodeGenerator::ExitFinallyBlock() {
   DCHECK(!result_register().is(r1));
   // Restore pending message from stack.
   __ pop(r1);
-  ExternalReference pending_message_script =
-      ExternalReference::address_of_pending_message_script(isolate());
-  __ mov(ip, Operand(pending_message_script));
-  __ str(r1, MemOperand(ip));
-
-  __ pop(r1);
-  __ SmiUntag(r1);
-  ExternalReference has_pending_message =
-      ExternalReference::address_of_has_pending_message(isolate());
-  __ mov(ip, Operand(has_pending_message));
-  STATIC_ASSERT(sizeof(bool) == 1);   // NOLINT(runtime/sizeof)
-  __ strb(r1, MemOperand(ip));
-
-  __ pop(r1);
   ExternalReference pending_message_obj =
       ExternalReference::address_of_pending_message_obj(isolate());
   __ mov(ip, Operand(pending_message_obj));
@@ -5325,34 +5342,6 @@ void FullCodeGenerator::ExitFinallyBlock() {
 
 #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.
-    __ ldr(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
-    __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-  }
-  __ PopTryHandler();
-  __ bl(finally_entry_);
-
-  *stack_depth = 0;
-  *context_length = 0;
-  return previous_;
-}
-
-
-#undef __
-
 
 static Address GetInterruptImmediateLoadAddress(Address pc) {
   Address load_address = pc - 2 * Assembler::kInstrSize;
index da0cba9..64d0055 100644 (file)
@@ -227,6 +227,12 @@ void InternalArrayConstructorDescriptor::Initialize(
 }
 
 
+void CompareDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r1, r0};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
 void CompareNilDescriptor::Initialize(CallInterfaceDescriptorData* data) {
   Register registers[] = {cp, r0};
   data->Initialize(arraysize(registers), registers, NULL);
index 2e097f9..b45e1c5 100644 (file)
@@ -2140,14 +2140,6 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
 }
 
 
-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 =
@@ -2162,16 +2154,6 @@ LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* 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 =
index fc8b300..fbf648f 100644 (file)
@@ -100,7 +100,6 @@ class LCodeGen;
   V(LoadRoot)                                \
   V(LoadFieldByIndex)                        \
   V(LoadFunctionPrototype)                   \
-  V(LoadGlobalCell)                          \
   V(LoadGlobalGeneric)                       \
   V(LoadKeyed)                               \
   V(LoadKeyedGeneric)                        \
@@ -142,7 +141,6 @@ class LCodeGen;
   V(StoreCodeEntry)                          \
   V(StoreContextSlot)                        \
   V(StoreFrameContext)                       \
-  V(StoreGlobalCell)                         \
   V(StoreKeyed)                              \
   V(StoreKeyedGeneric)                       \
   V(StoreNamedField)                         \
@@ -1704,13 +1702,6 @@ class LLoadKeyedGeneric FINAL : public LTemplateInstruction<1, 3, 1> {
 };
 
 
-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,
@@ -1732,21 +1723,6 @@ class LLoadGlobalGeneric FINAL : public LTemplateInstruction<1, 2, 1> {
 };
 
 
-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) {
index 5b6ed2c..2026318 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/base/bits.h"
 #include "src/code-factory.h"
 #include "src/code-stubs.h"
+#include "src/cpu-profiler.h"
 #include "src/hydrogen-osr.h"
 #include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
@@ -119,7 +120,7 @@ bool LCodeGen::GeneratePrologue() {
     // 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() && is_sloppy(info_->language_mode()) &&
+    if (graph()->this_has_uses() && is_sloppy(info_->language_mode()) &&
         !info_->is_native()) {
       Label ok;
       int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
@@ -345,54 +346,40 @@ bool LCodeGen::GenerateJumpTable() {
 
       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");
-          __ PushFixedFrame();
-          // 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());
-          __ mov(ip, Operand(Smi::FromInt(StackFrame::STUB)));
-          __ push(ip);
-          __ add(fp, sp,
-                 Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
-          __ bind(&call_deopt_entry);
-          // Add the base address to the offset previously loaded in
-          // entry_offset.
-          __ add(entry_offset, entry_offset,
-                 Operand(ExternalReference::ForDeoptEntry(base)));
-          __ blx(entry_offset);
-        }
-
-        masm()->CheckConstPool(false, false);
+        Comment(";;; call deopt with frame");
+        __ PushFixedFrame();
+        __ bl(&needs_frame);
       } 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);
-
-        masm()->CheckConstPool(false, !need_branch);
+        __ bl(&call_deopt_entry);
       }
+      info()->LogDeoptCallPosition(masm()->pc_offset(),
+                                   table_entry->deopt_info.inlining_id);
+      masm()->CheckConstPool(false, false);
     }
 
-    if (!call_deopt_entry.is_bound()) {
-      Comment(";;; call deopt");
-      __ bind(&call_deopt_entry);
+    if (needs_frame.is_linked()) {
+      __ bind(&needs_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());
+      __ mov(ip, Operand(Smi::FromInt(StackFrame::STUB)));
+      __ push(ip);
+      __ add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+    }
 
-      if (info()->saves_caller_doubles()) {
-        DCHECK(info()->IsStub());
-        RestoreCallerDoubles();
-      }
+    Comment(";;; call deopt");
+    __ bind(&call_deopt_entry);
 
-      // Add the base address to the offset previously loaded in entry_offset.
-      __ add(entry_offset, entry_offset,
-             Operand(ExternalReference::ForDeoptEntry(base)));
-      __ blx(entry_offset);
+    if (info()->saves_caller_doubles()) {
+      DCHECK(info()->IsStub());
+      RestoreCallerDoubles();
     }
+
+    // Add the base address to the offset previously loaded in entry_offset.
+    __ add(entry_offset, entry_offset,
+           Operand(ExternalReference::ForDeoptEntry(base)));
+    __ bx(entry_offset);
   }
 
   // Force constant pool emission at the end of the deopt jump table to make
@@ -893,8 +880,8 @@ void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
     __ stop("trap_on_deopt", condition);
   }
 
-  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
-                                    instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info = MakeDeoptInfo(instr, deopt_reason);
+
   DCHECK(info()->IsStub() || frame_is_built_);
   // Go through jump table if we need to handle condition, build frame, or
   // restore caller doubles.
@@ -902,6 +889,7 @@ void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
       !info()->saves_caller_doubles()) {
     DeoptComment(deopt_info);
     __ Call(entry, RelocInfo::RUNTIME_ENTRY);
+    info()->LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
   } else {
     Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
                                             !frame_is_built_);
@@ -2729,10 +2717,11 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
 
   // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
   // Check if the constructor in the map is a function.
-  __ ldr(temp, FieldMemOperand(temp, Map::kConstructorOffset));
+  Register instance_type = ip;
+  __ GetMapConstructor(temp, temp, temp2, instance_type);
 
   // Objects with a non-function constructor have class 'Object'.
-  __ CompareObjectType(temp, temp2, temp2, JS_FUNCTION_TYPE);
+  __ cmp(instance_type, Operand(JS_FUNCTION_TYPE));
   if (class_name->IsOneByteEqualTo(STATIC_CHAR_VECTOR("Object"))) {
     __ b(ne, is_true);
   } else {
@@ -2838,8 +2827,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
     // 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)));
-    __ ldr(ip, FieldMemOperand(ip, PropertyCell::kValueOffset));
+    __ mov(ip, Operand(cell));
+    __ ldr(ip, FieldMemOperand(ip, Cell::kValueOffset));
     __ cmp(map, Operand(ip));
     __ b(ne, &cache_miss);
     __ bind(deferred->load_bool());  // Label for calculating code patching.
@@ -2993,18 +2982,6 @@ void LCodeGen::DoReturn(LReturn* instr) {
 }
 
 
-void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
-  Register result = ToRegister(instr->result());
-  __ mov(ip, Operand(Handle<Object>(instr->hydrogen()->cell().handle())));
-  __ ldr(result, FieldMemOperand(ip, Cell::kValueOffset));
-  if (instr->hydrogen()->RequiresHoleCheck()) {
-    __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
-    __ cmp(result, ip);
-    DeoptimizeIf(eq, instr, Deoptimizer::kHole);
-  }
-}
-
-
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
@@ -3034,36 +3011,12 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
   }
   ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
-  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode,
+                                                       PREMONOMORPHIC).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());
-    __ ldr(payload, FieldMemOperand(cell, Cell::kValueOffset));
-    __ CompareRoot(payload, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(eq, instr, Deoptimizer::kHole);
-  }
-
-  // Store the value.
-  __ str(value, FieldMemOperand(cell, Cell::kValueOffset));
-  // Cells are always rescanned, so no write barrier here.
-}
-
-
 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
   Register context = ToRegister(instr->context());
   Register result = ToRegister(instr->result());
@@ -3156,8 +3109,9 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
   if (FLAG_vector_ics) {
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
-  Handle<Code> ic =
-      CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(
+                        isolate(), NOT_CONTEXTUAL,
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS);
 }
 
@@ -3448,7 +3402,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code();
+  Handle<Code> ic =
+      CodeFactory::KeyedLoadICInOptimizedCode(
+          isolate(), instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS);
 }
 
@@ -4309,7 +4265,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
   __ mov(StoreDescriptor::NameRegister(), Operand(instr->name()));
-  Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->language_mode());
+  Handle<Code> ic =
+      StoreIC::initialize_stub(isolate(), instr->language_mode(),
+                               instr->hydrogen()->initialization_state());
   CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS);
 }
 
@@ -4530,8 +4488,9 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
   DCHECK(ToRegister(instr->key()).is(StoreDescriptor::NameRegister()));
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
-  Handle<Code> ic =
-      CodeFactory::KeyedStoreIC(isolate(), instr->language_mode()).code();
+  Handle<Code> ic = CodeFactory::KeyedStoreICInOptimizedCode(
+                        isolate(), instr->language_mode(),
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS);
 }
 
@@ -5239,7 +5198,7 @@ void LCodeGen::DoCheckValue(LCheckValue* instr) {
   if (isolate()->heap()->InNewSpace(*object)) {
     Register reg = ToRegister(instr->value());
     Handle<Cell> cell = isolate()->factory()->NewCell(object);
-    __ mov(ip, Operand(Handle<Object>(cell)));
+    __ mov(ip, Operand(cell));
     __ ldr(ip, FieldMemOperand(ip, Cell::kValueOffset));
     __ cmp(reg, ip);
   } else {
index c8fb60d..b3cacc8 100644 (file)
@@ -439,6 +439,7 @@ void MacroAssembler::LoadRoot(Register destination,
 void MacroAssembler::StoreRoot(Register source,
                                Heap::RootListIndex index,
                                Condition cond) {
+  DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
   str(source, MemOperand(kRootRegister, index << kPointerSizeLog2), cond);
 }
 
@@ -1395,44 +1396,22 @@ void MacroAssembler::DebugBreak() {
 }
 
 
-void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
-                                    int handler_index) {
+void MacroAssembler::PushStackHandler() {
   // Adjust this code if not the case.
-  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kSize == 1 * 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 r0-r4, r5-r6 are available.
-  // We will build up the handler from the bottom by pushing on the stack.
-  // Set up the code object (r5) and the state (r6) for pushing.
-  unsigned state =
-      StackHandler::IndexField::encode(handler_index) |
-      StackHandler::KindField::encode(kind);
-  mov(r5, Operand(CodeObject()));
-  mov(r6, Operand(state));
-
-  // Push the frame pointer, context, state, and code object.
-  if (kind == StackHandler::JS_ENTRY) {
-    mov(cp, Operand(Smi::FromInt(0)));  // Indicates no context.
-    mov(ip, Operand::Zero());  // NULL frame pointer.
-    stm(db_w, sp, r5.bit() | r6.bit() | cp.bit() | ip.bit());
-  } else {
-    stm(db_w, sp, r5.bit() | r6.bit() | cp.bit() | fp.bit());
-  }
 
   // Link the current handler as the next handler.
   mov(r6, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
   ldr(r5, MemOperand(r6));
   push(r5);
+
   // Set this new handler as the current one.
   str(sp, MemOperand(r6));
 }
 
 
-void MacroAssembler::PopTryHandler() {
+void MacroAssembler::PopStackHandler() {
   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
   pop(r1);
   mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
@@ -1441,98 +1420,6 @@ void MacroAssembler::PopTryHandler() {
 }
 
 
-void MacroAssembler::JumpToHandlerEntry() {
-  // Compute the handler entry address and jump to it.  The handler table is
-  // a fixed array of (smi-tagged) code offsets.
-  // r0 = exception, r1 = code object, r2 = state.
-
-  ConstantPoolUnavailableScope constant_pool_unavailable(this);
-  if (FLAG_enable_ool_constant_pool) {
-    ldr(pp, FieldMemOperand(r1, Code::kConstantPoolOffset));  // Constant pool.
-  }
-  ldr(r3, FieldMemOperand(r1, Code::kHandlerTableOffset));  // Handler table.
-  add(r3, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
-  mov(r2, Operand(r2, LSR, StackHandler::kKindWidth));  // Handler index.
-  ldr(r2, MemOperand(r3, r2, LSL, kPointerSizeLog2));  // Smi-tagged offset.
-  add(r1, r1, Operand(Code::kHeaderSize - kHeapObjectTag));  // Code start.
-  add(pc, r1, Operand::SmiUntag(r2));  // Jump
-}
-
-
-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);
-
-  // The exception is expected in r0.
-  if (!value.is(r0)) {
-    mov(r0, value);
-  }
-  // Drop the stack pointer to the top of the top handler.
-  mov(r3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
-  ldr(sp, MemOperand(r3));
-  // Restore the next handler.
-  pop(r2);
-  str(r2, MemOperand(r3));
-
-  // Get the code object (r1) and state (r2).  Restore the context and frame
-  // pointer.
-  ldm(ia_w, sp, r1.bit() | r2.bit() | cp.bit() | fp.bit());
-
-  // 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.
-  tst(cp, cp);
-  str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
-
-  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 r0.
-  if (!value.is(r0)) {
-    mov(r0, value);
-  }
-  // Drop the stack pointer to the top of the top stack handler.
-  mov(r3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
-  ldr(sp, MemOperand(r3));
-
-  // Unwind the handlers until the ENTRY handler is found.
-  Label fetch_next, check_kind;
-  jmp(&check_kind);
-  bind(&fetch_next);
-  ldr(sp, MemOperand(sp, StackHandlerConstants::kNextOffset));
-
-  bind(&check_kind);
-  STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
-  ldr(r2, MemOperand(sp, StackHandlerConstants::kStateOffset));
-  tst(r2, Operand(StackHandler::KindField::kMask));
-  b(ne, &fetch_next);
-
-  // Set the top handler address to next handler past the top ENTRY handler.
-  pop(r2);
-  str(r2, MemOperand(r3));
-  // Get the code object (r1) and state (r2).  Clear the context and frame
-  // pointer (0 was saved in the handler).
-  ldm(ia_w, sp, r1.bit() | r2.bit() | cp.bit() | fp.bit());
-
-  JumpToHandlerEntry();
-}
-
-
 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
                                             Register scratch,
                                             Label* miss) {
@@ -2292,6 +2179,20 @@ void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
 }
 
 
+void MacroAssembler::GetMapConstructor(Register result, Register map,
+                                       Register temp, Register temp2) {
+  Label done, loop;
+  ldr(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
+  bind(&loop);
+  JumpIfSmi(result, &done);
+  CompareObjectType(result, temp, temp2, MAP_TYPE);
+  b(ne, &done);
+  ldr(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset));
+  b(&loop);
+  bind(&done);
+}
+
+
 void MacroAssembler::TryGetFunctionPrototype(Register function,
                                              Register result,
                                              Register scratch,
@@ -2345,7 +2246,7 @@ void MacroAssembler::TryGetFunctionPrototype(Register function,
     // Non-instance prototype: Fetch prototype from constructor field
     // in initial map.
     bind(&non_instance);
-    ldr(result, FieldMemOperand(result, Map::kConstructorOffset));
+    GetMapConstructor(result, result, scratch, ip);
   }
 
   // All done.
index 5de013e..f92aab4 100644 (file)
@@ -643,19 +643,12 @@ class MacroAssembler: public Assembler {
   // ---------------------------------------------------------------------------
   // Exception handling
 
-  // Push a new try handler and link into try handler chain.
-  void PushTryHandler(StackHandler::Kind kind, int handler_index);
+  // Push a new stack handler and link into stack handler chain.
+  void PushStackHandler();
 
-  // Unlink the stack handler on top of the stack from the try handler chain.
+  // Unlink the stack handler on top of the stack from the stack 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);
+  void PopStackHandler();
 
   // ---------------------------------------------------------------------------
   // Inline caching support
@@ -811,6 +804,11 @@ class MacroAssembler: public Assembler {
   // ---------------------------------------------------------------------------
   // Support functions.
 
+  // Machine code version of Map::GetConstructor().
+  // |temp| holds |result|'s map when done, and |temp2| its instance type.
+  void GetMapConstructor(Register result, Register map, Register temp,
+                         Register temp2);
+
   // 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
@@ -1464,10 +1462,6 @@ class MacroAssembler: public Assembler {
                           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);
index 209b5d2..4c681ae 100644 (file)
@@ -13,6 +13,7 @@
 #include "src/arm/constants-arm.h"
 #include "src/arm/simulator-arm.h"
 #include "src/assembler.h"
+#include "src/base/bits.h"
 #include "src/codegen.h"
 #include "src/disasm.h"
 
@@ -1506,7 +1507,7 @@ int32_t Simulator::GetShiftRm(Instruction* instr, bool* carry_out) {
 int32_t Simulator::GetImm(Instruction* instr, bool* carry_out) {
   int rotate = instr->RotateValue() * 2;
   int immed8 = instr->Immed8Value();
-  int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
+  int imm = base::bits::RotateRight32(immed8, rotate);
   *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
   return imm;
 }
index 4547efe..7d8d81e 100644 (file)
@@ -18,7 +18,12 @@ bool CpuFeatures::SupportsCrankshaft() { return true; }
 
 
 void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
-  UNIMPLEMENTED();
+  // On arm64 only internal references need extra work.
+  DCHECK(RelocInfo::IsInternalReference(rmode_));
+
+  // Absolute code pointer inside code object moves with the code object.
+  intptr_t* p = reinterpret_cast<intptr_t*>(pc_);
+  *p += delta;  // Relocate entry.
 }
 
 
@@ -654,6 +659,12 @@ void Assembler::deserialization_set_special_target_at(
 }
 
 
+void Assembler::deserialization_set_target_internal_reference_at(
+    Address pc, Address target, RelocInfo::Mode mode) {
+  Memory::Address_at(pc) = target;
+}
+
+
 void Assembler::set_target_address_at(Address pc,
                                       ConstantPoolArray* constant_pool,
                                       Address target,
@@ -733,12 +744,24 @@ void RelocInfo::set_target_object(Object* target,
 }
 
 
-Address RelocInfo::target_reference() {
+Address RelocInfo::target_external_reference() {
   DCHECK(rmode_ == EXTERNAL_REFERENCE);
   return Assembler::target_address_at(pc_, host_);
 }
 
 
+Address RelocInfo::target_internal_reference() {
+  DCHECK(rmode_ == INTERNAL_REFERENCE);
+  return Memory::Address_at(pc_);
+}
+
+
+Address RelocInfo::target_internal_reference_address() {
+  DCHECK(rmode_ == INTERNAL_REFERENCE);
+  return reinterpret_cast<Address>(pc_);
+}
+
+
 Address RelocInfo::target_runtime_entry(Assembler* origin) {
   DCHECK(IsRuntimeEntry(rmode_));
   return target_address();
@@ -826,11 +849,14 @@ void RelocInfo::set_call_address(Address target) {
 
 
 void RelocInfo::WipeOut() {
-  DCHECK(IsEmbeddedObject(rmode_) ||
-         IsCodeTarget(rmode_) ||
-         IsRuntimeEntry(rmode_) ||
-         IsExternalReference(rmode_));
-  Assembler::set_target_address_at(pc_, host_, NULL);
+  DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
+         IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
+         IsInternalReference(rmode_));
+  if (IsInternalReference(rmode_)) {
+    Memory::Address_at(pc_) = NULL;
+  } else {
+    Assembler::set_target_address_at(pc_, host_, NULL);
+  }
 }
 
 
@@ -838,7 +864,7 @@ bool RelocInfo::IsPatchedReturnSequence() {
   // The sequence must be:
   //   ldr ip0, [pc, #offset]
   //   blr ip0
-  // See arm64/debug-arm64.cc BreakLocationIterator::SetDebugBreakAtReturn().
+  // See arm64/debug-arm64.cc BreakLocation::SetDebugBreakAtReturn().
   Instruction* i1 = reinterpret_cast<Instruction*>(pc_);
   Instruction* i2 = i1->following();
   return i1->IsLdrLiteralX() && (i1->Rt() == ip0.code()) &&
@@ -862,6 +888,8 @@ void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
     visitor->VisitCell(this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     visitor->VisitExternalReference(this);
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
+    visitor->VisitInternalReference(this);
   } else if (((RelocInfo::IsJSReturn(mode) &&
               IsPatchedReturnSequence()) ||
              (RelocInfo::IsDebugBreakSlot(mode) &&
@@ -885,6 +913,8 @@ void RelocInfo::Visit(Heap* heap) {
     StaticVisitor::VisitCell(heap, this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     StaticVisitor::VisitExternalReference(this);
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
+    StaticVisitor::VisitInternalReference(this);
   } else if (heap->isolate()->debug()->has_break_points() &&
              ((RelocInfo::IsJSReturn(mode) &&
               IsPatchedReturnSequence()) ||
index bba78c8..d072433 100644 (file)
@@ -171,7 +171,7 @@ CPURegList CPURegList::GetSafepointSavedRegisters() {
 // -----------------------------------------------------------------------------
 // Implementation of RelocInfo
 
-const int RelocInfo::kApplyMask = 0;
+const int RelocInfo::kApplyMask = 1 << RelocInfo::INTERNAL_REFERENCE;
 
 
 bool RelocInfo::IsCodedSpecially() {
@@ -188,26 +188,6 @@ bool RelocInfo::IsInConstantPool() {
 }
 
 
-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 * kInstructionSize);
-}
-
-
-// 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) {
-  UNIMPLEMENTED();
-}
-
-
 Register GetAllocatableRegisterThatIsNotOneOf(Register reg1, Register reg2,
                                               Register reg3, Register reg4) {
   CPURegList regs(reg1, reg2, reg3, reg4);
@@ -752,7 +732,15 @@ void Assembler::bind(Label* label) {
     DCHECK(prevlinkoffset >= 0);
 
     // Update the link to point to the label.
-    link->SetImmPCOffsetTarget(reinterpret_cast<Instruction*>(pc_));
+    if (link->IsUnresolvedInternalReference()) {
+      // Internal references do not get patched to an instruction but directly
+      // to an address.
+      internal_reference_positions_.push_back(linkoffset);
+      PatchingAssembler patcher(link, 2);
+      patcher.dc64(reinterpret_cast<uintptr_t>(pc_));
+    } else {
+      link->SetImmPCOffsetTarget(reinterpret_cast<Instruction*>(pc_));
+    }
 
     // Link the label to the previous link in the chain.
     if (linkoffset - prevlinkoffset == kStartOfLabelLinkChain) {
@@ -2080,6 +2068,50 @@ void Assembler::ucvtf(const FPRegister& fd,
 }
 
 
+void Assembler::dcptr(Label* label) {
+  RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
+  if (label->is_bound()) {
+    // The label is bound, so it does not need to be updated and the internal
+    // reference should be emitted.
+    //
+    // In this case, label->pos() returns the offset of the label from the
+    // start of the buffer.
+    internal_reference_positions_.push_back(pc_offset());
+    dc64(reinterpret_cast<uintptr_t>(buffer_ + label->pos()));
+  } else {
+    int32_t offset;
+    if (label->is_linked()) {
+      // The label is linked, so the internal reference should be added
+      // onto the end of the label's link chain.
+      //
+      // In this case, label->pos() returns the offset of the last linked
+      // instruction from the start of the buffer.
+      offset = label->pos() - pc_offset();
+      DCHECK(offset != kStartOfLabelLinkChain);
+    } else {
+      // The label is unused, so it now becomes linked and the internal
+      // reference is at the start of the new link chain.
+      offset = kStartOfLabelLinkChain;
+    }
+    // The instruction at pc is now the last link in the label's chain.
+    label->link_to(pc_offset());
+
+    // Traditionally the offset to the previous instruction in the chain is
+    // encoded in the instruction payload (e.g. branch range) but internal
+    // references are not instructions so while unbound they are encoded as
+    // two consecutive brk instructions. The two 16-bit immediates are used
+    // to encode the offset.
+    offset >>= kInstructionSizeLog2;
+    DCHECK(is_int32(offset));
+    uint32_t high16 = unsigned_bitextract_32(31, 16, offset);
+    uint32_t low16 = unsigned_bitextract_32(15, 0, offset);
+
+    brk(high16);
+    brk(low16);
+  }
+}
+
+
 // Note:
 // Below, a difference in case for the same letter indicates a
 // negated bit.
@@ -2839,6 +2871,12 @@ void Assembler::GrowBuffer() {
   // buffer nor pc absolute pointing inside the code buffer, so there is no need
   // to relocate any emitted relocation entries.
 
+  // Relocate internal references.
+  for (auto pos : internal_reference_positions_) {
+    intptr_t* p = reinterpret_cast<intptr_t*>(buffer_ + pos);
+    *p += pc_delta;
+  }
+
   // Pending relocation entries are also relative, no need to relocate.
 }
 
@@ -2848,6 +2886,7 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
   RelocInfo rinfo(reinterpret_cast<byte*>(pc_), rmode, data, NULL);
   if (((rmode >= RelocInfo::JS_RETURN) &&
        (rmode <= RelocInfo::DEBUG_BREAK_SLOT)) ||
+      (rmode == RelocInfo::INTERNAL_REFERENCE) ||
       (rmode == RelocInfo::CONST_POOL) ||
       (rmode == RelocInfo::VENEER_POOL) ||
       (rmode == RelocInfo::DEOPT_REASON)) {
@@ -2857,6 +2896,7 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
            || RelocInfo::IsComment(rmode)
            || RelocInfo::IsDeoptReason(rmode)
            || RelocInfo::IsPosition(rmode)
+           || RelocInfo::IsInternalReference(rmode)
            || RelocInfo::IsConstPool(rmode)
            || RelocInfo::IsVeneerPool(rmode));
     // These modes do not need an entry in the constant pool.
index 9968985..d672589 100644 (file)
@@ -5,14 +5,15 @@
 #ifndef V8_ARM64_ASSEMBLER_ARM64_H_
 #define V8_ARM64_ASSEMBLER_ARM64_H_
 
+#include <deque>
 #include <list>
 #include <map>
 #include <vector>
 
 #include "src/arm64/instructions-arm64.h"
 #include "src/assembler.h"
+#include "src/compiler.h"
 #include "src/globals.h"
-#include "src/serialize.h"
 #include "src/utils.h"
 
 
@@ -900,6 +901,11 @@ class Assembler : public AssemblerBase {
   inline static void deserialization_set_special_target_at(
       Address constant_pool_entry, Code* code, Address target);
 
+  // This sets the internal reference at the pc.
+  inline static void deserialization_set_target_internal_reference_at(
+      Address pc, Address target,
+      RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
+
   // All addresses in the constant pool are the same size as pointers.
   static const int kSpecialTargetSize = kPointerSize;
 
@@ -951,7 +957,9 @@ class Assembler : public AssemblerBase {
 
   // Number of instructions generated for the return sequence in
   // FullCodeGenerator::EmitReturnSequence.
-  static const int kJSRetSequenceInstructions = 7;
+  static const int kJSReturnSequenceInstructions = 7;
+  static const int kJSReturnSequenceLength =
+      kJSReturnSequenceInstructions * kInstructionSize;
   // Distance between start of patched return sequence and the emitted address
   // to jump to.
   static const int kPatchReturnSequenceAddressOffset =  0;
@@ -959,7 +967,7 @@ class Assembler : public AssemblerBase {
 
   // Number of instructions necessary to be able to later patch it to a call.
   // See DebugCodegen::GenerateSlot() and
-  // BreakLocationIterator::SetDebugBreakAtSlot().
+  // BreakLocation::SetDebugBreakAtSlot().
   static const int kDebugBreakSlotInstructions = 4;
   static const int kDebugBreakSlotLength =
     kDebugBreakSlotInstructions * kInstructionSize;
@@ -1010,7 +1018,7 @@ class Assembler : public AssemblerBase {
 
   // Record a deoptimization reason that can be used by a log or cpu profiler.
   // Use --trace-deopt to enable.
-  void RecordDeoptReason(const int reason, const int raw_position);
+  void RecordDeoptReason(const int reason, const SourcePosition position);
 
   int buffer_space() const;
 
@@ -1743,6 +1751,9 @@ class Assembler : public AssemblerBase {
   // Emit 64 bits of data in the instruction stream.
   void dc64(uint64_t data) { EmitData(&data, sizeof(data)); }
 
+  // Emit an address in the instruction stream.
+  void dcptr(Label* label);
+
   // Copy a string into the instruction stream, including the terminating NULL
   // character. The instruction pointer (pc_) is then aligned correctly for
   // subsequent instructions.
@@ -2159,6 +2170,10 @@ class Assembler : public AssemblerBase {
   // Each relocation is encoded as a variable size value
   static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
   RelocInfoWriter reloc_info_writer;
+  // Internal reference positions, required for (potential) patching in
+  // GrowBuffer(); contains only those internal references whose labels
+  // are already bound.
+  std::deque<int> internal_reference_positions_;
 
   // Relocation info records are also used during code generation as temporary
   // containers for constants and code target addresses until they are emitted
index 89e3040..dfb59c0 100644 (file)
@@ -1324,53 +1324,106 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
 }
 
 
-void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
-  ASM_LOCATION("Builtins::Generate_FunctionApply");
-  const int kIndexOffset    =
-      StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
-  const int kLimitOffset    =
-      StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
-  const int kArgsOffset     =  2 * kPointerSize;
-  const int kReceiverOffset =  3 * kPointerSize;
-  const int kFunctionOffset =  4 * kPointerSize;
+static void Generate_CheckStackOverflow(MacroAssembler* masm,
+                                        const int calleeOffset) {
+  Register argc = x0;
+  Register function = x15;
+
+  // 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 enough_stack_space;
+  __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
+  __ Ldr(function, MemOperand(fp, calleeOffset));
+  // Make x10 the space we have left. The stack might already be overflowed
+  // here which will cause x10 to become negative.
+  // TODO(jbramley): Check that the stack usage here is safe.
+  __ Sub(x10, jssp, x10);
+  // Check if the arguments will overflow the stack.
+  __ Cmp(x10, Operand::UntagSmiAndScale(argc, kPointerSizeLog2));
+  __ B(gt, &enough_stack_space);
+  // There is not enough stack space, so use a builtin to throw an appropriate
+  // error.
+  __ Push(function, argc);
+  __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+  // We should never return from the APPLY_OVERFLOW builtin.
+  if (__ emit_debug_code()) {
+    __ Unreachable();
+  }
+
+  __ Bind(&enough_stack_space);
+}
+
+
+static void Generate_PushAppliedArguments(MacroAssembler* masm,
+                                          const int argumentsOffset,
+                                          const int indexOffset,
+                                          const int limitOffset) {
+  Label entry, loop;
+  Register current = x0;
+  __ Ldr(current, MemOperand(fp, indexOffset));
+  __ B(&entry);
+
+  __ Bind(&loop);
+  // Load the current argument from the arguments array and push it.
+  // TODO(all): Couldn't we optimize this for JS arrays?
+
+  __ Ldr(x1, MemOperand(fp, argumentsOffset));
+  __ Push(x1, current);
+
+  // Call the runtime to access the property in the arguments array.
+  __ CallRuntime(Runtime::kGetProperty, 2);
+  __ Push(x0);
+
+  // Use inline caching to access the arguments.
+  __ Ldr(current, MemOperand(fp, indexOffset));
+  __ Add(current, current, Smi::FromInt(1));
+  __ Str(current, MemOperand(fp, indexOffset));
+
+  // Test if the copy loop has finished copying all the elements from the
+  // arguments object.
+  __ Bind(&entry);
+  __ Ldr(x1, MemOperand(fp, limitOffset));
+  __ Cmp(current, x1);
+  __ B(ne, &loop);
+
+  // On exit, the pushed arguments count is in x0, untagged
+  __ SmiUntag(current);
+}
+
+
+static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
+  const int kFormalParameters = targetIsArgument ? 3 : 2;
+  const int kStackSize = kFormalParameters + 1;
 
   {
     FrameScope frame_scope(masm, StackFrame::INTERNAL);
 
+    const int kArgumentsOffset =  kFPOnStackSize + kPCOnStackSize;
+    const int kReceiverOffset = kArgumentsOffset + kPointerSize;
+    const int kFunctionOffset = kReceiverOffset + kPointerSize;
+    const int kIndexOffset    =
+        StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
+    const int kLimitOffset    =
+        StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
+
     Register args = x12;
     Register receiver = x14;
     Register function = x15;
 
     // Get the length of the arguments via a builtin call.
     __ Ldr(function, MemOperand(fp, kFunctionOffset));
-    __ Ldr(args, MemOperand(fp, kArgsOffset));
+    __ Ldr(args, MemOperand(fp, kArgumentsOffset));
     __ Push(function, args);
-    __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
+    if (targetIsArgument) {
+      __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION);
+    } else {
+      __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
+    }
     Register argc = x0;
 
-    // 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 enough_stack_space;
-    __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
-    __ Ldr(function, MemOperand(fp, kFunctionOffset));
-    // Make x10 the space we have left. The stack might already be overflowed
-    // here which will cause x10 to become negative.
-    // TODO(jbramley): Check that the stack usage here is safe.
-    __ Sub(x10, jssp, x10);
-    // Check if the arguments will overflow the stack.
-    __ Cmp(x10, Operand::UntagSmiAndScale(argc, kPointerSizeLog2));
-    __ B(gt, &enough_stack_space);
-    // There is not enough stack space, so use a builtin to throw an appropriate
-    // error.
-    __ Push(function, argc);
-    __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
-    // We should never return from the APPLY_OVERFLOW builtin.
-    if (__ emit_debug_code()) {
-      __ Unreachable();
-    }
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
 
-    __ Bind(&enough_stack_space);
     // Push current limit and index.
     __ Mov(x1, 0);  // Initial index.
     __ Push(argc, x1);
@@ -1424,33 +1477,8 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
     __ Push(receiver);
 
     // Copy all arguments from the array to the stack.
-    Label entry, loop;
-    Register current = x0;
-    __ Ldr(current, MemOperand(fp, kIndexOffset));
-    __ B(&entry);
-
-    __ Bind(&loop);
-    // Load the current argument from the arguments array and push it.
-    // TODO(all): Couldn't we optimize this for JS arrays?
-
-    __ Ldr(x1, MemOperand(fp, kArgsOffset));
-    __ Push(x1, current);
-
-    // Call the runtime to access the property in the arguments array.
-    __ CallRuntime(Runtime::kGetProperty, 2);
-    __ Push(x0);
-
-    // Use inline caching to access the arguments.
-    __ Ldr(current, MemOperand(fp, kIndexOffset));
-    __ Add(current, current, Smi::FromInt(1));
-    __ Str(current, MemOperand(fp, kIndexOffset));
-
-    // Test if the copy loop has finished copying all the elements from the
-    // arguments object.
-    __ Bind(&entry);
-    __ Ldr(x1, MemOperand(fp, kLimitOffset));
-    __ Cmp(current, x1);
-    __ B(ne, &loop);
+    Generate_PushAppliedArguments(
+        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
 
     // At the end of the loop, the number of arguments is stored in 'current',
     // represented as a smi.
@@ -1460,12 +1488,11 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
 
     // Call the function.
     Label call_proxy;
-    ParameterCount actual(current);
-    __ SmiUntag(current);
+    ParameterCount actual(x0);
     __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE, &call_proxy);
     __ InvokeFunction(function, actual, CALL_FUNCTION, NullCallWrapper());
     frame_scope.GenerateLeaveFrame();
-    __ Drop(3);
+    __ Drop(kStackSize);
     __ Ret();
 
     // Call the function proxy.
@@ -1479,11 +1506,93 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
     __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
             RelocInfo::CODE_TARGET);
   }
-  __ Drop(3);
+  __ Drop(kStackSize);
   __ Ret();
 }
 
 
+static void Generate_ConstructHelper(MacroAssembler* masm) {
+  const int kFormalParameters = 3;
+  const int kStackSize = kFormalParameters + 1;
+
+  {
+    FrameScope frame_scope(masm, StackFrame::INTERNAL);
+
+    const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize;
+    const int kArgumentsOffset =  kNewTargetOffset + kPointerSize;
+    const int kFunctionOffset = kArgumentsOffset + kPointerSize;
+
+    const int kIndexOffset    =
+        StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
+    const int kLimitOffset    =
+        StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
+
+    // Is x11 safe to use?
+    Register newTarget = x11;
+    Register args = x12;
+    Register function = x15;
+
+    // If newTarget is not supplied, set it to constructor
+    Label validate_arguments;
+    __ Ldr(x0, MemOperand(fp, kNewTargetOffset));
+    __ CompareRoot(x0, Heap::kUndefinedValueRootIndex);
+    __ B(ne, &validate_arguments);
+    __ Ldr(x0, MemOperand(fp, kFunctionOffset));
+    __ Str(x0, MemOperand(fp, kNewTargetOffset));
+
+    // Validate arguments
+    __ Bind(&validate_arguments);
+    __ Ldr(function, MemOperand(fp, kFunctionOffset));
+    __ Ldr(args, MemOperand(fp, kArgumentsOffset));
+    __ Ldr(newTarget, MemOperand(fp, kNewTargetOffset));
+    __ Push(function, args, newTarget);
+    __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION);
+    Register argc = x0;
+
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
+
+    // Push current limit and index, constructor & newTarget
+    __ Mov(x1, 0);  // Initial index.
+    __ Ldr(newTarget, MemOperand(fp, kNewTargetOffset));
+    __ Push(argc, x1, newTarget, function);
+
+    // Copy all arguments from the array to the stack.
+    Generate_PushAppliedArguments(
+        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
+
+    __ Ldr(x1, MemOperand(fp, kFunctionOffset));
+    // Use undefined feedback vector
+    __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
+
+    // Call the function.
+    CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
+    __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
+
+    __ Drop(1);
+  }
+  __ Drop(kStackSize);
+  __ Ret();
+}
+
+
+void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+  ASM_LOCATION("Builtins::Generate_FunctionApply");
+  Generate_ApplyHelper(masm, false);
+}
+
+
+void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
+  ASM_LOCATION("Builtins::Generate_ReflectApply");
+  Generate_ApplyHelper(masm, true);
+}
+
+
+void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
+  ASM_LOCATION("Builtins::Generate_ReflectConstruct");
+  Generate_ConstructHelper(masm);
+}
+
+
 static void ArgumentAdaptorStackCheck(MacroAssembler* masm,
                                       Label* stack_overflow) {
   // ----------- S t a t e -------------
index c50a30a..4247aec 100644 (file)
@@ -11,6 +11,7 @@
 #include "src/codegen.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
@@ -1188,28 +1189,28 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // Handling of exception.
   __ Bind(&exception_returned);
 
-  // Retrieve the pending exception.
-  ExternalReference pending_exception_address(
-      Isolate::kPendingExceptionAddress, isolate());
-  const Register& exception = result;
-  const Register& exception_address = x11;
-  __ Mov(exception_address, Operand(pending_exception_address));
-  __ Ldr(exception, MemOperand(exception_address));
-
-  // Clear the pending exception.
-  __ Mov(x10, Operand(isolate()->factory()->the_hole_value()));
-  __ Str(x10, MemOperand(exception_address));
-
-  //  x0    exception   The exception descriptor.
-  //  x21   argv
-  //  x22   argc
-  //  x23   target
-
-  // Special handling of termination exceptions, which are uncatchable by
-  // JavaScript code.
-  Label throw_termination_exception;
-  __ Cmp(exception, Operand(isolate()->factory()->termination_exception()));
-  __ B(eq, &throw_termination_exception);
+  ExternalReference pending_handler_context_address(
+      Isolate::kPendingHandlerContextAddress, isolate());
+  ExternalReference pending_handler_code_address(
+      Isolate::kPendingHandlerCodeAddress, isolate());
+  ExternalReference pending_handler_offset_address(
+      Isolate::kPendingHandlerOffsetAddress, isolate());
+  ExternalReference pending_handler_fp_address(
+      Isolate::kPendingHandlerFPAddress, isolate());
+  ExternalReference pending_handler_sp_address(
+      Isolate::kPendingHandlerSPAddress, isolate());
+
+  // Ask the runtime for help to determine the handler. This will set x0 to
+  // contain the current pending exception, don't clobber it.
+  ExternalReference find_handler(Runtime::kFindExceptionHandler, isolate());
+  DCHECK(csp.Is(masm->StackPointer()));
+  {
+    FrameScope scope(masm, StackFrame::MANUAL);
+    __ Mov(x0, 0);  // argc.
+    __ Mov(x1, 0);  // argv.
+    __ Mov(x2, ExternalReference::isolate_address(isolate()));
+    __ CallCFunction(find_handler, 3);
+  }
 
   // We didn't execute a return case, so the stack frame hasn't been updated
   // (except for the return address slot). However, we don't need to initialize
@@ -1217,18 +1218,29 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // unwinds the stack.
   __ SetStackPointer(jssp);
 
-  ASM_LOCATION("Throw normal");
-  __ Mov(argv, 0);
-  __ Mov(argc, 0);
-  __ Mov(target, 0);
-  __ Throw(x0, x10, x11, x12, x13);
-
-  __ Bind(&throw_termination_exception);
-  ASM_LOCATION("Throw termination");
-  __ Mov(argv, 0);
-  __ Mov(argc, 0);
-  __ Mov(target, 0);
-  __ ThrowUncatchable(x0, x10, x11, x12, x13);
+  // Retrieve the handler context, SP and FP.
+  __ Mov(cp, Operand(pending_handler_context_address));
+  __ Ldr(cp, MemOperand(cp));
+  __ Mov(jssp, Operand(pending_handler_sp_address));
+  __ Ldr(jssp, MemOperand(jssp));
+  __ Mov(fp, Operand(pending_handler_fp_address));
+  __ Ldr(fp, MemOperand(fp));
+
+  // If the handler is a JS frame, restore the context to the frame. Note that
+  // the context will be set to (cp == 0) for non-JS frames.
+  Label not_js_frame;
+  __ Cbz(cp, &not_js_frame);
+  __ Str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  __ Bind(&not_js_frame);
+
+  // Compute the handler entry address and jump to it.
+  __ Mov(x10, Operand(pending_handler_code_address));
+  __ Ldr(x10, MemOperand(x10));
+  __ Mov(x11, Operand(pending_handler_offset_address));
+  __ Ldr(x11, MemOperand(x11));
+  __ Add(x10, x10, Code::kHeaderSize - kHeapObjectTag);
+  __ Add(x10, x10, x11);
+  __ Br(x10);
 }
 
 
@@ -1333,10 +1345,9 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ LoadRoot(x0, 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.
+  // Invoke: Link this frame into the handler chain.
   __ Bind(&invoke);
-  __ PushTryHandler(StackHandler::JS_ENTRY, 0);
+  __ PushStackHandler();
   // If an exception not caught by another handler occurs, this handler
   // returns control to the code after the B(&invoke) above, which
   // restores all callee-saved registers (including cp and fp) to their
@@ -1370,7 +1381,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ Blr(x12);
 
   // Unlink this frame from the handler chain.
-  __ PopTryHandler();
+  __ PopStackHandler();
 
 
   __ Bind(&exit);
@@ -1454,7 +1465,7 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
   __ Ret();
 
   StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
+  char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
 
   __ Bind(&miss);
   PropertyAccessCompiler::TailCallBuiltin(
@@ -2062,9 +2073,13 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
                     ArgumentsAdaptorFrameConstants::kLengthOffset));
   __ SmiUntag(param_count, param_count_smi);
   if (has_new_target()) {
+    __ Cmp(param_count, Operand(0));
+    Label skip_decrement;
+    __ B(eq, &skip_decrement);
     // Skip new.target: it is not a part of arguments.
     __ Sub(param_count, param_count, Operand(1));
     __ SmiTag(param_count_smi, param_count);
+    __ Bind(&skip_decrement);
   }
   __ Add(x10, caller_fp, Operand(param_count, LSL, kPointerSizeLog2));
   __ Add(params, x10, StandardFrameConstants::kCallerSPOffset);
@@ -2209,7 +2224,7 @@ void RestParamAccessStub::GenerateNew(MacroAssembler* masm) {
 
 void RegExpExecStub::Generate(MacroAssembler* masm) {
 #ifdef V8_INTERPRETED_REGEXP
-  __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 #else  // V8_INTERPRETED_REGEXP
 
   // Stack frame on entry.
@@ -2661,18 +2676,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   __ Cmp(x10, exception_value);
   __ B(eq, &runtime);
 
-  __ Str(x10, MemOperand(x11));  // Clear pending exception.
-
-  // Check if the exception is a termination. If so, throw as uncatchable.
-  Label termination_exception;
-  __ JumpIfRoot(exception_value,
-                Heap::kTerminationExceptionRootIndex,
-                &termination_exception);
-
-  __ Throw(exception_value, x10, x11, x12, x13);
-
-  __ Bind(&termination_exception);
-  __ ThrowUncatchable(exception_value, x10, x11, x12, x13);
+  // For exception, throw the exception again.
+  __ TailCallRuntime(Runtime::kRegExpExecReThrow, 4, 1);
 
   __ Bind(&failure);
   __ Mov(x0, Operand(isolate()->factory()->null_value()));
@@ -2683,7 +2688,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
 
   __ Bind(&runtime);
   __ PopCPURegList(used_callee_saved_registers);
-  __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 
   // Deferred code for string handling.
   // (6) Not a long external string?  If yes, go to (8).
@@ -3299,7 +3304,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
 
 
 void StringCharCodeAtGenerator::GenerateSlow(
-    MacroAssembler* masm,
+    MacroAssembler* masm, EmbedMode embed_mode,
     const RuntimeCallHelper& call_helper) {
   __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
 
@@ -3307,8 +3312,13 @@ void StringCharCodeAtGenerator::GenerateSlow(
   // If index is a heap number, try converting it to an integer.
   __ JumpIfNotHeapNumber(index_, index_not_number_);
   call_helper.BeforeCall(masm);
-  // Save object_ on the stack and pass index_ as argument for runtime call.
-  __ Push(object_, index_);
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ Push(VectorLoadICDescriptor::VectorRegister(),
+            VectorLoadICDescriptor::SlotRegister(), object_, index_);
+  } else {
+    // Save object_ on the stack and pass index_ as argument for runtime call.
+    __ Push(object_, index_);
+  }
   if (index_flags_ == STRING_INDEX_IS_NUMBER) {
     __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
   } else {
@@ -3319,7 +3329,12 @@ void StringCharCodeAtGenerator::GenerateSlow(
   // Save the conversion result before the pop instructions below
   // have a chance to overwrite it.
   __ Mov(index_, x0);
-  __ Pop(object_);
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ Pop(object_, VectorLoadICDescriptor::SlotRegister(),
+           VectorLoadICDescriptor::VectorRegister());
+  } else {
+    __ Pop(object_);
+  }
   // Reload the instance type.
   __ Ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
   __ Ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
@@ -3616,7 +3631,7 @@ void CompareICStub::GenerateStrings(MacroAssembler* masm) {
   if (equality) {
     __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
   } else {
-    __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+    __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
   }
 
   __ Bind(&miss);
@@ -3948,7 +3963,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
   __ Ret();
 
   __ Bind(&runtime);
-  __ TailCallRuntime(Runtime::kSubString, 3, 1);
+  __ TailCallRuntime(Runtime::kSubStringRT, 3, 1);
 
   __ bind(&single_char);
   // x1: result_length
@@ -4156,7 +4171,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
 
   // Call the runtime.
   // Returns -1 (less), 0 (equal), or 1 (greater) tagged as a small integer.
-  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+  __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
 }
 
 
@@ -4441,15 +4456,15 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
 
 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorLoadStub stub(isolate(), state());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawLoadStub stub(isolate(), state());
+  stub.GenerateForTrampoline(masm);
 }
 
 
 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorKeyedLoadStub stub(isolate());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawKeyedLoadStub stub(isolate());
+  stub.GenerateForTrampoline(masm);
 }
 
 
@@ -4467,6 +4482,234 @@ void CallIC_ArrayTrampolineStub::Generate(MacroAssembler* masm) {
 }
 
 
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+                             Register key, Register vector, Register slot,
+                             Register feedback, Register scratch1,
+                             Register scratch2, Register scratch3,
+                             bool is_polymorphic, Label* miss) {
+  // feedback initially contains the feedback array
+  Label next_loop, prepare_next;
+  Label load_smi_map, compare_map;
+  Label start_polymorphic;
+
+  Register receiver_map = scratch1;
+  Register cached_map = scratch2;
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &load_smi_map);
+  __ Ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ Bind(&compare_map);
+  __ Ldr(cached_map,
+         FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+  __ Ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ Cmp(receiver_map, cached_map);
+  __ B(ne, &start_polymorphic);
+  // found, now call handler.
+  Register handler = feedback;
+  __ Ldr(handler, FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+  __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag);
+  __ Jump(feedback);
+
+  Register length = scratch3;
+  __ Bind(&start_polymorphic);
+  __ Ldr(length, FieldMemOperand(feedback, FixedArray::kLengthOffset));
+  if (!is_polymorphic) {
+    __ Cmp(length, Operand(Smi::FromInt(2)));
+    __ B(eq, miss);
+  }
+
+  Register too_far = length;
+  Register pointer_reg = feedback;
+
+  // +-----+------+------+-----+-----+ ... ----+
+  // | map | len  | wm0  | h0  | wm1 |      hN |
+  // +-----+------+------+-----+-----+ ... ----+
+  //                 0      1     2        len-1
+  //                              ^              ^
+  //                              |              |
+  //                         pointer_reg      too_far
+  //                         aka feedback     scratch3
+  // also need receiver_map (aka scratch1)
+  // use cached_map (scratch2) to look in the weak map values.
+  __ Add(too_far, feedback,
+         Operand::UntagSmiAndScale(length, kPointerSizeLog2));
+  __ Add(too_far, too_far, FixedArray::kHeaderSize - kHeapObjectTag);
+  __ Add(pointer_reg, feedback,
+         FixedArray::OffsetOfElementAt(2) - kHeapObjectTag);
+
+  __ Bind(&next_loop);
+  __ Ldr(cached_map, MemOperand(pointer_reg));
+  __ Ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ Cmp(receiver_map, cached_map);
+  __ B(ne, &prepare_next);
+  __ Ldr(handler, MemOperand(pointer_reg, kPointerSize));
+  __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag);
+  __ Jump(handler);
+
+  __ Bind(&prepare_next);
+  __ Add(pointer_reg, pointer_reg, kPointerSize * 2);
+  __ Cmp(pointer_reg, too_far);
+  __ B(lt, &next_loop);
+
+  // We exhausted our array of map handler pairs.
+  __ jmp(miss);
+
+  __ Bind(&load_smi_map);
+  __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
+  __ jmp(&compare_map);
+}
+
+
+static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+                                  Register key, Register vector, Register slot,
+                                  Register weak_cell, Register scratch,
+                                  Label* miss) {
+  // feedback initially contains the feedback array
+  Label compare_smi_map;
+  Register receiver_map = scratch;
+  Register cached_map = weak_cell;
+
+  // Move the weak map into the weak_cell register.
+  __ Ldr(cached_map, FieldMemOperand(weak_cell, WeakCell::kValueOffset));
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &compare_smi_map);
+  __ Ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ Cmp(cached_map, receiver_map);
+  __ B(ne, miss);
+
+  Register handler = weak_cell;
+  __ Add(handler, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+  __ Ldr(handler,
+         FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag);
+  __ Jump(weak_cell);
+
+  // In microbenchmarks, it made sense to unroll this code so that the call to
+  // the handler is duplicated for a HeapObject receiver and a Smi receiver.
+  // TODO(mvstanton): does this hold on ARM?
+  __ Bind(&compare_smi_map);
+  __ JumpIfNotRoot(weak_cell, Heap::kHeapNumberMapRootIndex, miss);
+  __ Add(handler, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+  __ Ldr(handler,
+         FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag);
+  __ Jump(handler);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // x1
+  Register name = VectorLoadICDescriptor::NameRegister();          // x2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // x3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // x0
+  Register feedback = x4;
+  Register scratch1 = x5;
+
+  __ Add(feedback, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+  __ Ldr(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ Ldr(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ JumpIfNotRoot(scratch1, Heap::kWeakCellMapRootIndex, &try_array);
+  HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback, scratch1,
+                        &miss);
+
+  // Is it a fixed array?
+  __ Bind(&try_array);
+  __ JumpIfNotRoot(scratch1, Heap::kFixedArrayMapRootIndex, &not_array);
+  HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, x6,
+                   x7, true, &miss);
+
+  __ Bind(&not_array);
+  __ JumpIfNotRoot(feedback, Heap::kmegamorphic_symbolRootIndex, &miss);
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, code_flags,
+                                               false, receiver, name, feedback,
+                                               scratch1, x6, x7);
+
+  __ Bind(&miss);
+  LoadIC::GenerateMiss(masm);
+}
+
+
+void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // x1
+  Register key = VectorLoadICDescriptor::NameRegister();           // x2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // x3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // x0
+  Register feedback = x4;
+  Register scratch1 = x5;
+
+  __ Add(feedback, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+  __ Ldr(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ Ldr(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ JumpIfNotRoot(scratch1, Heap::kWeakCellMapRootIndex, &try_array);
+  HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, scratch1,
+                        &miss);
+
+  __ Bind(&try_array);
+  // Is it a fixed array?
+  __ JumpIfNotRoot(scratch1, Heap::kFixedArrayMapRootIndex, &not_array);
+
+  // We have a polymorphic element handler.
+  Label polymorphic, try_poly_name;
+  __ Bind(&polymorphic);
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, x6,
+                   x7, true, &miss);
+
+  __ Bind(&not_array);
+  // Is it generic?
+  __ JumpIfNotRoot(feedback, Heap::kmegamorphic_symbolRootIndex,
+                   &try_poly_name);
+  Handle<Code> megamorphic_stub =
+      KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+  __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET);
+
+  __ Bind(&try_poly_name);
+  // We might have a name in feedback, and a fixed array in the next slot.
+  __ Cmp(key, feedback);
+  __ B(ne, &miss);
+  // If the name comparison succeeded, we know we have a fixed array with
+  // at least one map/handler pair.
+  __ Add(feedback, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+  __ Ldr(feedback,
+         FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, x6,
+                   x7, false, &miss);
+
+  __ Bind(&miss);
+  KeyedLoadIC::GenerateMiss(masm);
+}
+
+
 // The entry hook is a "BumpSystemStackPointer" instruction (sub), followed by
 // a "Push lr" instruction, followed by a call.
 static const unsigned int kProfileEntryHookCallSize =
@@ -5256,7 +5499,6 @@ static void CallApiFunctionAndReturn(
   }
 
   Label promote_scheduled_exception;
-  Label exception_handled;
   Label delete_allocated_handles;
   Label leave_exit_frame;
   Label return_value_loaded;
@@ -5278,6 +5520,7 @@ static void CallApiFunctionAndReturn(
   __ Cmp(limit_reg, x1);
   __ B(ne, &delete_allocated_handles);
 
+  // Leave the API exit frame.
   __ Bind(&leave_exit_frame);
   // Restore callee-saved registers.
   __ Peek(x19, (spill_offset + 0) * kXRegSize);
@@ -5285,13 +5528,6 @@ static void CallApiFunctionAndReturn(
   __ Peek(x21, (spill_offset + 2) * kXRegSize);
   __ Peek(x22, (spill_offset + 3) * kXRegSize);
 
-  // Check if the function scheduled an exception.
-  __ Mov(x5, ExternalReference::scheduled_exception_address(isolate));
-  __ Ldr(x5, MemOperand(x5));
-  __ JumpIfNotRoot(x5, Heap::kTheHoleValueRootIndex,
-                   &promote_scheduled_exception);
-  __ Bind(&exception_handled);
-
   bool restore_context = context_restore_operand != NULL;
   if (restore_context) {
     __ Ldr(cp, *context_restore_operand);
@@ -5302,6 +5538,13 @@ static void CallApiFunctionAndReturn(
   }
 
   __ LeaveExitFrame(false, x1, !restore_context);
+
+  // Check if the function scheduled an exception.
+  __ Mov(x5, ExternalReference::scheduled_exception_address(isolate));
+  __ Ldr(x5, MemOperand(x5));
+  __ JumpIfNotRoot(x5, Heap::kTheHoleValueRootIndex,
+                   &promote_scheduled_exception);
+
   if (stack_space_operand != NULL) {
     __ Drop(x2, 1);
   } else {
@@ -5309,13 +5552,9 @@ static void CallApiFunctionAndReturn(
   }
   __ Ret();
 
+  // Re-throw by promoting a scheduled exception.
   __ Bind(&promote_scheduled_exception);
-  {
-    FrameScope frame(masm, StackFrame::INTERNAL);
-    __ CallExternalReference(
-        ExternalReference(Runtime::kPromoteScheduledException, isolate), 0);
-  }
-  __ B(&exception_handled);
+  __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
 
   // HandleScope limit has changed. Delete allocated extensions.
   __ Bind(&delete_allocated_handles);
index dae5a28..56e3c03 100644 (file)
@@ -15,12 +15,8 @@ namespace internal {
 
 #define __ ACCESS_MASM(masm)
 
-bool BreakLocationIterator::IsDebugBreakAtReturn() {
-  return Debug::IsDebugBreakAtReturn(rinfo());
-}
-
 
-void BreakLocationIterator::SetDebugBreakAtReturn() {
+void BreakLocation::SetDebugBreakAtReturn() {
   // Patch the code emitted by FullCodeGenerator::EmitReturnSequence, changing
   // the return from JS function sequence from
   //   mov sp, fp
@@ -39,8 +35,8 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
 
   // The patching code must not overflow the space occupied by the return
   // sequence.
-  STATIC_ASSERT(Assembler::kJSRetSequenceInstructions >= 5);
-  PatchingAssembler patcher(reinterpret_cast<Instruction*>(rinfo()->pc()), 5);
+  STATIC_ASSERT(Assembler::kJSReturnSequenceInstructions >= 5);
+  PatchingAssembler patcher(reinterpret_cast<Instruction*>(pc()), 5);
   byte* entry =
       debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry();
 
@@ -59,27 +55,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
 }
 
 
-void BreakLocationIterator::ClearDebugBreakAtReturn() {
-  // Reset the code emitted by EmitReturnSequence to its original state.
-  rinfo()->PatchCode(original_rinfo()->pc(),
-                     Assembler::kJSRetSequenceInstructions);
-}
-
-
-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() {
+void BreakLocation::SetDebugBreakAtSlot() {
   // Patch the code emitted by DebugCodegen::GenerateSlots, changing the debug
   // break slot code from
   //   mov x0, x0    @ nop DEBUG_BREAK_NOP
@@ -99,7 +75,7 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
   // The patching code must not overflow the space occupied by the return
   // sequence.
   STATIC_ASSERT(Assembler::kDebugBreakSlotInstructions >= 4);
-  PatchingAssembler patcher(reinterpret_cast<Instruction*>(rinfo()->pc()), 4);
+  PatchingAssembler patcher(reinterpret_cast<Instruction*>(pc()), 4);
   byte* entry =
       debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry();
 
@@ -117,13 +93,6 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
 }
 
 
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
-  DCHECK(IsDebugBreakSlot());
-  rinfo()->PatchCode(original_rinfo()->pc(),
-                     Assembler::kDebugBreakSlotInstructions);
-}
-
-
 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
                                           RegList object_regs,
                                           RegList non_object_regs,
index 8c4b776..b28d6f1 100644 (file)
@@ -115,7 +115,7 @@ void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
 
 #define __ masm()->
 
-void Deoptimizer::EntryGenerator::Generate() {
+void Deoptimizer::TableEntryGenerator::Generate() {
   GeneratePrologue();
 
   // TODO(all): This code needs to be revisited. We probably only need to save
index 8d4ce86..883079c 100644 (file)
@@ -99,11 +99,6 @@ inline Object* JavaScriptFrame::function_slot_object() const {
 }
 
 
-inline void StackHandler::SetFp(Address slot, Address fp) {
-  Memory::Address_at(slot) = fp;
-}
-
-
 } }  // namespace v8::internal
 
 #endif  // V8_ARM64_FRAMES_ARM64_H_
index 63b6a98..9feac93 100644 (file)
@@ -105,7 +105,8 @@ class JumpPatchSite BASE_EMBEDDED {
 void FullCodeGenerator::Generate() {
   CompilationInfo* info = info_;
   handler_table_ =
-      isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
+      Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray(
+          HandlerTable::LengthForRange(function()->handler_count()), TENURED));
 
   profiling_counter_ = isolate()->factory()->NewCell(
       Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
@@ -196,7 +197,7 @@ void FullCodeGenerator::Generate() {
     // 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_script_scope()) {
+    if (info->scope()->is_script_scope()) {
       __ Mov(x10, Operand(info->scope()->GetScopeInfo(info->isolate())));
       __ Push(x1, x10);
       __ CallRuntime(Runtime::kNewScriptContext, 2);
@@ -241,6 +242,11 @@ void FullCodeGenerator::Generate() {
     }
   }
 
+  ArgumentsAccessStub::HasNewTarget has_new_target =
+      IsSubclassConstructor(info->function()->kind())
+          ? ArgumentsAccessStub::HAS_NEW_TARGET
+          : ArgumentsAccessStub::NO_NEW_TARGET;
+
   // Possibly allocate RestParameters
   int rest_index;
   Variable* rest_param = scope()->rest_parameter(&rest_index);
@@ -249,6 +255,11 @@ void FullCodeGenerator::Generate() {
 
     int num_parameters = info->scope()->num_parameters();
     int offset = num_parameters * kPointerSize;
+    if (has_new_target == ArgumentsAccessStub::HAS_NEW_TARGET) {
+      --num_parameters;
+      ++rest_index;
+    }
+
     __ Add(x3, fp, StandardFrameConstants::kCallerSPOffset + offset);
     __ Mov(x2, Smi::FromInt(num_parameters));
     __ Mov(x1, Smi::FromInt(rest_index));
@@ -281,10 +292,6 @@ void FullCodeGenerator::Generate() {
     //   function, receiver address, parameter count.
     // The stub will rewrite receiver and parameter count if the previous
     // stack frame was an arguments adapter frame.
-    ArgumentsAccessStub::HasNewTarget has_new_target =
-        IsSubclassConstructor(info->function()->kind())
-            ? ArgumentsAccessStub::HAS_NEW_TARGET
-            : ArgumentsAccessStub::NO_NEW_TARGET;
     ArgumentsAccessStub::Type type;
     if (is_strict(language_mode()) || !is_simple_parameter_list()) {
       type = ArgumentsAccessStub::NEW_STRICT;
@@ -456,10 +463,10 @@ void FullCodeGenerator::EmitReturnSequence() {
 
     // Make sure that the constant pool is not emitted inside of the return
     // sequence. This sequence can get patched when the debugger is used. See
-    // debug-arm64.cc:BreakLocationIterator::SetDebugBreakAtReturn().
+    // debug-arm64.cc:BreakLocation::SetDebugBreakAtReturn().
     {
       InstructionAccurateScope scope(masm_,
-                                     Assembler::kJSRetSequenceInstructions);
+                                     Assembler::kJSReturnSequenceInstructions);
       CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
       __ RecordJSReturn();
       // This code is generated using Assembler methods rather than Macro
@@ -1508,7 +1515,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
         __ Mov(VectorLoadICDescriptor::SlotRegister(),
                SmiFromSlot(proxy->VariableFeedbackSlot()));
       }
-      CallLoadIC(CONTEXTUAL);
+      CallGlobalLoadIC(var->name());
       context()->Plug(x0);
       break;
     }
@@ -2261,6 +2268,16 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
     }
     __ Push(scratch);
     EmitPropertyKey(property, lit->GetIdForProperty(i));
+
+    // The static prototype property is read only. We handle the non computed
+    // property name case in the parser. Since this is the only case where we
+    // need to check for an own read only property we special case this so we do
+    // not need to do this for every property.
+    if (property->is_static() && property->is_computed_name()) {
+      __ CallRuntime(Runtime::kThrowIfStaticPrototype, 1);
+      __ Push(x0);
+    }
+
     VisitForStackValue(value);
     EmitSetHomeObjectIfNeeded(value, 2);
 
@@ -2398,23 +2415,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
     __ Ldr(StoreDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
     CallStoreIC();
 
-  } else if (op == Token::INIT_CONST_LEGACY) {
-    // Const initializers need a write barrier.
-    DCHECK(!var->IsParameter());  // No const parameters.
-    if (var->IsLookupSlot()) {
-      __ Mov(x1, Operand(var->name()));
-      __ Push(x0, cp, x1);
-      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
-    } else {
-      DCHECK(var->IsStackLocal() || var->IsContextSlot());
-      Label skip;
-      MemOperand location = VarOperand(var, x1);
-      __ Ldr(x10, location);
-      __ JumpIfNotRoot(x10, Heap::kTheHoleValueRootIndex, &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());
@@ -2430,6 +2430,20 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
     __ Bind(&assign);
     EmitStoreToStackLocalOrContextSlot(var, location);
 
+  } else if (var->mode() == CONST && op != Token::INIT_CONST) {
+    // Assignment to const variable needs a write barrier.
+    DCHECK(!var->IsLookupSlot());
+    DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+    Label const_error;
+    MemOperand location = VarOperand(var, x1);
+    __ Ldr(x10, location);
+    __ JumpIfNotRoot(x10, Heap::kTheHoleValueRootIndex, &const_error);
+    __ Mov(x10, Operand(var->name()));
+    __ Push(x10);
+    __ CallRuntime(Runtime::kThrowReferenceError, 1);
+    __ Bind(&const_error);
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
   } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
     if (var->IsLookupSlot()) {
       // Assignment to var.
@@ -2453,8 +2467,31 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
-  } else if (IsSignallingAssignmentToConst(var, op, language_mode())) {
-    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
+  } else if (op == Token::INIT_CONST_LEGACY) {
+    // Const initializers need a write barrier.
+    DCHECK(var->mode() == CONST_LEGACY);
+    DCHECK(!var->IsParameter());  // No const parameters.
+    if (var->IsLookupSlot()) {
+      __ Mov(x1, Operand(var->name()));
+      __ Push(x0, cp, x1);
+      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
+    } else {
+      DCHECK(var->IsStackLocal() || var->IsContextSlot());
+      Label skip;
+      MemOperand location = VarOperand(var, x1);
+      __ Ldr(x10, location);
+      __ JumpIfNotRoot(x10, Heap::kTheHoleValueRootIndex, &skip);
+      EmitStoreToStackLocalOrContextSlot(var, location);
+      __ Bind(&skip);
+    }
+
+  } else {
+    DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT_CONST_LEGACY);
+    if (is_strict(language_mode())) {
+      __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+    }
+    // Silently ignore store in sloppy mode.
   }
 }
 
@@ -2586,7 +2623,12 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
     }
     // Push undefined as receiver. This is patched in the method prologue if it
     // is a sloppy mode method.
-    __ Push(isolate()->factory()->undefined_value());
+    {
+      UseScratchRegisterScope temps(masm_);
+      Register temp = temps.AcquireX();
+      __ LoadRoot(temp, Heap::kUndefinedValueRootIndex);
+      __ Push(temp);
+    }
   } else {
     // Load the function from the receiver.
     DCHECK(callee->IsProperty());
@@ -2945,8 +2987,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
 
 
 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
-  if (!ValidateSuperCall(expr)) return;
-
   Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
   GetVar(result_register(), new_target_var);
   __ Push(result_register());
@@ -3467,9 +3507,10 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 
   // Check if the constructor in the map is a JS function.
-  __ Ldr(x12, FieldMemOperand(x10, Map::kConstructorOffset));
-  __ JumpIfNotObjectType(x12, x13, x14, JS_FUNCTION_TYPE,
-                         &non_function_constructor);
+  Register instance_type = x14;
+  __ GetMapConstructor(x12, x10, x13, instance_type);
+  __ Cmp(instance_type, JS_FUNCTION_TYPE);
+  __ B(ne, &non_function_constructor);
 
   // x12 now contains the constructor function. Grab the
   // instance class name from there.
@@ -3764,7 +3805,7 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
   __ B(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ Bind(&done);
   context()->Plug(result);
@@ -3810,7 +3851,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
   __ B(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ Bind(&done);
   context()->Plug(result);
@@ -3985,7 +4026,7 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
 
   // Call runtime to perform the lookup.
   __ Push(cache, key);
-  __ CallRuntime(Runtime::kGetFromCache, 2);
+  __ CallRuntime(Runtime::kGetFromCacheRT, 2);
 
   __ Bind(&done);
   context()->Plug(x0);
@@ -4254,18 +4295,11 @@ void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
 
 
 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()) {
+    Comment cmnt(masm_, "[ CallRunTime");
     // Push the builtins object as the receiver.
     __ Ldr(x10, GlobalObjectMemOperand());
     __ Ldr(LoadDescriptor::ReceiverRegister(),
@@ -4287,7 +4321,6 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     __ Pop(x10);
     __ Push(x0, x10);
 
-    int arg_count = args->length();
     for (int i = 0; i < arg_count; i++) {
       VisitForStackValue(args->at(i));
     }
@@ -4302,15 +4335,29 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
 
     context()->DropAndPlug(1, x0);
+
   } else {
-    // Push the arguments ("left-to-right").
-    for (int i = 0; i < arg_count; i++) {
-      VisitForStackValue(args->at(i));
-    }
+    const Runtime::Function* function = expr->function();
+    switch (function->function_id) {
+#define CALL_INTRINSIC_GENERATOR(Name)     \
+  case Runtime::kInline##Name: {           \
+    Comment cmnt(masm_, "[ Inline" #Name); \
+    return Emit##Name(expr);               \
+  }
+      FOR_EACH_FULL_CODE_INTRINSIC(CALL_INTRINSIC_GENERATOR)
+#undef CALL_INTRINSIC_GENERATOR
+      default: {
+        Comment cmnt(masm_, "[ CallRuntime for unhandled intrinsic");
+        // 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(x0);
+        // Call the C runtime function.
+        __ CallRuntime(expr->function(), arg_count);
+        context()->Plug(x0);
+      }
+    }
   }
 }
 
@@ -4980,7 +5027,6 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
 
       // 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"
       __ Peek(x3, 1 * kPointerSize);                         // iter
       __ Push(load_name, x3, x0);                       // "throw", iter, except
@@ -4991,8 +5037,8 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       // re-boxing.
       __ Bind(&l_try);
       __ Pop(x0);                                        // result
-      __ PushTryHandler(StackHandler::CATCH, expr->index());
-      const int handler_size = StackHandlerConstants::kSize;
+      EnterTryBlock(expr->index(), &l_catch);
+      const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ Push(x0);                                       // result
       __ B(&l_suspend);
 
@@ -5003,9 +5049,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       __ B(&l_resume);
 
       __ Bind(&l_suspend);
-      const int generator_object_depth = kPointerSize + handler_size;
+      const int generator_object_depth = kPointerSize + try_block_size;
       __ Peek(x0, generator_object_depth);
       __ Push(x0);                                       // g
+      __ Push(Smi::FromInt(expr->index()));              // handler-index
       DCHECK((l_continuation.pos() > 0) && Smi::IsValid(l_continuation.pos()));
       __ Mov(x1, Smi::FromInt(l_continuation.pos()));
       __ Str(x1, FieldMemOperand(x0, JSGeneratorObject::kContinuationOffset));
@@ -5013,12 +5060,12 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       __ Mov(x1, cp);
       __ RecordWriteField(x0, JSGeneratorObject::kContextOffset, x1, x2,
                           kLRHasBeenSaved, kDontSaveFPRegs);
-      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 2);
       __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
       __ Pop(x0);                                        // result
       EmitReturnSequence();
       __ Bind(&l_resume);                                // received in x0
-      __ PopTryHandler();
+      ExitTryBlock(expr->index());
 
       // receiver = iter; f = 'next'; arg = received;
       __ Bind(&l_next);
@@ -5288,20 +5335,6 @@ void FullCodeGenerator::EnterFinallyBlock() {
       ExternalReference::address_of_pending_message_obj(isolate());
   __ Mov(x10, pending_message_obj);
   __ Ldr(x10, MemOperand(x10));
-
-  ExternalReference has_pending_message =
-      ExternalReference::address_of_has_pending_message(isolate());
-  STATIC_ASSERT(sizeof(bool) == 1);   // NOLINT(runtime/sizeof)
-  __ Mov(x11, has_pending_message);
-  __ Ldrb(x11, MemOperand(x11));
-  __ SmiTag(x11);
-
-  __ Push(x10, x11);
-
-  ExternalReference pending_message_script =
-      ExternalReference::address_of_pending_message_script(isolate());
-  __ Mov(x10, pending_message_script);
-  __ Ldr(x10, MemOperand(x10));
   __ Push(x10);
 }
 
@@ -5311,23 +5344,11 @@ void FullCodeGenerator::ExitFinallyBlock() {
   DCHECK(!result_register().is(x10));
 
   // Restore pending message from stack.
-  __ Pop(x10, x11, x12);
-  ExternalReference pending_message_script =
-      ExternalReference::address_of_pending_message_script(isolate());
-  __ Mov(x13, pending_message_script);
-  __ Str(x10, MemOperand(x13));
-
-  __ SmiUntag(x11);
-  ExternalReference has_pending_message =
-      ExternalReference::address_of_has_pending_message(isolate());
-  __ Mov(x13, has_pending_message);
-  STATIC_ASSERT(sizeof(bool) == 1);   // NOLINT(runtime/sizeof)
-  __ Strb(x11, MemOperand(x13));
-
+  __ Pop(x10);
   ExternalReference pending_message_obj =
       ExternalReference::address_of_pending_message_obj(isolate());
   __ Mov(x13, pending_message_obj);
-  __ Str(x12, MemOperand(x13));
+  __ Str(x10, MemOperand(x13));
 
   // Restore result register and cooked return address from the stack.
   __ Pop(x10, result_register());
@@ -5437,37 +5458,6 @@ BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
 }
 
 
-#define __ ACCESS_MASM(masm())
-
-
-FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
-    int* stack_depth,
-    int* context_length) {
-  ASM_LOCATION("FullCodeGenerator::TryFinally::Exit");
-  // 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.
-    __ Peek(cp, StackHandlerConstants::kContextOffset);
-    __ Str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-  }
-  __ PopTryHandler();
-  __ Bl(finally_entry_);
-
-  *stack_depth = 0;
-  *context_length = 0;
-  return previous_;
-}
-
-
-#undef __
-
-
 } }  // namespace v8::internal
 
 #endif  // V8_TARGET_ARCH_ARM64
index 71094ba..7a5effe 100644 (file)
@@ -191,6 +191,9 @@ int64_t Instruction::ImmPCOffset() {
     // All PC-relative branches.
     // Relative branch offsets are instruction-size-aligned.
     offset = ImmBranch() << kInstructionSizeLog2;
+  } else if (IsUnresolvedInternalReference()) {
+    // Internal references are always word-aligned.
+    offset = ImmUnresolvedInternalReference() << kInstructionSizeLog2;
   } else {
     // Load literal (offset from PC).
     DCHECK(IsLdrLiteral());
@@ -223,7 +226,10 @@ void Instruction::SetImmPCOffsetTarget(Instruction* target) {
     SetPCRelImmTarget(target);
   } else if (BranchType() != UnknownBranchType) {
     SetBranchImmTarget(target);
+  } else if (IsUnresolvedInternalReference()) {
+    SetUnresolvedInternalReferenceImmTarget(target);
   } else {
+    // Load literal (offset from PC).
     SetImmLLiteral(target);
   }
 }
@@ -278,7 +284,23 @@ void Instruction::SetBranchImmTarget(Instruction* target) {
 }
 
 
+void Instruction::SetUnresolvedInternalReferenceImmTarget(Instruction* target) {
+  DCHECK(IsUnresolvedInternalReference());
+  DCHECK(IsAligned(DistanceTo(target), kInstructionSize));
+
+  ptrdiff_t target_offset = DistanceTo(target) >> kInstructionSizeLog2;
+  DCHECK(is_int32(target_offset));
+  uint32_t high16 = unsigned_bitextract_32(31, 16, target_offset);
+  uint32_t low16 = unsigned_bitextract_32(15, 0, target_offset);
+
+  PatchingAssembler patcher(this, 2);
+  patcher.brk(high16);
+  patcher.brk(low16);
+}
+
+
 void Instruction::SetImmLLiteral(Instruction* source) {
+  DCHECK(IsLdrLiteral());
   DCHECK(IsAligned(DistanceTo(source), kInstructionSize));
   ptrdiff_t offset = DistanceTo(source) >> kLoadLiteralScaleLog2;
   Instr imm = Assembler::ImmLLiteral(offset);
index 374e246..142b7c1 100644 (file)
@@ -121,10 +121,18 @@ class Instruction {
     return InstructionBits() & mask;
   }
 
+  V8_INLINE const Instruction* following(int count = 1) const {
+    return InstructionAtOffset(count * static_cast<int>(kInstructionSize));
+  }
+
   V8_INLINE Instruction* following(int count = 1) {
     return InstructionAtOffset(count * static_cast<int>(kInstructionSize));
   }
 
+  V8_INLINE const Instruction* preceding(int count = 1) const {
+    return following(-count);
+  }
+
   V8_INLINE Instruction* preceding(int count = 1) {
     return following(-count);
   }
@@ -189,6 +197,14 @@ class Instruction {
     return Mask(PCRelAddressingMask) == ADR;
   }
 
+  bool IsBrk() const { return Mask(ExceptionMask) == BRK; }
+
+  bool IsUnresolvedInternalReference() const {
+    // Unresolved internal references are encoded as two consecutive brk
+    // instructions.
+    return IsBrk() && following()->IsBrk();
+  }
+
   bool IsLogicalImmediate() const {
     return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
   }
@@ -306,6 +322,15 @@ class Instruction {
     return 0;
   }
 
+  int ImmUnresolvedInternalReference() const {
+    DCHECK(IsUnresolvedInternalReference());
+    // Unresolved references are encoded as two consecutive brk instructions.
+    // The associated immediate is made of the two 16-bit payloads.
+    int32_t high16 = ImmException();
+    int32_t low16 = following()->ImmException();
+    return (high16 << 16) | low16;
+  }
+
   bool IsBranchAndLinkToRegister() const {
     return Mask(UnconditionalBranchToRegisterMask) == BLR;
   }
@@ -349,6 +374,7 @@ class Instruction {
   // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
   // a PC-relative addressing instruction.
   void SetImmPCOffsetTarget(Instruction* target);
+  void SetUnresolvedInternalReferenceImmTarget(Instruction* target);
   // Patch a literal load instruction to load from 'source'.
   void SetImmLLiteral(Instruction* source);
 
@@ -359,13 +385,18 @@ class Instruction {
 
   enum CheckAlignment { NO_CHECK, CHECK_ALIGNMENT };
 
+  V8_INLINE const Instruction* InstructionAtOffset(
+      int64_t offset, CheckAlignment check = CHECK_ALIGNMENT) const {
+    // The FUZZ_disasm test relies on no check being done.
+    DCHECK(check == NO_CHECK || IsAligned(offset, kInstructionSize));
+    return this + offset;
+  }
+
   V8_INLINE Instruction* InstructionAtOffset(
-      int64_t offset,
-      CheckAlignment check = CHECK_ALIGNMENT) {
-    Address addr = reinterpret_cast<Address>(this) + offset;
+      int64_t offset, CheckAlignment check = CHECK_ALIGNMENT) {
     // The FUZZ_disasm test relies on no check being done.
-    DCHECK(check == NO_CHECK || IsAddressAligned(addr, kInstructionSize));
-    return Cast(addr);
+    DCHECK(check == NO_CHECK || IsAligned(offset, kInstructionSize));
+    return this + offset;
   }
 
   template<typename T> V8_INLINE static Instruction* Cast(T src) {
index 6deeabf..773dec4 100644 (file)
@@ -261,6 +261,15 @@ void InternalArrayConstructorDescriptor::Initialize(
 }
 
 
+void CompareDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x1: left operand
+  // x0: right operand
+  Register registers[] = {cp, x1, x0};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
 void CompareNilDescriptor::Initialize(CallInterfaceDescriptorData* data) {
   // cp: context
   // x0: value to compare
index 0234fcd..4a89fc4 100644 (file)
@@ -1692,14 +1692,6 @@ LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
 }
 
 
-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 =
@@ -2351,18 +2343,6 @@ LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
-  LOperand* value = UseRegister(instr->value());
-  if (instr->RequiresHoleCheck()) {
-    return AssignEnvironment(new(zone()) LStoreGlobalCell(value,
-                                                          TempRegister(),
-                                                          TempRegister()));
-  } else {
-    return new(zone()) LStoreGlobalCell(value, TempRegister(), NULL);
-  }
-}
-
-
 LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
   LOperand* key = UseRegisterOrConstant(instr->key());
   LOperand* temp = NULL;
index 8b48729..0549689 100644 (file)
@@ -102,7 +102,6 @@ class LCodeGen;
   V(LoadContextSlot)                         \
   V(LoadFieldByIndex)                        \
   V(LoadFunctionPrototype)                   \
-  V(LoadGlobalCell)                          \
   V(LoadGlobalGeneric)                       \
   V(LoadKeyedExternal)                       \
   V(LoadKeyedFixed)                          \
@@ -151,7 +150,6 @@ class LCodeGen;
   V(StoreCodeEntry)                          \
   V(StoreContextSlot)                        \
   V(StoreFrameContext)                       \
-  V(StoreGlobalCell)                         \
   V(StoreKeyedExternal)                      \
   V(StoreKeyedFixed)                         \
   V(StoreKeyedFixedDouble)                   \
@@ -1731,13 +1729,6 @@ class LLoadFunctionPrototype FINAL : public LTemplateInstruction<1, 1, 1> {
 };
 
 
-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,
@@ -2809,23 +2800,6 @@ class LStoreContextSlot FINAL : public LTemplateInstruction<0, 2, 1> {
 };
 
 
-class LStoreGlobalCell FINAL : public LTemplateInstruction<0, 1, 2> {
- public:
-  LStoreGlobalCell(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(StoreGlobalCell, "store-global-cell")
-  DECLARE_HYDROGEN_ACCESSOR(StoreGlobalCell)
-};
-
-
 class LSubI FINAL : public LTemplateInstruction<1, 2, 0> {
  public:
   LSubI(LOperand* left, LOperand* right)
index ef01c91..cd331db 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/base/bits.h"
 #include "src/code-factory.h"
 #include "src/code-stubs.h"
+#include "src/cpu-profiler.h"
 #include "src/hydrogen-osr.h"
 #include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
@@ -434,7 +435,6 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
     CallFunctionStub stub(isolate(), arity, flags);
     CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
   }
-  after_push_argument_ = false;
 }
 
 
@@ -449,7 +449,6 @@ void LCodeGen::DoCallNew(LCallNew* instr) {
 
   CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
   CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
-  after_push_argument_ = false;
 
   DCHECK(ToRegister(instr->result()).is(x0));
 }
@@ -497,7 +496,6 @@ void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
     ArrayNArgumentsConstructorStub stub(isolate(), kind, override_mode);
     CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
   }
-  after_push_argument_ = false;
 
   DCHECK(ToRegister(instr->result()).is(x0));
 }
@@ -519,7 +517,7 @@ void LCodeGen::LoadContextFromDeferred(LOperand* context) {
   if (context->IsRegister()) {
     __ Mov(cp, ToRegister(context));
   } else if (context->IsStackSlot()) {
-    __ Ldr(cp, ToMemOperand(context, kMustUseFramePointer));
+    __ Ldr(cp, ToMemOperand(context));
   } else if (context->IsConstantOperand()) {
     HConstant* constant =
         chunk_->LookupConstant(LConstantOperand::cast(context));
@@ -662,7 +660,7 @@ bool LCodeGen::GeneratePrologue() {
     // 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() && is_sloppy(info_->language_mode()) &&
+    if (graph()->this_has_uses() && is_sloppy(info_->language_mode()) &&
         !info_->is_native()) {
       Label ok;
       int receiver_offset = info_->scope()->num_parameters() * kXRegSize;
@@ -841,7 +839,7 @@ bool LCodeGen::GenerateDeferredCode() {
 
 
 bool LCodeGen::GenerateJumpTable() {
-  Label needs_frame, restore_caller_doubles, call_deopt_entry;
+  Label needs_frame, call_deopt_entry;
 
   if (jump_table_.length() > 0) {
     Comment(";;; -------------------- Jump table --------------------");
@@ -863,55 +861,52 @@ bool LCodeGen::GenerateJumpTable() {
       // address and add an immediate offset.
       __ Mov(entry_offset, entry - base);
 
-      // The last entry can fall through into `call_deopt_entry`, avoiding a
-      // branch.
-      bool last_entry = (i + 1) == length;
-
       if (table_entry->needs_frame) {
         DCHECK(!info()->saves_caller_doubles());
-        if (!needs_frame.is_bound()) {
-          // 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());
-
-          UseScratchRegisterScope temps(masm());
-          Register stub_marker = temps.AcquireX();
-          __ Bind(&needs_frame);
-          __ Mov(stub_marker, Smi::FromInt(StackFrame::STUB));
-          __ Push(lr, fp, cp, stub_marker);
-          __ Add(fp, __ StackPointer(), 2 * kPointerSize);
-          if (!last_entry) __ B(&call_deopt_entry);
-        } else {
-          // Reuse the existing needs_frame code.
-          __ B(&needs_frame);
-        }
-      } else if (info()->saves_caller_doubles()) {
-        DCHECK(info()->IsStub());
-        if (!restore_caller_doubles.is_bound()) {
-          __ Bind(&restore_caller_doubles);
-          RestoreCallerDoubles();
-          if (!last_entry) __ B(&call_deopt_entry);
-        } else {
-          // Reuse the existing restore_caller_doubles code.
-          __ B(&restore_caller_doubles);
-        }
+        Comment(";;; call deopt with frame");
+        // Save lr before Bl, fp will be adjusted in the needs_frame code.
+        __ Push(lr, fp);
+        // Reuse the existing needs_frame code.
+        __ Bl(&needs_frame);
       } else {
         // There is nothing special to do, so just continue to the second-level
         // table.
-        if (!last_entry) __ B(&call_deopt_entry);
+        __ Bl(&call_deopt_entry);
       }
+      info()->LogDeoptCallPosition(masm()->pc_offset(),
+                                   table_entry->deopt_info.inlining_id);
 
-      masm()->CheckConstPool(false, last_entry);
+      masm()->CheckConstPool(false, false);
+    }
+
+    if (needs_frame.is_linked()) {
+      // 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());
+
+      Comment(";;; needs_frame common code");
+      UseScratchRegisterScope temps(masm());
+      Register stub_marker = temps.AcquireX();
+      __ Bind(&needs_frame);
+      __ Mov(stub_marker, Smi::FromInt(StackFrame::STUB));
+      __ Push(cp, stub_marker);
+      __ Add(fp, __ StackPointer(), 2 * kPointerSize);
     }
 
     // Generate common code for calling the second-level deopt table.
-    Register deopt_entry = temps.AcquireX();
     __ Bind(&call_deopt_entry);
+
+    if (info()->saves_caller_doubles()) {
+      DCHECK(info()->IsStub());
+      RestoreCallerDoubles();
+    }
+
+    Register deopt_entry = temps.AcquireX();
     __ Mov(deopt_entry, Operand(reinterpret_cast<uint64_t>(base),
                                 RelocInfo::RUNTIME_ENTRY));
     __ Add(deopt_entry, deopt_entry, entry_offset);
-    __ Call(deopt_entry);
+    __ Br(deopt_entry);
   }
 
   // Force constant pool emission at the end of the deopt jump table to make
@@ -1057,14 +1052,15 @@ void LCodeGen::DeoptimizeBranch(
     __ Bind(&dont_trap);
   }
 
-  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
-                                    instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info = MakeDeoptInfo(instr, deopt_reason);
+
   DCHECK(info()->IsStub() || frame_is_built_);
   // Go through jump table if we need to build frame, or restore caller doubles.
   if (branch_type == always &&
       frame_is_built_ && !info()->saves_caller_doubles()) {
     DeoptComment(deopt_info);
     __ Call(entry, RelocInfo::RUNTIME_ENTRY);
+    info()->LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
   } else {
     Deoptimizer::JumpTableEntry* table_entry =
         new (zone()) Deoptimizer::JumpTableEntry(
@@ -1151,7 +1147,7 @@ void LCodeGen::DeoptimizeIfMinusZero(DoubleRegister input, LInstruction* instr,
 
 void LCodeGen::DeoptimizeIfNotHeapNumber(Register object, LInstruction* instr) {
   __ CompareObjectMap(object, Heap::kHeapNumberMapRootIndex);
-  DeoptimizeIf(ne, instr, Deoptimizer::kNotHeapNumber);
+  DeoptimizeIf(ne, instr, Deoptimizer::kNotAHeapNumber);
 }
 
 
@@ -1276,38 +1272,13 @@ static int64_t ArgumentsOffsetWithoutFrame(int index) {
 }
 
 
-MemOperand LCodeGen::ToMemOperand(LOperand* op, StackMode stack_mode) const {
+MemOperand LCodeGen::ToMemOperand(LOperand* op) const {
   DCHECK(op != NULL);
   DCHECK(!op->IsRegister());
   DCHECK(!op->IsDoubleRegister());
   DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
   if (NeedsEagerFrame()) {
-    int fp_offset = StackSlotOffset(op->index());
-    if (op->index() >= 0) {
-      // Loads and stores have a bigger reach in positive offset than negative.
-      // When the load or the store can't be done in one instruction via fp
-      // (too big negative offset), we try to access via jssp (positive offset).
-      // We can reference a stack slot from jssp only if jssp references the end
-      // of the stack slots. It's not the case when:
-      //  - stack_mode != kCanUseStackPointer: this is the case when a deferred
-      //     code saved the registers.
-      //  - after_push_argument_: arguments has been pushed for a call.
-      //  - inlined_arguments_: inlined arguments have been pushed once. All the
-      //     remainder of the function cannot trust jssp any longer.
-      //  - saves_caller_doubles: some double registers have been pushed, jssp
-      //     references the end of the double registers and not the end of the
-      //     stack slots.
-      // Also, if the offset from fp is small enough to make a load/store in
-      // one instruction, we use a fp access.
-      if ((stack_mode == kCanUseStackPointer) && !after_push_argument_ &&
-          !inlined_arguments_ && !is_int9(fp_offset) &&
-          !info()->saves_caller_doubles()) {
-        int jssp_offset =
-            (GetStackSlotCount() - op->index() - 1) * kPointerSize;
-        return MemOperand(masm()->StackPointer(), jssp_offset);
-      }
-    }
-    return MemOperand(fp, fp_offset);
+    return MemOperand(fp, StackSlotOffset(op->index()));
   } else {
     // Retrieve parameter without eager stack-frame relative to the
     // stack-pointer.
@@ -1711,10 +1682,6 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
 
 
 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
-  // We push some arguments and they will be pop in an other block. We can't
-  // trust that jssp references the end of the stack slots until the end of
-  // the function.
-  inlined_arguments_ = true;
   Register result = ToRegister(instr->result());
 
   if (instr->hydrogen()->from_inlined()) {
@@ -2131,8 +2098,6 @@ void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
     }
     generator.AfterCall();
   }
-
-  after_push_argument_ = false;
 }
 
 
@@ -2152,13 +2117,11 @@ void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) {
   __ Call(x10);
 
   RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
-  after_push_argument_ = false;
 }
 
 
 void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
   CallRuntime(instr->function(), instr->arity(), instr);
-  after_push_argument_ = false;
 }
 
 
@@ -2184,7 +2147,6 @@ void LCodeGen::DoCallStub(LCallStub* instr) {
     default:
       UNREACHABLE();
   }
-  after_push_argument_ = false;
 }
 
 
@@ -2437,15 +2399,17 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
 
   // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
   // Check if the constructor in the map is a function.
-  __ Ldr(scratch1, FieldMemOperand(map, Map::kConstructorOffset));
-
+  {
+    UseScratchRegisterScope temps(masm());
+    Register instance_type = temps.AcquireX();
+    __ GetMapConstructor(scratch1, map, scratch2, instance_type);
+    __ Cmp(instance_type, JS_FUNCTION_TYPE);
+  }
   // Objects with a non-function constructor have class 'Object'.
   if (String::Equals(class_name, isolate()->factory()->Object_string())) {
-    __ JumpIfNotObjectType(
-        scratch1, scratch2, scratch2, JS_FUNCTION_TYPE, true_label);
+    __ B(ne, true_label);
   } else {
-    __ JumpIfNotObjectType(
-        scratch1, scratch2, scratch2, JS_FUNCTION_TYPE, false_label);
+    __ B(ne, false_label);
   }
 
   // The constructor function is in scratch1. Get its instance class name.
@@ -2664,7 +2628,7 @@ void LCodeGen::DoCheckValue(LCheckValue* instr) {
     UseScratchRegisterScope temps(masm());
     Register temp = temps.AcquireX();
     Handle<Cell> cell = isolate()->factory()->NewCell(object);
-    __ Mov(temp, Operand(Handle<Object>(cell)));
+    __ Mov(temp, Operand(cell));
     __ Ldr(temp, FieldMemOperand(temp, Cell::kValueOffset));
     __ Cmp(reg, temp);
   } else {
@@ -3139,8 +3103,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
     __ bind(&map_check);
     // Will be patched with the cached map.
     Handle<Cell> cell = factory()->NewCell(factory()->the_hole_value());
-    __ ldr(scratch, Immediate(Handle<Object>(cell)));
-    __ ldr(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
+    __ ldr(scratch, Immediate(cell));
+    __ ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset));
     __ cmp(map, scratch);
     __ b(&cache_miss, ne);
     // The address of this instruction is computed relative to the map check
@@ -3238,7 +3202,6 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
                       instr->hydrogen()->formal_parameter_count(),
                       instr->arity(), instr);
   }
-  after_push_argument_ = false;
 }
 
 
@@ -3402,17 +3365,6 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
 }
 
 
-void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
-  Register result = ToRegister(instr->result());
-  __ Mov(result, Operand(Handle<Object>(instr->hydrogen()->cell().handle())));
-  __ Ldr(result, FieldMemOperand(result, Cell::kValueOffset));
-  if (instr->hydrogen()->RequiresHoleCheck()) {
-    DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr,
-                     Deoptimizer::kHole);
-  }
-}
-
-
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
@@ -3441,7 +3393,8 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
   }
   ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
-  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode,
+                                                       PREMONOMORPHIC).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3693,7 +3646,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code();
+  Handle<Code> ic =
+      CodeFactory::KeyedLoadICInOptimizedCode(
+          isolate(), instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 
   DCHECK(ToRegister(instr->result()).Is(x0));
@@ -3750,8 +3705,9 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
 
-  Handle<Code> ic =
-      CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(
+                        isolate(), NOT_CONTEXTUAL,
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 
   DCHECK(ToRegister(instr->result()).is(x0));
@@ -4787,8 +4743,6 @@ void LCodeGen::DoPushArguments(LPushArguments* instr) {
 
   // The preamble was done by LPreparePushArguments.
   args.PushQueued(MacroAssembler::PushPopQueue::SKIP_PREAMBLE);
-
-  after_push_argument_ = true;
 }
 
 
@@ -5185,30 +5139,6 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
 }
 
 
-void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
-  Register value = ToRegister(instr->value());
-  Register cell = ToRegister(instr->temp1());
-
-  // 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. We deoptimize in that case.
-  if (instr->hydrogen()->RequiresHoleCheck()) {
-    Register payload = ToRegister(instr->temp2());
-    __ Ldr(payload, FieldMemOperand(cell, Cell::kValueOffset));
-    DeoptimizeIfRoot(payload, Heap::kTheHoleValueRootIndex, instr,
-                     Deoptimizer::kHole);
-  }
-
-  // Store the value.
-  __ Str(value, FieldMemOperand(cell, Cell::kValueOffset));
-  // Cells are always rescanned, so no write barrier here.
-}
-
-
 void LCodeGen::DoStoreKeyedExternal(LStoreKeyedExternal* instr) {
   Register ext_ptr = ToRegister(instr->elements());
   Register key = no_reg;
@@ -5381,8 +5311,9 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
   DCHECK(ToRegister(instr->key()).is(StoreDescriptor::NameRegister()));
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
-  Handle<Code> ic =
-      CodeFactory::KeyedStoreIC(isolate(), instr->language_mode()).code();
+  Handle<Code> ic = CodeFactory::KeyedStoreICInOptimizedCode(
+                        isolate(), instr->language_mode(),
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -5492,7 +5423,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
   __ Mov(StoreDescriptor::NameRegister(), Operand(instr->name()));
-  Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->language_mode());
+  Handle<Code> ic =
+      StoreIC::initialize_stub(isolate(), instr->language_mode(),
+                               instr->hydrogen()->initialization_state());
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
index fe16a4e..d94262e 100644 (file)
@@ -37,16 +37,10 @@ class LCodeGen: public LCodeGenBase {
         frame_is_built_(false),
         safepoints_(info->zone()),
         resolver_(this),
-        expected_safepoint_kind_(Safepoint::kSimple),
-        after_push_argument_(false),
-        inlined_arguments_(false) {
+        expected_safepoint_kind_(Safepoint::kSimple) {
     PopulateDeoptimizationLiteralsWithInlinedFunctions();
   }
 
-  ~LCodeGen() {
-    DCHECK(!after_push_argument_ || inlined_arguments_);
-  }
-
   // Simple accessors.
   Scope* scope() const { return scope_; }
 
@@ -87,9 +81,7 @@ class LCodeGen: public LCodeGenBase {
   Register ToRegister32(LOperand* op) const;
   Operand ToOperand(LOperand* op);
   Operand ToOperand32(LOperand* op);
-  enum StackMode { kMustUseFramePointer, kCanUseStackPointer };
-  MemOperand ToMemOperand(LOperand* op,
-                          StackMode stack_mode = kCanUseStackPointer) const;
+  MemOperand ToMemOperand(LOperand* op) const;
   Handle<Object> ToHandle(LConstantOperand* op) const;
 
   template <class LI>
@@ -366,15 +358,6 @@ class LCodeGen: public LCodeGenBase {
 
   Safepoint::Kind expected_safepoint_kind_;
 
-  // This flag is true when we are after a push (but before a call).
-  // In this situation, jssp no longer references the end of the stack slots so,
-  // we can only reference a stack slot via fp.
-  bool after_push_argument_;
-  // If we have inlined arguments, we are no longer able to use jssp because
-  // jssp is modified and we never know if we are in a block after or before
-  // the pop of the arguments (which restores jssp).
-  bool inlined_arguments_;
-
   int old_position_;
 
   class PushSafepointRegistersScope BASE_EMBEDDED {
index 8b55975..5df2e5a 100644 (file)
@@ -1403,6 +1403,7 @@ void MacroAssembler::LoadRoot(CPURegister destination,
 
 void MacroAssembler::StoreRoot(Register source,
                                Heap::RootListIndex index) {
+  DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
   Str(source, MemOperand(root, index << kPointerSizeLog2));
 }
 
@@ -1549,27 +1550,6 @@ void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver,
 }
 
 
-void MacroAssembler::JumpToHandlerEntry(Register exception,
-                                        Register object,
-                                        Register state,
-                                        Register scratch1,
-                                        Register scratch2) {
-  // Handler expects argument in x0.
-  DCHECK(exception.Is(x0));
-
-  // Compute the handler entry address and jump to it. The handler table is
-  // a fixed array of (smi-tagged) code offsets.
-  Ldr(scratch1, FieldMemOperand(object, Code::kHandlerTableOffset));
-  Add(scratch1, scratch1, FixedArray::kHeaderSize - kHeapObjectTag);
-  STATIC_ASSERT(StackHandler::kKindWidth < kPointerSizeLog2);
-  Lsr(scratch2, state, StackHandler::kKindWidth);
-  Ldr(scratch2, MemOperand(scratch1, scratch2, LSL, kPointerSizeLog2));
-  Add(scratch1, object, Code::kHeaderSize - kHeapObjectTag);
-  Add(scratch1, scratch1, Operand::UntagSmi(scratch2));
-  Br(scratch1);
-}
-
-
 void MacroAssembler::InNewSpace(Register object,
                                 Condition cond,
                                 Label* branch) {
@@ -1582,95 +1562,6 @@ void MacroAssembler::InNewSpace(Register object,
 }
 
 
-void MacroAssembler::Throw(Register value,
-                           Register scratch1,
-                           Register scratch2,
-                           Register scratch3,
-                           Register scratch4) {
-  // 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);
-
-  // The handler expects the exception in x0.
-  DCHECK(value.Is(x0));
-
-  // Drop the stack pointer to the top of the top handler.
-  DCHECK(jssp.Is(StackPointer()));
-  Mov(scratch1, Operand(ExternalReference(Isolate::kHandlerAddress,
-                                          isolate())));
-  Ldr(jssp, MemOperand(scratch1));
-  // Restore the next handler.
-  Pop(scratch2);
-  Str(scratch2, MemOperand(scratch1));
-
-  // Get the code object and state.  Restore the context and frame pointer.
-  Register object = scratch1;
-  Register state = scratch2;
-  Pop(object, state, cp, 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.
-  Label not_js_frame;
-  Cbz(cp, &not_js_frame);
-  Str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-  Bind(&not_js_frame);
-
-  JumpToHandlerEntry(value, object, state, scratch3, scratch4);
-}
-
-
-void MacroAssembler::ThrowUncatchable(Register value,
-                                      Register scratch1,
-                                      Register scratch2,
-                                      Register scratch3,
-                                      Register scratch4) {
-  // 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 handler expects the exception in x0.
-  DCHECK(value.Is(x0));
-
-  // Drop the stack pointer to the top of the top stack handler.
-  DCHECK(jssp.Is(StackPointer()));
-  Mov(scratch1, Operand(ExternalReference(Isolate::kHandlerAddress,
-                                          isolate())));
-  Ldr(jssp, MemOperand(scratch1));
-
-  // Unwind the handlers until the ENTRY handler is found.
-  Label fetch_next, check_kind;
-  B(&check_kind);
-  Bind(&fetch_next);
-  Peek(jssp, StackHandlerConstants::kNextOffset);
-
-  Bind(&check_kind);
-  STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
-  Peek(scratch2, StackHandlerConstants::kStateOffset);
-  TestAndBranchIfAnySet(scratch2, StackHandler::KindField::kMask, &fetch_next);
-
-  // Set the top handler address to next handler past the top ENTRY handler.
-  Pop(scratch2);
-  Str(scratch2, MemOperand(scratch1));
-
-  // Get the code object and state.  Clear the context and frame pointer (0 was
-  // saved in the handler).
-  Register object = scratch1;
-  Register state = scratch2;
-  Pop(object, state, cp, fp);
-
-  JumpToHandlerEntry(value, object, state, scratch3, scratch4);
-}
-
-
 void MacroAssembler::AssertSmi(Register object, BailoutReason reason) {
   if (emit_debug_code()) {
     STATIC_ASSERT(kSmiTag == 0);
@@ -3147,46 +3038,26 @@ void MacroAssembler::DebugBreak() {
 }
 
 
-void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
-                                    int handler_index) {
+void MacroAssembler::PushStackHandler() {
   DCHECK(jssp.Is(StackPointer()));
   // Adjust this code if the asserts don't hold.
-  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kSize == 1 * 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 the live registers x0-x4.
   // (See JSEntryStub::GenerateBody().)
 
-  unsigned state =
-      StackHandler::IndexField::encode(handler_index) |
-      StackHandler::KindField::encode(kind);
-
-  // Set up the code object and the state for pushing.
-  Mov(x10, Operand(CodeObject()));
-  Mov(x11, state);
-
-  // Push the frame pointer, context, state, and code object.
-  if (kind == StackHandler::JS_ENTRY) {
-    DCHECK(Smi::FromInt(0) == 0);
-    Push(xzr, xzr, x11, x10);
-  } else {
-    Push(fp, cp, x11, x10);
-  }
-
   // Link the current handler as the next handler.
   Mov(x11, ExternalReference(Isolate::kHandlerAddress, isolate()));
   Ldr(x10, MemOperand(x11));
   Push(x10);
+
   // Set this new handler as the current one.
   Str(jssp, MemOperand(x11));
 }
 
 
-void MacroAssembler::PopTryHandler() {
+void MacroAssembler::PopStackHandler() {
   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
   Pop(x10);
   Mov(x11, ExternalReference(Isolate::kHandlerAddress, isolate()));
@@ -3705,6 +3576,20 @@ void MacroAssembler::LoadElementsKindFromMap(Register result, Register map) {
 }
 
 
+void MacroAssembler::GetMapConstructor(Register result, Register map,
+                                       Register temp, Register temp2) {
+  Label done, loop;
+  Ldr(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
+  Bind(&loop);
+  JumpIfSmi(result, &done);
+  CompareObjectType(result, temp, temp2, MAP_TYPE);
+  B(ne, &done);
+  Ldr(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset));
+  B(&loop);
+  Bind(&done);
+}
+
+
 void MacroAssembler::TryGetFunctionPrototype(Register function,
                                              Register result,
                                              Register scratch,
@@ -3756,7 +3641,7 @@ void MacroAssembler::TryGetFunctionPrototype(Register function,
     // Non-instance prototype: fetch prototype from constructor field in initial
     // map.
     Bind(&non_instance);
-    Ldr(result, FieldMemOperand(result, Map::kConstructorOffset));
+    GetMapConstructor(result, result, scratch, scratch);
   }
 
   // All done.
index 3a0df0b..3937f6f 100644 (file)
@@ -1078,22 +1078,6 @@ class MacroAssembler : public Assembler {
   // This is required for compatibility in architecture indepenedant code.
   inline void jmp(Label* L) { B(L); }
 
-  // Passes thrown value to the handler of top of the try handler chain.
-  // Register value must be x0.
-  void Throw(Register value,
-             Register scratch1,
-             Register scratch2,
-             Register scratch3,
-             Register scratch4);
-
-  // Propagates an uncatchable exception to the top of the current JS stack's
-  // handler chain. Register value must be x0.
-  void ThrowUncatchable(Register value,
-                        Register scratch1,
-                        Register scratch2,
-                        Register scratch3,
-                        Register scratch4);
-
   void CallStub(CodeStub* stub, TypeFeedbackId ast_id = TypeFeedbackId::None());
   void TailCallStub(CodeStub* stub);
 
@@ -1289,12 +1273,12 @@ class MacroAssembler : public Assembler {
   // ---------------------------------------------------------------------------
   // Exception handling
 
-  // Push a new try handler and link into try handler chain.
-  void PushTryHandler(StackHandler::Kind kind, int handler_index);
+  // Push a new stack handler and link into stack handler chain.
+  void PushStackHandler();
 
-  // Unlink the stack handler on top of the stack from the try handler chain.
+  // Unlink the stack handler on top of the stack from the stack handler chain.
   // Must preserve the result register.
-  void PopTryHandler();
+  void PopStackHandler();
 
 
   // ---------------------------------------------------------------------------
@@ -1378,6 +1362,11 @@ class MacroAssembler : public Assembler {
     kDontMissOnBoundFunction
   };
 
+  // Machine code version of Map::GetConstructor().
+  // |temp| holds |result|'s map when done, and |temp2| its instance type.
+  void GetMapConstructor(Register result, Register map, Register temp,
+                         Register temp2);
+
   void TryGetFunctionPrototype(Register function,
                                Register result,
                                Register scratch,
@@ -2070,14 +2059,6 @@ class MacroAssembler : public Assembler {
   // have mixed types. The format string (x0) should not be included.
   void CallPrintf(int arg_count = 0, const CPURegister * args = NULL);
 
-  // Helper for throwing exceptions.  Compute a handler address and jump to
-  // it.  See the implementation for register usage.
-  void JumpToHandlerEntry(Register exception,
-                          Register object,
-                          Register state,
-                          Register scratch1,
-                          Register scratch2);
-
   // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
   void InNewSpace(Register object,
                   Condition cond,  // eq for new space, ne otherwise.
index 784f51f..12d2b4c 100644 (file)
@@ -240,7 +240,7 @@ function SparseMove(array, start_i, del_count, len, num_additional_args) {
   // Move data to new array.
   var new_array = new InternalArray(
       // Clamp array length to 2^32-1 to avoid early RangeError.
-      MathMin(len - del_count + num_additional_args, 0xffffffff));
+      $min(len - del_count + num_additional_args, 0xffffffff));
   var big_indices;
   var indices = %GetArrayKeys(array, len);
   if (IS_NUMBER(indices)) {
index cf00693..cbb5143 100644 (file)
@@ -39,16 +39,16 @@ function ArrayBufferSlice(start, end) {
   var first;
   var byte_length = %_ArrayBufferGetByteLength(this);
   if (relativeStart < 0) {
-    first = MathMax(byte_length + relativeStart, 0);
+    first = $max(byte_length + relativeStart, 0);
   } else {
-    first = MathMin(relativeStart, byte_length);
+    first = $min(relativeStart, byte_length);
   }
   var relativeEnd = IS_UNDEFINED(end) ? byte_length : end;
   var fin;
   if (relativeEnd < 0) {
-    fin = MathMax(byte_length + relativeEnd, 0);
+    fin = $max(byte_length + relativeEnd, 0);
   } else {
-    fin = MathMin(relativeEnd, byte_length);
+    fin = $min(relativeEnd, byte_length);
   }
 
   if (fin < first) {
index f4299ed..ffee104 100644 (file)
@@ -54,7 +54,7 @@
 #include "src/regexp-macro-assembler.h"
 #include "src/regexp-stack.h"
 #include "src/runtime/runtime.h"
-#include "src/serialize.h"
+#include "src/snapshot/serialize.h"
 #include "src/token.h"
 
 #if V8_TARGET_ARCH_IA32
@@ -292,11 +292,6 @@ int Label::pos() const {
 //               (Bits 6..31 of pc delta, with leading zeroes
 //                dropped, and last non-zero chunk tagged with 1.)
 
-
-#ifdef DEBUG
-const int kMaxStandardNonCompactModes = 14;
-#endif
-
 const int kTagBits = 2;
 const int kTagMask = (1 << kTagBits) - 1;
 const int kExtraTagBits = 4;
@@ -452,8 +447,6 @@ void RelocInfoWriter::Write(const RelocInfo* rinfo) {
 #endif
   DCHECK(rinfo->rmode() < RelocInfo::NUMBER_OF_MODES);
   DCHECK(rinfo->pc() - last_pc_ >= 0);
-  DCHECK(RelocInfo::LAST_STANDARD_NONCOMPACT_ENUM - RelocInfo::LAST_COMPACT_ENUM
-         <= kMaxStandardNonCompactModes);
   // Use unsigned delta-encoding for pc.
   uint32_t pc_delta = static_cast<uint32_t>(rinfo->pc() - last_pc_);
 
@@ -465,7 +458,7 @@ void RelocInfoWriter::Write(const RelocInfo* rinfo) {
     DCHECK(begin_pos - pos_ <= RelocInfo::kMaxCallSize);
   } else if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
     // Use signed delta-encoding for id.
-    DCHECK(static_cast<int>(rinfo->data()) == rinfo->data());
+    DCHECK_EQ(static_cast<int>(rinfo->data()), rinfo->data());
     int id_delta = static_cast<int>(rinfo->data()) - last_id_;
     // Check if delta is small enough to fit in a tagged byte.
     if (is_intn(id_delta, kSmallDataBits)) {
@@ -483,12 +476,12 @@ void RelocInfoWriter::Write(const RelocInfo* rinfo) {
     WriteTaggedData(rinfo->data(), kDeoptReasonTag);
   } else if (RelocInfo::IsPosition(rmode)) {
     // Use signed delta-encoding for position.
-    DCHECK(static_cast<int>(rinfo->data()) == rinfo->data());
+    DCHECK_EQ(static_cast<int>(rinfo->data()), rinfo->data());
     int pos_delta = static_cast<int>(rinfo->data()) - last_position_;
     if (rmode == RelocInfo::STATEMENT_POSITION) {
       WritePosition(pc_delta, pos_delta, rmode);
     } else {
-      DCHECK(rmode == RelocInfo::POSITION);
+      DCHECK_EQ(rmode, RelocInfo::POSITION);
       if (pc_delta != 0 || last_mode_ != RelocInfo::POSITION) {
         FlushPosition();
         next_position_candidate_pc_delta_ = pc_delta;
@@ -511,10 +504,14 @@ void RelocInfoWriter::Write(const RelocInfo* rinfo) {
                                                              : kVeneerPoolTag);
   } else {
     DCHECK(rmode > RelocInfo::LAST_COMPACT_ENUM);
-    int saved_mode = rmode - RelocInfo::LAST_COMPACT_ENUM;
+    DCHECK(rmode <= RelocInfo::LAST_STANDARD_NONCOMPACT_ENUM);
+    STATIC_ASSERT(RelocInfo::LAST_STANDARD_NONCOMPACT_ENUM -
+                      RelocInfo::LAST_COMPACT_ENUM <=
+                  kPoolExtraTag);
+    int saved_mode = rmode - RelocInfo::LAST_COMPACT_ENUM - 1;
     // For all other modes we simply use the mode as the extra tag.
     // None of these modes need a data component.
-    DCHECK(saved_mode < kPoolExtraTag);
+    DCHECK(0 <= saved_mode && saved_mode < kPoolExtraTag);
     WriteExtraTaggedPC(pc_delta, saved_mode);
   }
   last_pc_ = rinfo->pc();
@@ -721,7 +718,7 @@ void RelocIterator::next() {
         Advance(kIntSize);
       } else {
         AdvanceReadPC();
-        int rmode = extra_tag + RelocInfo::LAST_COMPACT_ENUM;
+        int rmode = extra_tag + RelocInfo::LAST_COMPACT_ENUM + 1;
         if (SetMode(static_cast<RelocInfo::Mode>(rmode))) return;
       }
     }
@@ -832,6 +829,8 @@ const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
       return "external reference";
     case RelocInfo::INTERNAL_REFERENCE:
       return "internal reference";
+    case RelocInfo::INTERNAL_REFERENCE_ENCODED:
+      return "encoded internal reference";
     case RelocInfo::DEOPT_REASON:
       return "deopt reason";
     case RelocInfo::CONST_POOL:
@@ -861,8 +860,10 @@ void RelocInfo::Print(Isolate* isolate, std::ostream& os) {  // NOLINT
     os << "  (" << Brief(target_object()) << ")";
   } else if (rmode_ == EXTERNAL_REFERENCE) {
     ExternalReferenceEncoder ref_encoder(isolate);
-    os << " (" << ref_encoder.NameOfAddress(target_reference()) << ")  ("
-       << static_cast<const void*>(target_reference()) << ")";
+    os << " ("
+       << ref_encoder.NameOfAddress(isolate, target_external_reference())
+       << ")  (" << static_cast<const void*>(target_external_reference())
+       << ")";
   } else if (IsCodeTarget(rmode_)) {
     Code* code = Code::GetCodeFromTargetAddress(target_address());
     os << " (" << Code::Kind2String(code->kind()) << ")  ("
@@ -910,13 +911,21 @@ void RelocInfo::Verify(Isolate* isolate) {
       CHECK(code->address() == HeapObject::cast(found)->address());
       break;
     }
+    case INTERNAL_REFERENCE:
+    case INTERNAL_REFERENCE_ENCODED: {
+      Address target = target_internal_reference();
+      Address pc = target_internal_reference_address();
+      Code* code = Code::cast(isolate->FindCodeObject(pc));
+      CHECK(target >= code->instruction_start());
+      CHECK(target <= code->instruction_end());
+      break;
+    }
     case RUNTIME_ENTRY:
     case JS_RETURN:
     case COMMENT:
     case POSITION:
     case STATEMENT_POSITION:
     case EXTERNAL_REFERENCE:
-    case INTERNAL_REFERENCE:
     case DEOPT_REASON:
     case CONST_POOL:
     case VENEER_POOL:
@@ -1223,8 +1232,7 @@ ExternalReference ExternalReference::old_pointer_space_allocation_limit_address(
 
 ExternalReference ExternalReference::old_data_space_allocation_top_address(
     Isolate* isolate) {
-  return ExternalReference(
-      isolate->heap()->OldDataSpaceAllocationTopAddress());
+  return ExternalReference(isolate->heap()->OldDataSpaceAllocationTopAddress());
 }
 
 
@@ -1265,18 +1273,6 @@ ExternalReference ExternalReference::address_of_pending_message_obj(
 }
 
 
-ExternalReference ExternalReference::address_of_has_pending_message(
-    Isolate* isolate) {
-  return ExternalReference(isolate->has_pending_message_address());
-}
-
-
-ExternalReference ExternalReference::address_of_pending_message_script(
-    Isolate* isolate) {
-  return ExternalReference(isolate->pending_message_script_address());
-}
-
-
 ExternalReference ExternalReference::address_of_min_int() {
   return ExternalReference(reinterpret_cast<void*>(&double_constants.min_int));
 }
@@ -1656,9 +1652,11 @@ bool PositionsRecorder::WriteRecordedPositions() {
 // Platform specific but identical code for all the platforms.
 
 
-void Assembler::RecordDeoptReason(const int reason, const int raw_position) {
+void Assembler::RecordDeoptReason(const int reason,
+                                  const SourcePosition position) {
   if (FLAG_trace_deopt || isolate()->cpu_profiler()->is_profiling()) {
     EnsureSpace ensure_space(this);
+    int raw_position = position.IsUnknown() ? 0 : position.raw();
     RecordRelocInfo(RelocInfo::POSITION, raw_position);
     RecordRelocInfo(RelocInfo::DEOPT_REASON, reason);
   }
index eb00f8a..ab37cd9 100644 (file)
@@ -379,6 +379,9 @@ class RelocInfo {
     EXTERNAL_REFERENCE,  // The address of an external C++ function.
     INTERNAL_REFERENCE,  // An address inside the same function.
 
+    // Encoded internal reference, used only on MIPS, MIPS64 and PPC.
+    INTERNAL_REFERENCE_ENCODED,
+
     // Marks constant and veneer pools. Only used on ARM and ARM64.
     // They use a custom noncompact encoding.
     CONST_POOL,
@@ -394,10 +397,6 @@ class RelocInfo {
     CODE_AGE_SEQUENCE,  // Not stored in RelocInfo array, used explictly by
                         // code aging.
 
-    // Encoded internal reference, used only on MIPS and MIPS64.
-    // Re-uses previous ARM-only encoding, to fit in RealRelocMode space.
-    INTERNAL_REFERENCE_ENCODED = CONST_POOL,
-
     FIRST_REAL_RELOC_MODE = CODE_TARGET,
     LAST_REAL_RELOC_MODE = VENEER_POOL,
     FIRST_PSEUDO_RELOC_MODE = CODE_AGE_SEQUENCE,
@@ -406,7 +405,7 @@ class RelocInfo {
     LAST_GCED_ENUM = CELL,
     // Modes <= LAST_COMPACT_ENUM are guaranteed to have compact encoding.
     LAST_COMPACT_ENUM = CODE_TARGET_WITH_ID,
-    LAST_STANDARD_NONCOMPACT_ENUM = INTERNAL_REFERENCE
+    LAST_STANDARD_NONCOMPACT_ENUM = INTERNAL_REFERENCE_ENCODED
   };
 
   RelocInfo() {}
@@ -476,6 +475,9 @@ class RelocInfo {
   static inline bool IsDebugBreakSlot(Mode mode) {
     return mode == DEBUG_BREAK_SLOT;
   }
+  static inline bool IsDebuggerStatement(Mode mode) {
+    return mode == DEBUG_BREAK;
+  }
   static inline bool IsNone(Mode mode) {
     return mode == NONE32 || mode == NONE64;
   }
@@ -575,9 +577,17 @@ class RelocInfo {
   // place, ready to be patched with the target.
   INLINE(int target_address_size());
 
-  // Read/modify the reference in the instruction this relocation
-  // applies to; can only be called if rmode_ is external_reference
-  INLINE(Address target_reference());
+  // Read the reference in the instruction this relocation
+  // applies to; can only be called if rmode_ is EXTERNAL_REFERENCE.
+  INLINE(Address target_external_reference());
+
+  // Read the reference in the instruction this relocation
+  // applies to; can only be called if rmode_ is INTERNAL_REFERENCE.
+  INLINE(Address target_internal_reference());
+
+  // Return the reference address this relocation applies to;
+  // can only be called if rmode_ is INTERNAL_REFERENCE.
+  INLINE(Address target_internal_reference_address());
 
   // Read/modify the address of a call instruction. This is used to relocate
   // the break points where straight-line code is patched with a call
@@ -595,9 +605,6 @@ class RelocInfo {
   template<typename StaticVisitor> inline void Visit(Heap* heap);
   inline void Visit(Isolate* isolate, ObjectVisitor* v);
 
-  // Patch the code with some other code.
-  void PatchCode(byte* instructions, int instruction_count);
-
   // Patch the code with a call.
   void PatchCodeWithCall(Address target, int guard_bytes);
 
@@ -951,8 +958,6 @@ class ExternalReference BASE_EMBEDDED {
 
   static ExternalReference scheduled_exception_address(Isolate* isolate);
   static ExternalReference address_of_pending_message_obj(Isolate* isolate);
-  static ExternalReference address_of_has_pending_message(Isolate* isolate);
-  static ExternalReference address_of_pending_message_script(Isolate* isolate);
 
   // Static variables containing common double constants.
   static ExternalReference address_of_min_int();
index ea25ad8..f63919c 100644 (file)
@@ -6,7 +6,6 @@
 
 #include "src/ast.h"
 #include "src/ast-numbering.h"
-#include "src/compiler.h"
 #include "src/scopes.h"
 
 namespace v8 {
@@ -18,6 +17,8 @@ class AstNumberingVisitor FINAL : public AstVisitor {
   explicit AstNumberingVisitor(Isolate* isolate, Zone* zone)
       : AstVisitor(),
         next_id_(BailoutId::FirstUsable().ToInt()),
+        properties_(zone),
+        ic_slot_cache_(FLAG_vector_ics ? 4 : 0),
         dont_optimize_reason_(kNoReason) {
     InitializeAstVisitor(isolate, zone);
   }
@@ -60,14 +61,15 @@ class AstNumberingVisitor FINAL : public AstVisitor {
   template <typename Node>
   void ReserveFeedbackSlots(Node* node) {
     FeedbackVectorRequirements reqs =
-        node->ComputeFeedbackRequirements(isolate());
+        node->ComputeFeedbackRequirements(isolate(), &ic_slot_cache_);
     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));
+      node->SetFirstFeedbackICSlot(FeedbackVectorICSlot(ic_slots),
+                                   &ic_slot_cache_);
       properties_.increase_ic_slots(reqs.ic_slots());
       if (FLAG_vector_ics) {
         for (int i = 0; i < reqs.ic_slots(); i++) {
@@ -81,6 +83,9 @@ class AstNumberingVisitor FINAL : public AstVisitor {
 
   int next_id_;
   AstProperties properties_;
+  // The slot cache allows us to reuse certain vector IC slots. It's only used
+  // if FLAG_vector_ics is true.
+  ICSlotCache ic_slot_cache_;
   BailoutReason dont_optimize_reason_;
 
   DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
@@ -186,7 +191,6 @@ void AstNumberingVisitor::VisitImportDeclaration(ImportDeclaration* node) {
   IncrementNodeCount();
   DisableOptimization(kImportDeclaration);
   VisitVariableProxy(node->proxy());
-  Visit(node->module());
 }
 
 
index fe33325..b34a55b 100644 (file)
@@ -230,37 +230,41 @@ class AstValue : public ZoneObject {
 
 
 // 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(is_construct_call, "_IsConstructCall")              \
-  F(let, "let")                                         \
-  F(make_reference_error, "MakeReferenceErrorEmbedded") \
-  F(make_syntax_error, "MakeSyntaxErrorEmbedded")       \
-  F(make_type_error, "MakeTypeErrorEmbedded")           \
-  F(native, "native")                                   \
-  F(new_target, "new.target")                           \
-  F(next, "next")                                       \
-  F(proto, "__proto__")                                 \
-  F(prototype, "prototype")                             \
-  F(this, "this")                                       \
-  F(use_asm, "use asm")                                 \
-  F(use_strong, "use strong")                           \
-  F(use_strict, "use strict")                           \
+#define STRING_CONSTANTS(F)                                                \
+  F(anonymous_function, "(anonymous function)")                            \
+  F(arguments, "arguments")                                                \
+  F(constructor, "constructor")                                            \
+  F(default, "default")                                                    \
+  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(is_construct_call, "_IsConstructCall")                                 \
+  F(is_spec_object, "_IsSpecObject")                                       \
+  F(let, "let")                                                            \
+  F(make_reference_error, "MakeReferenceErrorEmbedded")                    \
+  F(make_syntax_error, "MakeSyntaxErrorEmbedded")                          \
+  F(make_type_error, "MakeTypeErrorEmbedded")                              \
+  F(native, "native")                                                      \
+  F(new_target, "new.target")                                              \
+  F(next, "next")                                                          \
+  F(proto, "__proto__")                                                    \
+  F(prototype, "prototype")                                                \
+  F(this, "this")                                                          \
+  F(throw_iterator_result_not_an_object, "ThrowIteratorResultNotAnObject") \
+  F(to_string, "ToString")                                                 \
+  F(use_asm, "use asm")                                                    \
+  F(use_strong, "use strong")                                              \
+  F(use_strict, "use strict")                                              \
   F(value, "value")
 
 #define OTHER_CONSTANTS(F) \
index 7a7e3d3..8caf9c2 100644 (file)
@@ -59,24 +59,29 @@ bool Expression::IsUndefinedLiteral(Isolate* isolate) const {
 }
 
 
-VariableProxy::VariableProxy(Zone* zone, Variable* var, int position)
-    : Expression(zone, position),
+VariableProxy::VariableProxy(Zone* zone, Variable* var, int start_position,
+                             int end_position)
+    : Expression(zone, start_position),
       bit_field_(IsThisField::encode(var->is_this()) |
                  IsAssignedField::encode(false) |
                  IsResolvedField::encode(false)),
       variable_feedback_slot_(FeedbackVectorICSlot::Invalid()),
-      raw_name_(var->raw_name()) {
+      raw_name_(var->raw_name()),
+      end_position_(end_position) {
   BindTo(var);
 }
 
 
-VariableProxy::VariableProxy(Zone* zone, const AstRawString* name, bool is_this,
-                             int position)
-    : Expression(zone, position),
-      bit_field_(IsThisField::encode(is_this) | IsAssignedField::encode(false) |
+VariableProxy::VariableProxy(Zone* zone, const AstRawString* name,
+                             Variable::Kind variable_kind, int start_position,
+                             int end_position)
+    : Expression(zone, start_position),
+      bit_field_(IsThisField::encode(variable_kind == Variable::THIS) |
+                 IsAssignedField::encode(false) |
                  IsResolvedField::encode(false)),
       variable_feedback_slot_(FeedbackVectorICSlot::Invalid()),
-      raw_name_(name) {}
+      raw_name_(name),
+      end_position_(end_position) {}
 
 
 void VariableProxy::BindTo(Variable* var) {
@@ -87,6 +92,35 @@ void VariableProxy::BindTo(Variable* var) {
 }
 
 
+void VariableProxy::SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                                           ICSlotCache* cache) {
+  variable_feedback_slot_ = slot;
+  if (var()->IsUnallocated()) {
+    cache->Add(VariableICSlotPair(var(), slot));
+  }
+}
+
+
+FeedbackVectorRequirements VariableProxy::ComputeFeedbackRequirements(
+    Isolate* isolate, const ICSlotCache* cache) {
+  if (UsesVariableFeedbackSlot()) {
+    // VariableProxies that point to the same Variable within a function can
+    // make their loads from the same IC slot.
+    if (var()->IsUnallocated()) {
+      for (int i = 0; i < cache->length(); i++) {
+        VariableICSlotPair& pair = cache->at(i);
+        if (pair.variable() == var()) {
+          variable_feedback_slot_ = pair.slot();
+          return FeedbackVectorRequirements(0, 0);
+        }
+      }
+    }
+    return FeedbackVectorRequirements(0, 1);
+  }
+  return FeedbackVectorRequirements(0, 0);
+}
+
+
 Assignment::Assignment(Zone* zone, Token::Value op, Expression* target,
                        Expression* value, int pos)
     : Expression(zone, pos),
@@ -562,7 +596,8 @@ bool Call::IsUsingCallFeedbackSlot(Isolate* isolate) const {
 }
 
 
-FeedbackVectorRequirements Call::ComputeFeedbackRequirements(Isolate* isolate) {
+FeedbackVectorRequirements Call::ComputeFeedbackRequirements(
+    Isolate* isolate, const ICSlotCache* cache) {
   int ic_slots = IsUsingCallFeedbackICSlot(isolate) ? 1 : 0;
   int slots = IsUsingCallFeedbackSlot(isolate) ? 1 : 0;
   // A Call uses either a slot or an IC slot.
@@ -590,48 +625,6 @@ Call::CallType Call::GetCallType(Isolate* isolate) const {
 }
 
 
-bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
-                               LookupIterator* it) {
-  target_ = Handle<JSFunction>::null();
-  cell_ = Handle<Cell>::null();
-  DCHECK(it->IsFound() && it->GetHolder<JSObject>().is_identical_to(global));
-  cell_ = it->GetPropertyCell();
-  if (cell_->value()->IsJSFunction()) {
-    Handle<JSFunction> candidate(JSFunction::cast(cell_->value()));
-    // If the function is in new space we assume it's more likely to
-    // change and thus prefer the general IC code.
-    if (!it->isolate()->heap()->InNewSpace(*candidate)) {
-      target_ = candidate;
-      return true;
-    }
-  }
-  return false;
-}
-
-
-void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
-  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());
-  }
-}
-
-
-void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
-  DCHECK(!is_computed_name());
-  TypeFeedbackId id = key()->AsLiteral()->LiteralFeedbackId();
-  SmallMapList maps;
-  oracle->CollectReceiverTypes(id, &maps);
-  receiver_type_ = maps.length() == 1 ? maps.at(0)
-                                      : Handle<Map>::null();
-}
-
-
 // ----------------------------------------------------------------------------
 // Implementation of AstVisitor
 
index 39bef91..27e8f09 100644 (file)
@@ -165,11 +165,30 @@ class FeedbackVectorRequirements {
 };
 
 
+class VariableICSlotPair FINAL {
+ public:
+  VariableICSlotPair(Variable* variable, FeedbackVectorICSlot slot)
+      : variable_(variable), slot_(slot) {}
+  VariableICSlotPair()
+      : variable_(NULL), slot_(FeedbackVectorICSlot::Invalid()) {}
+
+  Variable* variable() const { return variable_; }
+  FeedbackVectorICSlot slot() const { return slot_; }
+
+ private:
+  Variable* variable_;
+  FeedbackVectorICSlot slot_;
+};
+
+
+typedef List<VariableICSlotPair> ICSlotCache;
+
+
 class AstProperties FINAL BASE_EMBEDDED {
  public:
   class Flags : public EnumSet<AstPropertiesFlag, int> {};
 
-  AstProperties() : node_count_(0) {}
+  explicit AstProperties(Zone* zone) : node_count_(0), spec_(zone) {}
 
   Flags* flags() { return &flags_; }
   int node_count() { return node_count_; }
@@ -181,12 +200,12 @@ class AstProperties FINAL BASE_EMBEDDED {
   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_; }
+  const ZoneFeedbackVectorSpec* get_spec() const { return &spec_; }
 
  private:
   Flags flags_;
   int node_count_;
-  FeedbackVectorSpec spec_;
+  ZoneFeedbackVectorSpec spec_;
 };
 
 
@@ -229,11 +248,12 @@ class AstNode: public ZoneObject {
   // 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) {
+      Isolate* isolate, const ICSlotCache* cache) {
     return FeedbackVectorRequirements(0, 0);
   }
   virtual void SetFirstFeedbackSlot(FeedbackVectorSlot slot) { UNREACHABLE(); }
-  virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) {
+  virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                                      ICSlotCache* cache) {
     UNREACHABLE();
   }
   // Each ICSlot stores a kind of IC which the participating node should know.
@@ -609,23 +629,27 @@ class ImportDeclaration FINAL : public Declaration {
  public:
   DECLARE_NODE_TYPE(ImportDeclaration)
 
-  Module* module() const { return module_; }
+  const AstRawString* import_name() const { return import_name_; }
+  const AstRawString* module_specifier() const { return module_specifier_; }
+  void set_module_specifier(const AstRawString* module_specifier) {
+    DCHECK(module_specifier_ == NULL);
+    module_specifier_ = module_specifier;
+  }
   InitializationFlag initialization() const OVERRIDE {
-    return kCreatedInitialized;
+    return kNeedsInitialization;
   }
 
  protected:
-  ImportDeclaration(Zone* zone,
-                    VariableProxy* proxy,
-                    Module* module,
-                    Scope* scope,
-                    int pos)
-      : Declaration(zone, proxy, LET, scope, pos),
-        module_(module) {
-  }
+  ImportDeclaration(Zone* zone, VariableProxy* proxy,
+                    const AstRawString* import_name,
+                    const AstRawString* module_specifier, Scope* scope, int pos)
+      : Declaration(zone, proxy, IMPORT, scope, pos),
+        import_name_(import_name),
+        module_specifier_(module_specifier) {}
 
  private:
-  Module* module_;
+  const AstRawString* import_name_;
+  const AstRawString* module_specifier_;
 };
 
 
@@ -880,7 +904,7 @@ class ForInStatement FINAL : public ForEachStatement {
 
   // Type feedback information.
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE {
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE {
     return FeedbackVectorRequirements(1, 0);
   }
   void SetFirstFeedbackSlot(FeedbackVectorSlot slot) OVERRIDE {
@@ -942,12 +966,12 @@ class ForOfStatement FINAL : public ForEachStatement {
     return subject();
   }
 
-  // var iterator = subject[Symbol.iterator]();
+  // iterator = subject[Symbol.iterator]()
   Expression* assign_iterator() const {
     return assign_iterator_;
   }
 
-  // var result = iterator.next();
+  // result = iterator.next()  // with type check
   Expression* next_result() const {
     return next_result_;
   }
@@ -1414,7 +1438,6 @@ class ObjectLiteralProperty FINAL : public ZoneObject {
   Kind kind() { return kind_; }
 
   // Type feedback information.
-  void RecordTypeFeedback(TypeFeedbackOracle* oracle);
   bool IsMonomorphic() { return !receiver_type_.is_null(); }
   Handle<Map> GetReceiverType() { return receiver_type_; }
 
@@ -1426,6 +1449,8 @@ class ObjectLiteralProperty FINAL : public ZoneObject {
   bool is_static() const { return is_static_; }
   bool is_computed_name() const { return is_computed_name_; }
 
+  void set_receiver_type(Handle<Map> map) { receiver_type_ = map; }
+
  protected:
   friend class AstNodeFactory;
 
@@ -1614,9 +1639,7 @@ class VariableProxy FINAL : public Expression {
  public:
   DECLARE_NODE_TYPE(VariableProxy)
 
-  bool IsValidReferenceExpression() const OVERRIDE {
-    return !is_resolved() || var()->IsValidReference();
-  }
+  bool IsValidReferenceExpression() const OVERRIDE { return !is_this(); }
 
   bool IsArguments() const { return is_resolved() && var()->is_arguments(); }
 
@@ -1647,6 +1670,8 @@ class VariableProxy FINAL : public Expression {
     bit_field_ = IsResolvedField::update(bit_field_, true);
   }
 
+  int end_position() const { return end_position_; }
+
   // Bind this proxy to the variable var.
   void BindTo(Variable* var);
 
@@ -1655,13 +1680,10 @@ class VariableProxy FINAL : public Expression {
   }
 
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE {
-    return FeedbackVectorRequirements(0, UsesVariableFeedbackSlot() ? 1 : 0);
-  }
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE;
 
-  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
-    variable_feedback_slot_ = slot;
-  }
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                              ICSlotCache* cache) OVERRIDE;
   Code::Kind FeedbackICSlotKind(int index) OVERRIDE { return Code::LOAD_IC; }
   FeedbackVectorICSlot VariableFeedbackSlot() {
     DCHECK(!UsesVariableFeedbackSlot() || !variable_feedback_slot_.IsInvalid());
@@ -1669,10 +1691,12 @@ class VariableProxy FINAL : public Expression {
   }
 
  protected:
-  VariableProxy(Zone* zone, Variable* var, int position);
+  VariableProxy(Zone* zone, Variable* var, int start_position,
+                int end_position);
 
-  VariableProxy(Zone* zone, const AstRawString* name, bool is_this,
-                int position);
+  VariableProxy(Zone* zone, const AstRawString* name,
+                Variable::Kind variable_kind, int start_position,
+                int end_position);
 
   class IsThisField : public BitField8<bool, 0, 1> {};
   class IsAssignedField : public BitField8<bool, 1, 1> {};
@@ -1686,6 +1710,10 @@ class VariableProxy FINAL : public Expression {
     const AstRawString* raw_name_;  // if !is_resolved_
     Variable* var_;                 // if is_resolved_
   };
+  // Position is stored in the AstNode superclass, but VariableProxy needs to
+  // know its end position too (for error messages). It cannot be inferred from
+  // the variable name length because it can contain escapes.
+  int end_position_;
 };
 
 
@@ -1738,10 +1766,11 @@ class Property FINAL : public Expression {
   }
 
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE {
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE {
     return FeedbackVectorRequirements(0, FLAG_vector_ics ? 1 : 0);
   }
-  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                              ICSlotCache* cache) OVERRIDE {
     property_feedback_slot_ = slot;
   }
   Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
@@ -1788,8 +1817,9 @@ class Call FINAL : public Expression {
 
   // Type feedback information.
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE;
-  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE;
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                              ICSlotCache* cache) OVERRIDE {
     ic_slot_or_slot_ = slot.ToInt();
   }
   void SetFirstFeedbackSlot(FeedbackVectorSlot slot) OVERRIDE {
@@ -1832,15 +1862,16 @@ class Call FINAL : public Expression {
 
   Handle<JSFunction> target() { return target_; }
 
-  Handle<Cell> cell() { return cell_; }
-
   Handle<AllocationSite> allocation_site() { return allocation_site_; }
 
+  void SetKnownGlobalTarget(Handle<JSFunction> target) {
+    target_ = target;
+    set_is_uninitialized(false);
+  }
   void set_target(Handle<JSFunction> target) { target_ = target; }
   void set_allocation_site(Handle<AllocationSite> site) {
     allocation_site_ = site;
   }
-  bool ComputeGlobalTarget(Handle<GlobalObject> global, LookupIterator* it);
 
   static int num_ids() { return parent_num_ids() + 2; }
   BailoutId ReturnId() const { return BailoutId(local_id(0)); }
@@ -1895,7 +1926,6 @@ class Call FINAL : public Expression {
   Expression* expression_;
   ZoneList<Expression*>* arguments_;
   Handle<JSFunction> target_;
-  Handle<Cell> cell_;
   Handle<AllocationSite> allocation_site_;
   class IsUninitializedField : public BitField8<bool, 0, 1> {};
   uint8_t bit_field_;
@@ -1911,7 +1941,7 @@ class CallNew FINAL : public Expression {
 
   // Type feedback information.
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE {
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE {
     return FeedbackVectorRequirements(FLAG_pretenuring_call_new ? 2 : 1, 0);
   }
   void SetFirstFeedbackSlot(FeedbackVectorSlot slot) OVERRIDE {
@@ -1927,7 +1957,6 @@ class CallNew FINAL : public Expression {
     return CallNewFeedbackSlot().next();
   }
 
-  void RecordTypeFeedback(TypeFeedbackOracle* oracle);
   bool IsMonomorphic() OVERRIDE { return is_monomorphic_; }
   Handle<JSFunction> target() const { return target_; }
   Handle<AllocationSite> allocation_site() const {
@@ -1938,6 +1967,16 @@ class CallNew FINAL : public Expression {
   static int feedback_slots() { return 1; }
   BailoutId ReturnId() const { return BailoutId(local_id(0)); }
 
+  void set_allocation_site(Handle<AllocationSite> site) {
+    allocation_site_ = site;
+  }
+  void set_is_monomorphic(bool monomorphic) { is_monomorphic_ = monomorphic; }
+  void set_target(Handle<JSFunction> target) { target_ = target; }
+  void SetKnownGlobalTarget(Handle<JSFunction> target) {
+    target_ = target;
+    is_monomorphic_ = true;
+  }
+
  protected:
   CallNew(Zone* zone, Expression* expression, ZoneList<Expression*>* arguments,
           int pos)
@@ -1980,10 +2019,11 @@ class CallRuntime FINAL : public Expression {
     return FLAG_vector_ics && is_jsruntime();
   }
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE {
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE {
     return FeedbackVectorRequirements(0, HasCallRuntimeFeedbackSlot() ? 1 : 0);
   }
-  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                              ICSlotCache* cache) OVERRIDE {
     callruntime_feedback_slot_ = slot;
   }
   Code::Kind FeedbackICSlotKind(int index) OVERRIDE { return Code::LOAD_IC; }
@@ -2072,12 +2112,11 @@ class BinaryOperation FINAL : public Expression {
     return TypeFeedbackId(local_id(1));
   }
   Maybe<int> fixed_right_arg() const {
-    return has_fixed_right_arg_ ? Maybe<int>(fixed_right_arg_value_)
-                                : Maybe<int>();
+    return has_fixed_right_arg_ ? Just(fixed_right_arg_value_) : Nothing<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;
+    has_fixed_right_arg_ = arg.IsJust();
+    if (arg.IsJust()) fixed_right_arg_value_ = arg.FromJust();
   }
 
   virtual void RecordToBooleanTypeFeedback(
@@ -2354,10 +2393,11 @@ class Yield FINAL : public Expression {
     return FLAG_vector_ics && (yield_kind() == kDelegating);
   }
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE {
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE {
     return FeedbackVectorRequirements(0, HasFeedbackSlots() ? 3 : 0);
   }
-  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                              ICSlotCache* cache) OVERRIDE {
     yield_first_feedback_slot_ = slot;
   }
   Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
@@ -2534,7 +2574,7 @@ class FunctionLiteral FINAL : public Expression {
   void set_ast_properties(AstProperties* ast_properties) {
     ast_properties_ = *ast_properties;
   }
-  const FeedbackVectorSpec& feedback_vector_spec() const {
+  const ZoneFeedbackVectorSpec* feedback_vector_spec() const {
     return ast_properties_.get_spec();
   }
   bool dont_optimize() { return dont_optimize_reason_ != kNoReason; }
@@ -2558,6 +2598,7 @@ class FunctionLiteral FINAL : public Expression {
         scope_(scope),
         body_(body),
         raw_inferred_name_(ast_value_factory->empty_string()),
+        ast_properties_(zone),
         dont_optimize_reason_(kNoReason),
         materialized_literal_count_(materialized_literal_count),
         expected_property_count_(expected_property_count),
@@ -2598,7 +2639,7 @@ class FunctionLiteral FINAL : public Expression {
   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, 7> {};
+  class FunctionKindBits : public BitField<FunctionKind, 6, 8> {};
 };
 
 
@@ -2695,10 +2736,11 @@ class SuperReference FINAL : public Expression {
 
   // Type feedback information.
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE {
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE {
     return FeedbackVectorRequirements(0, FLAG_vector_ics ? 1 : 0);
   }
-  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                              ICSlotCache* cache) OVERRIDE {
     homeobject_feedback_slot_ = slot;
   }
   Code::Kind FeedbackICSlotKind(int index) OVERRIDE { return Code::LOAD_IC; }
@@ -3171,10 +3213,11 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
   }
 
   ImportDeclaration* NewImportDeclaration(VariableProxy* proxy,
-                                          Module* module,
-                                          Scope* scope,
-                                          int pos) {
-    return new (zone_) ImportDeclaration(zone_, proxy, module, scope, pos);
+                                          const AstRawString* import_name,
+                                          const AstRawString* module_specifier,
+                                          Scope* scope, int pos) {
+    return new (zone_) ImportDeclaration(zone_, proxy, import_name,
+                                         module_specifier, scope, pos);
   }
 
   ExportDeclaration* NewExportDeclaration(VariableProxy* proxy,
@@ -3369,14 +3412,17 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
   }
 
   VariableProxy* NewVariableProxy(Variable* var,
-                                  int pos = RelocInfo::kNoPosition) {
-    return new (zone_) VariableProxy(zone_, var, pos);
+                                  int start_position = RelocInfo::kNoPosition,
+                                  int end_position = RelocInfo::kNoPosition) {
+    return new (zone_) VariableProxy(zone_, var, start_position, end_position);
   }
 
   VariableProxy* NewVariableProxy(const AstRawString* name,
-                                  bool is_this,
-                                  int position = RelocInfo::kNoPosition) {
-    return new (zone_) VariableProxy(zone_, name, is_this, position);
+                                  Variable::Kind variable_kind,
+                                  int start_position = RelocInfo::kNoPosition,
+                                  int end_position = RelocInfo::kNoPosition) {
+    return new (zone_)
+        VariableProxy(zone_, name, variable_kind, start_position, end_position);
   }
 
   Property* NewProperty(Expression* obj, Expression* key, int pos) {
index cb31cc9..dcc5eb4 100644 (file)
@@ -10,27 +10,35 @@ namespace internal {
 BackgroundParsingTask::BackgroundParsingTask(
     StreamedSource* source, ScriptCompiler::CompileOptions options,
     int stack_size, Isolate* isolate)
-    : source_(source), options_(options), stack_size_(stack_size) {
-  // Prepare the data for the internalization phase and compilation phase, which
-  // will happen in the main thread after parsing.
-  source->info.Reset(new i::CompilationInfoWithZone(source->source_stream.get(),
-                                                    source->encoding, isolate));
-  source->info->MarkAsGlobal();
-
+    : source_(source), stack_size_(stack_size) {
   // We don't set the context to the CompilationInfo yet, because the background
   // thread cannot do anything with it anyway. We set it just before compilation
   // on the foreground thread.
   DCHECK(options == ScriptCompiler::kProduceParserCache ||
          options == ScriptCompiler::kProduceCodeCache ||
          options == ScriptCompiler::kNoCompileOptions);
-  source->allow_lazy =
-      !i::Compiler::DebuggerWantsEagerCompilation(source->info.get());
 
-  if (!source->allow_lazy && options_ == ScriptCompiler::kProduceParserCache) {
+  // Prepare the data for the internalization phase and compilation phase, which
+  // will happen in the main thread after parsing.
+  Zone* zone = new Zone();
+  ParseInfo* info = new ParseInfo(zone);
+  source->zone.Reset(zone);
+  source->info.Reset(info);
+  info->set_isolate(isolate);
+  info->set_source_stream(source->source_stream.get());
+  info->set_source_stream_encoding(source->encoding);
+  info->set_hash_seed(isolate->heap()->HashSeed());
+  info->set_global();
+  info->set_unicode_cache(&source_->unicode_cache);
+
+  bool disable_lazy = Compiler::DebuggerWantsEagerCompilation(isolate);
+  if (disable_lazy && options == ScriptCompiler::kProduceParserCache) {
     // Producing cached data while parsing eagerly is not supported.
-    options_ = ScriptCompiler::kNoCompileOptions;
+    options = ScriptCompiler::kNoCompileOptions;
   }
-  source->hash_seed = isolate->heap()->HashSeed();
+
+  info->set_compile_options(options);
+  info->set_allow_lazy_parsing(!disable_lazy);
 }
 
 
@@ -40,20 +48,19 @@ void BackgroundParsingTask::Run() {
   DisallowHandleDereference no_deref;
 
   ScriptData* script_data = NULL;
-  if (options_ == ScriptCompiler::kProduceParserCache ||
-      options_ == ScriptCompiler::kProduceCodeCache) {
-    source_->info->SetCachedData(&script_data, options_);
+  ScriptCompiler::CompileOptions options = source_->info->compile_options();
+  if (options == ScriptCompiler::kProduceParserCache ||
+      options == ScriptCompiler::kProduceCodeCache) {
+    source_->info->set_cached_data(&script_data);
   }
 
   uintptr_t stack_limit =
       reinterpret_cast<uintptr_t>(&stack_limit) - stack_size_ * KB;
 
+  source_->info->set_stack_limit(stack_limit);
   // Parser needs to stay alive for finalizing the parsing on the main
   // thread. Passing &parse_info is OK because Parser doesn't store it.
-  source_->parser.Reset(new Parser(source_->info.get(), stack_limit,
-                                   source_->hash_seed,
-                                   &source_->unicode_cache));
-  source_->parser->set_allow_lazy(source_->allow_lazy);
+  source_->parser.Reset(new Parser(source_->info.get()));
   source_->parser->ParseOnBackground(source_->info.get());
 
   if (script_data != NULL) {
index 19c93a8..80e1e27 100644 (file)
 namespace v8 {
 namespace internal {
 
-class Parser;
-
 // Internal representation of v8::ScriptCompiler::StreamedSource. Contains all
 // data which needs to be transmitted between threads for background parsing,
 // finalizing it on the main thread, and compiling on the main thread.
 struct StreamedSource {
   StreamedSource(ScriptCompiler::ExternalSourceStream* source_stream,
                  ScriptCompiler::StreamedSource::Encoding encoding)
-      : source_stream(source_stream),
-        encoding(encoding),
-        hash_seed(0),
-        allow_lazy(false) {}
+      : source_stream(source_stream), encoding(encoding) {}
 
   // Internal implementation of v8::ScriptCompiler::StreamedSource.
   SmartPointer<ScriptCompiler::ExternalSourceStream> source_stream;
@@ -36,9 +31,8 @@ struct StreamedSource {
   // between parsing and compilation. These need to be initialized before the
   // compilation starts.
   UnicodeCache unicode_cache;
-  SmartPointer<CompilationInfo> info;
-  uint32_t hash_seed;
-  bool allow_lazy;
+  SmartPointer<Zone> zone;
+  SmartPointer<ParseInfo> info;
   SmartPointer<Parser> parser;
 
  private:
@@ -58,7 +52,6 @@ class BackgroundParsingTask : public ScriptCompiler::ScriptStreamingTask {
 
  private:
   StreamedSource* source_;  // Not owned.
-  ScriptCompiler::CompileOptions options_;
   int stack_size_;
 };
 }
index 8bfe7a9..9b801c8 100644 (file)
@@ -116,19 +116,10 @@ namespace internal {
     "Improper object on prototype chain for store")                            \
   V(kIndexIsNegative, "Index is negative")                                     \
   V(kIndexIsTooLarge, "Index is too large")                                    \
-  V(kInlinedRuntimeFunctionClassOf, "Inlined runtime function: ClassOf")       \
   V(kInlinedRuntimeFunctionFastOneByteArrayJoin,                               \
     "Inlined runtime function: FastOneByteArrayJoin")                          \
-  V(kInlinedRuntimeFunctionGeneratorNext,                                      \
-    "Inlined runtime function: GeneratorNext")                                 \
-  V(kInlinedRuntimeFunctionGeneratorThrow,                                     \
-    "Inlined runtime function: GeneratorThrow")                                \
   V(kInlinedRuntimeFunctionGetFromCache,                                       \
     "Inlined runtime function: GetFromCache")                                  \
-  V(kInlinedRuntimeFunctionIsNonNegativeSmi,                                   \
-    "Inlined runtime function: IsNonNegativeSmi")                              \
-  V(kInlinedRuntimeFunctionIsStringWrapperSafeForDefaultValueOf,               \
-    "Inlined runtime function: IsStringWrapperSafeForDefaultValueOf")          \
   V(kInliningBailedOut, "Inlining bailed out")                                 \
   V(kInputGPRIsExpectedToHaveUpper32Cleared,                                   \
     "Input GPR is expected to have upper32 cleared")                           \
@@ -310,7 +301,6 @@ namespace internal {
   V(kUnexpectedUnusedPropertiesOfStringWrapper,                                \
     "Unexpected unused properties of string wrapper")                          \
   V(kUnimplemented, "unimplemented")                                           \
-  V(kUninitializedKSmiConstantRegister, "Uninitialized kSmiConstantRegister")  \
   V(kUnsupportedConstCompoundAssignment,                                       \
     "Unsupported const compound assignment")                                   \
   V(kUnsupportedCountOperationWithConst,                                       \
@@ -345,7 +335,8 @@ enum BailoutReason {
 
 
 const char* GetBailoutReason(BailoutReason reason);
-}
-}  // namespace v8::internal
+
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_BAILOUT_REASON_H_
index 0f4d4c7..5c7cd74 100644 (file)
@@ -148,17 +148,30 @@ inline uint32_t RoundDownToPowerOfTwo32(uint32_t value) {
 }
 
 
+// Precondition: 0 <= shift < 32
 inline uint32_t RotateRight32(uint32_t value, uint32_t shift) {
   if (shift == 0) return value;
   return (value >> shift) | (value << (32 - shift));
 }
 
+// Precondition: 0 <= shift < 32
+inline uint32_t RotateLeft32(uint32_t value, uint32_t shift) {
+  if (shift == 0) return value;
+  return (value << shift) | (value >> (32 - shift));
+}
 
+// Precondition: 0 <= shift < 64
 inline uint64_t RotateRight64(uint64_t value, uint64_t shift) {
   if (shift == 0) return value;
   return (value >> shift) | (value << (64 - shift));
 }
 
+// Precondition: 0 <= shift < 64
+inline uint64_t RotateLeft64(uint64_t value, uint64_t shift) {
+  if (shift == 0) return value;
+  return (value << shift) | (value >> (64 - shift));
+}
+
 
 // SignedAddOverflow32(lhs,rhs,val) performs a signed summation of |lhs| and
 // |rhs| and stores the result into the variable pointed to by |val| and
index 84cd231..872b20d 100644 (file)
@@ -385,6 +385,8 @@ CPU::CPU()
         case 0x37:  // SLM
         case 0x4a:
         case 0x4d:
+        case 0x4c:  // AMT
+        case 0x6e:
           is_atom_ = true;
       }
     }
index 25d77bb..a2688c9 100644 (file)
@@ -5,10 +5,11 @@
 #include "src/base/logging.h"
 
 #if V8_LIBC_GLIBC || V8_OS_BSD
-# include <cxxabi.h>
-# include <execinfo.h>
+#include <cxxabi.h>
+#include <dlfcn.h>
+#include <execinfo.h>
 #elif V8_OS_QNX
-# include <backtrace.h>
+#include <backtrace.h>
 #endif  // V8_LIBC_GLIBC || V8_OS_BSD
 
 #include <cstdio>
@@ -54,28 +55,24 @@ void DumpBacktrace() {
 #if V8_LIBC_GLIBC || V8_OS_BSD
   void* trace[100];
   int size = backtrace(trace, arraysize(trace));
-  char** symbols = backtrace_symbols(trace, size);
   OS::PrintError("\n==== C stack trace ===============================\n\n");
   if (size == 0) {
     OS::PrintError("(empty)\n");
-  } else if (symbols == NULL) {
-    OS::PrintError("(no symbols)\n");
   } else {
     for (int i = 1; i < size; ++i) {
       OS::PrintError("%2d: ", i);
-      char mangled[201];
-      if (sscanf(symbols[i], "%*[^(]%*[(]%200[^)+]", mangled) == 1) {  // NOLINT
-        int status;
-        size_t length;
-        char* demangled = abi::__cxa_demangle(mangled, NULL, &length, &status);
-        OS::PrintError("%s\n", demangled != NULL ? demangled : mangled);
+      Dl_info info;
+      char* demangled = NULL;
+      if (!dladdr(trace[i], &info) || !info.dli_sname) {
+        OS::PrintError("%p\n", trace[i]);
+      } else if ((demangled = abi::__cxa_demangle(info.dli_sname, 0, 0, 0))) {
+        OS::PrintError("%s\n", demangled);
         free(demangled);
       } else {
-        OS::PrintError("??\n");
+        OS::PrintError("%s\n", info.dli_sname);
       }
     }
   }
-  free(symbols);
 #elif V8_OS_QNX
   char out[1024];
   bt_accessor_t acc;
index 58316f8..68ed70a 100644 (file)
@@ -188,7 +188,7 @@ VirtualMemory::VirtualMemory(size_t size, size_t alignment)
   void* reservation = mmap(OS::GetRandomMmapAddr(),
                            request_size,
                            PROT_NONE,
-                           MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+                           MAP_PRIVATE | MAP_ANON,
                            kMmapFd,
                            kMmapFdOffset);
   if (reservation == MAP_FAILED) return;
@@ -260,7 +260,7 @@ void* VirtualMemory::ReserveRegion(size_t size) {
   void* result = mmap(OS::GetRandomMmapAddr(),
                       size,
                       PROT_NONE,
-                      MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+                      MAP_PRIVATE | MAP_ANON,
                       kMmapFd,
                       kMmapFdOffset);
 
@@ -288,7 +288,7 @@ bool VirtualMemory::UncommitRegion(void* base, size_t size) {
   return mmap(base,
               size,
               PROT_NONE,
-              MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
+              MAP_PRIVATE | MAP_ANON | MAP_FIXED,
               kMmapFd,
               kMmapFdOffset) != MAP_FAILED;
 }
index dc35d3d..e43493f 100644 (file)
@@ -358,6 +358,11 @@ bool OS::Remove(const char* path) {
 }
 
 
+bool OS::isDirectorySeparator(const char ch) {
+  return ch == '/';
+}
+
+
 FILE* OS::OpenTemporaryFile() {
   return tmpfile();
 }
index 5a6f2f1..07c0bc3 100644 (file)
@@ -575,6 +575,11 @@ bool OS::Remove(const char* path) {
 }
 
 
+bool OS::isDirectorySeparator(const char ch) {
+  return ch == '/' || ch == '\\';
+}
+
+
 FILE* OS::OpenTemporaryFile() {
   // tmpfile_s tries to use the root dir, don't use it.
   char tempPathBuffer[MAX_PATH];
index 07155f7..1873bbe 100644 (file)
@@ -142,6 +142,8 @@ class OS {
   static FILE* FOpen(const char* path, const char* mode);
   static bool Remove(const char* path);
 
+  static bool isDirectorySeparator(const char ch);
+
   // Opens a temporary file, the file is auto removed on close.
   static FILE* OpenTemporaryFile();
 
index 2592bb7..f094625 100644 (file)
@@ -13,8 +13,8 @@
 #include "src/extensions/statistics-extension.h"
 #include "src/extensions/trigger-failure-extension.h"
 #include "src/isolate-inl.h"
-#include "src/natives.h"
-#include "src/snapshot.h"
+#include "src/snapshot/natives.h"
+#include "src/snapshot/snapshot.h"
 #include "third_party/fdlibm/fdlibm.h"
 
 namespace v8 {
@@ -140,6 +140,7 @@ class Genesis BASE_EMBEDDED {
   Handle<JSFunction> GetGeneratorPoisonFunction();
 
   void CreateStrictModeFunctionMaps(Handle<JSFunction> empty);
+  void CreateStrongModeFunctionMaps(Handle<JSFunction> empty);
 
   // Make the "arguments" and "caller" properties throw a TypeError on access.
   void PoisonArgumentsAndCaller(Handle<Map> map);
@@ -256,18 +257,21 @@ class Genesis BASE_EMBEDDED {
             function_mode == FUNCTION_WITH_READONLY_PROTOTYPE);
   }
 
-  Handle<Map> CreateFunctionMap(FunctionMode function_mode);
+  Handle<Map> CreateSloppyFunctionMap(FunctionMode function_mode);
 
   void SetFunctionInstanceDescriptor(Handle<Map> map,
                                      FunctionMode function_mode);
   void MakeFunctionInstancePrototypeWritable();
 
-  Handle<Map> CreateStrictFunctionMap(
-      FunctionMode function_mode,
-      Handle<JSFunction> empty_function);
+  Handle<Map> CreateStrictFunctionMap(FunctionMode function_mode,
+                                      Handle<JSFunction> empty_function);
+  Handle<Map> CreateStrongFunctionMap(Handle<JSFunction> empty_function,
+                                      bool is_constructor);
+
 
   void SetStrictFunctionInstanceDescriptor(Handle<Map> map,
                                            FunctionMode function_mode);
+  void SetStrongFunctionInstanceDescriptor(Handle<Map> map);
 
   static bool CompileBuiltin(Isolate* isolate, int index);
   static bool CompileExperimentalBuiltin(Isolate* isolate, int index);
@@ -335,7 +339,7 @@ void Bootstrapper::DetachGlobal(Handle<Context> env) {
   Handle<JSGlobalProxy> global_proxy(JSGlobalProxy::cast(env->global_proxy()));
   global_proxy->set_native_context(*factory->null_value());
   SetObjectPrototype(global_proxy, factory->null_value());
-  global_proxy->map()->set_constructor(*factory->null_value());
+  global_proxy->map()->SetConstructor(*factory->null_value());
   if (FLAG_track_detached_contexts) {
     env->GetIsolate()->AddDetachedContext(env);
   }
@@ -378,51 +382,53 @@ void Genesis::SetFunctionInstanceDescriptor(
   int size = IsFunctionModeWithPrototype(function_mode) ? 5 : 4;
   Map::EnsureDescriptorSlack(map, size);
 
-  PropertyAttributes attribs = static_cast<PropertyAttributes>(
-      DONT_ENUM | DONT_DELETE | READ_ONLY);
+  PropertyAttributes ro_attribs =
+      static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+  PropertyAttributes roc_attribs =
+      static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
 
   Handle<AccessorInfo> length =
-      Accessors::FunctionLengthInfo(isolate(), attribs);
+      Accessors::FunctionLengthInfo(isolate(), roc_attribs);
   {  // Add length.
     AccessorConstantDescriptor d(Handle<Name>(Name::cast(length->name())),
-                                 length, attribs);
+                                 length, roc_attribs);
     map->AppendDescriptor(&d);
   }
   Handle<AccessorInfo> name =
-      Accessors::FunctionNameInfo(isolate(), attribs);
+      Accessors::FunctionNameInfo(isolate(), ro_attribs);
   {  // Add name.
     AccessorConstantDescriptor d(Handle<Name>(Name::cast(name->name())), name,
-                                 attribs);
+                                 roc_attribs);
     map->AppendDescriptor(&d);
   }
   Handle<AccessorInfo> args =
-      Accessors::FunctionArgumentsInfo(isolate(), attribs);
+      Accessors::FunctionArgumentsInfo(isolate(), ro_attribs);
   {  // Add arguments.
     AccessorConstantDescriptor d(Handle<Name>(Name::cast(args->name())), args,
-                                 attribs);
+                                 ro_attribs);
     map->AppendDescriptor(&d);
   }
   Handle<AccessorInfo> caller =
-      Accessors::FunctionCallerInfo(isolate(), attribs);
+      Accessors::FunctionCallerInfo(isolate(), ro_attribs);
   {  // Add caller.
     AccessorConstantDescriptor d(Handle<Name>(Name::cast(caller->name())),
-                                 caller, attribs);
+                                 caller, ro_attribs);
     map->AppendDescriptor(&d);
   }
   if (IsFunctionModeWithPrototype(function_mode)) {
     if (function_mode == FUNCTION_WITH_WRITEABLE_PROTOTYPE) {
-      attribs = static_cast<PropertyAttributes>(attribs & ~READ_ONLY);
+      ro_attribs = static_cast<PropertyAttributes>(ro_attribs & ~READ_ONLY);
     }
     Handle<AccessorInfo> prototype =
-        Accessors::FunctionPrototypeInfo(isolate(), attribs);
+        Accessors::FunctionPrototypeInfo(isolate(), ro_attribs);
     AccessorConstantDescriptor d(Handle<Name>(Name::cast(prototype->name())),
-                                 prototype, attribs);
+                                 prototype, ro_attribs);
     map->AppendDescriptor(&d);
   }
 }
 
 
-Handle<Map> Genesis::CreateFunctionMap(FunctionMode function_mode) {
+Handle<Map> Genesis::CreateSloppyFunctionMap(FunctionMode function_mode) {
   Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
   SetFunctionInstanceDescriptor(map, function_mode);
   map->set_function_with_prototype(IsFunctionModeWithPrototype(function_mode));
@@ -437,7 +443,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
   // Functions with this map will not have a 'prototype' property, and
   // can not be used as constructors.
   Handle<Map> function_without_prototype_map =
-      CreateFunctionMap(FUNCTION_WITHOUT_PROTOTYPE);
+      CreateSloppyFunctionMap(FUNCTION_WITHOUT_PROTOTYPE);
   native_context()->set_sloppy_function_without_prototype_map(
       *function_without_prototype_map);
 
@@ -445,7 +451,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
   // of builtins.
   // Later the map is replaced with writable prototype map, allocated below.
   Handle<Map> function_map =
-      CreateFunctionMap(FUNCTION_WITH_READONLY_PROTOTYPE);
+      CreateSloppyFunctionMap(FUNCTION_WITH_READONLY_PROTOTYPE);
   native_context()->set_sloppy_function_map(*function_map);
   native_context()->set_sloppy_function_with_readonly_prototype_map(
       *function_map);
@@ -453,7 +459,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
   // The final map for functions. Writeable prototype.
   // This map is installed in MakeFunctionInstancePrototypeWritable.
   sloppy_function_map_writable_prototype_ =
-      CreateFunctionMap(FUNCTION_WITH_WRITEABLE_PROTOTYPE);
+      CreateSloppyFunctionMap(FUNCTION_WITH_WRITEABLE_PROTOTYPE);
 
   Factory* factory = isolate->factory();
 
@@ -501,7 +507,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
 
   // Allocate the function map first and then patch the prototype later
   Handle<Map> empty_function_map =
-      CreateFunctionMap(FUNCTION_WITHOUT_PROTOTYPE);
+      CreateSloppyFunctionMap(FUNCTION_WITHOUT_PROTOTYPE);
   DCHECK(!empty_function_map->is_dictionary_map());
   empty_function_map->SetPrototype(object_function_prototype);
   empty_function_map->set_is_prototype_map(true);
@@ -536,6 +542,8 @@ void Genesis::SetStrictFunctionInstanceDescriptor(
       static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
   PropertyAttributes ro_attribs =
       static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+  PropertyAttributes roc_attribs =
+      static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
 
   // Add length.
   if (function_mode == BOUND_FUNCTION) {
@@ -547,16 +555,16 @@ void Genesis::SetStrictFunctionInstanceDescriptor(
            function_mode == FUNCTION_WITH_READONLY_PROTOTYPE ||
            function_mode == FUNCTION_WITHOUT_PROTOTYPE);
     Handle<AccessorInfo> length =
-        Accessors::FunctionLengthInfo(isolate(), ro_attribs);
+        Accessors::FunctionLengthInfo(isolate(), roc_attribs);
     AccessorConstantDescriptor d(Handle<Name>(Name::cast(length->name())),
-                                 length, ro_attribs);
+                                 length, roc_attribs);
     map->AppendDescriptor(&d);
   }
   Handle<AccessorInfo> name =
-      Accessors::FunctionNameInfo(isolate(), ro_attribs);
+      Accessors::FunctionNameInfo(isolate(), roc_attribs);
   {  // Add name.
     AccessorConstantDescriptor d(Handle<Name>(Name::cast(name->name())), name,
-                                 ro_attribs);
+                                 roc_attribs);
     map->AppendDescriptor(&d);
   }
   {  // Add arguments.
@@ -583,6 +591,29 @@ void Genesis::SetStrictFunctionInstanceDescriptor(
 }
 
 
+void Genesis::SetStrongFunctionInstanceDescriptor(Handle<Map> map) {
+  Map::EnsureDescriptorSlack(map, 2);
+
+  PropertyAttributes ro_attribs =
+      static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+
+  Handle<AccessorInfo> length =
+      Accessors::FunctionLengthInfo(isolate(), ro_attribs);
+  {  // Add length.
+    AccessorConstantDescriptor d(Handle<Name>(Name::cast(length->name())),
+                                 length, ro_attribs);
+    map->AppendDescriptor(&d);
+  }
+  Handle<AccessorInfo> name =
+      Accessors::FunctionNameInfo(isolate(), ro_attribs);
+  {  // Add name.
+    AccessorConstantDescriptor d(Handle<Name>(Name::cast(name->name())), name,
+                                 ro_attribs);
+    map->AppendDescriptor(&d);
+  }
+}
+
+
 // ECMAScript 5th Edition, 13.2.3
 Handle<JSFunction> Genesis::GetStrictPoisonFunction() {
   if (strict_poison_function.is_null()) {
@@ -628,6 +659,18 @@ Handle<Map> Genesis::CreateStrictFunctionMap(
 }
 
 
+Handle<Map> Genesis::CreateStrongFunctionMap(
+    Handle<JSFunction> empty_function, bool is_constructor) {
+  Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
+  SetStrongFunctionInstanceDescriptor(map);
+  map->set_function_with_prototype(is_constructor);
+  map->SetPrototype(empty_function);
+  map->set_is_extensible(is_constructor);
+  // TODO(rossberg): mark strong
+  return map;
+}
+
+
 void Genesis::CreateStrictModeFunctionMaps(Handle<JSFunction> empty) {
   // Allocate map for the prototype-less strict mode instances.
   Handle<Map> strict_function_without_prototype_map =
@@ -659,6 +702,16 @@ void Genesis::CreateStrictModeFunctionMaps(Handle<JSFunction> empty) {
 }
 
 
+void Genesis::CreateStrongModeFunctionMaps(Handle<JSFunction> empty) {
+  // Allocate map for strong mode instances, which never have prototypes.
+  Handle<Map> strong_function_map = CreateStrongFunctionMap(empty, false);
+  native_context()->set_strong_function_map(*strong_function_map);
+  // Constructors do, though.
+  Handle<Map> strong_constructor_map = CreateStrongFunctionMap(empty, true);
+  native_context()->set_strong_constructor_map(*strong_constructor_map);
+}
+
+
 static void SetAccessors(Handle<Map> map,
                          Handle<String> name,
                          Handle<JSFunction> func) {
@@ -1264,8 +1317,8 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
     map->set_inobject_properties(1);
 
     // Copy constructor from the sloppy arguments boilerplate.
-    map->set_constructor(
-        native_context()->sloppy_arguments_map()->constructor());
+    map->SetConstructor(
+        native_context()->sloppy_arguments_map()->GetConstructor());
 
     native_context()->set_strict_arguments_map(*map);
 
@@ -1412,8 +1465,8 @@ bool Genesis::CompileScriptCached(Isolate* isolate,
     Handle<String> script_name =
         factory->NewStringFromUtf8(name).ToHandleChecked();
     function_info = Compiler::CompileScript(
-        source, script_name, 0, 0, false, false, top_context, extension, NULL,
-        ScriptCompiler::kNoCompileOptions,
+        source, script_name, 0, 0, false, false, Handle<Object>(), top_context,
+        extension, NULL, ScriptCompiler::kNoCompileOptions,
         use_runtime_context ? NATIVES_CODE : NOT_NATIVES_CODE, false);
     if (function_info.is_null()) return false;
     if (cache != NULL) cache->Add(name, function_info);
@@ -1485,7 +1538,7 @@ static Handle<JSObject> ResolveBuiltinIdHolder(Handle<Context> native_context,
 
 void Genesis::InstallNativeFunctions() {
   HandleScope scope(isolate());
-  INSTALL_NATIVE(JSFunction, "CreateDate", create_date_fun);
+  INSTALL_NATIVE(JSFunction, "$createDate", create_date_fun);
 
   INSTALL_NATIVE(JSFunction, "ToNumber", to_number_fun);
   INSTALL_NATIVE(JSFunction, "ToString", to_string_fun);
@@ -1501,7 +1554,7 @@ void Genesis::InstallNativeFunctions() {
   INSTALL_NATIVE(JSFunction, "ToCompletePropertyDescriptor",
                  to_complete_property_descriptor);
 
-  INSTALL_NATIVE(JSFunction, "IsPromise", is_promise);
+  INSTALL_NATIVE(Symbol, "promiseStatus", promise_status);
   INSTALL_NATIVE(JSFunction, "PromiseCreate", promise_create);
   INSTALL_NATIVE(JSFunction, "PromiseResolve", promise_resolve);
   INSTALL_NATIVE(JSFunction, "PromiseReject", promise_reject);
@@ -1598,9 +1651,7 @@ void Genesis::InitializeBuiltinTypedArrays() {
 #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)
@@ -1609,12 +1660,12 @@ 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)
 EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_unicode_regexps)
 EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_computed_property_names)
 EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_rest_parameters)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_reflect)
 
 
 void Genesis::InstallNativeFunctions_harmony_proxies() {
@@ -1631,9 +1682,7 @@ void Genesis::InstallNativeFunctions_harmony_proxies() {
 #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)
@@ -1642,7 +1691,6 @@ 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)
 EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_computed_property_names)
@@ -1653,10 +1701,9 @@ void Genesis::InitializeGlobal_harmony_regexps() {
 
   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();
+  Runtime::SetObjectProperty(isolate(), builtins,
+                             factory()->harmony_regexps_string(), flag,
+                             STRICT).Assert();
 }
 
 
@@ -1665,11 +1712,51 @@ void Genesis::InitializeGlobal_harmony_unicode_regexps() {
 
   Handle<HeapObject> flag(FLAG_harmony_unicode_regexps ? heap()->true_value()
                                                        : heap()->false_value());
-  PropertyAttributes attributes =
-      static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
-  Runtime::DefineObjectProperty(builtins,
-                                factory()->harmony_unicode_regexps_string(),
-                                flag, attributes).Assert();
+  Runtime::SetObjectProperty(isolate(), builtins,
+                             factory()->harmony_unicode_regexps_string(), flag,
+                             STRICT).Assert();
+}
+
+
+void Genesis::InitializeGlobal_harmony_reflect() {
+  if (!FLAG_harmony_reflect) return;
+  Handle<JSObject> builtins(native_context()->builtins());
+  // Install references to functions of the Reflect object
+  {
+    Handle<JSFunction> apply =
+        InstallFunction(builtins, "ReflectApply", JS_OBJECT_TYPE,
+                        JSObject::kHeaderSize, MaybeHandle<JSObject>(),
+                        Builtins::kReflectApply);
+    Handle<JSFunction> construct =
+        InstallFunction(builtins, "ReflectConstruct", JS_OBJECT_TYPE,
+                        JSObject::kHeaderSize, MaybeHandle<JSObject>(),
+                        Builtins::kReflectConstruct);
+    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, Code::CALL_IC);
+      Handle<TypeFeedbackVector> feedback_vector =
+          factory()->NewTypeFeedbackVector(&spec);
+      apply->shared()->set_feedback_vector(*feedback_vector);
+
+      feedback_vector = factory()->NewTypeFeedbackVector(&spec);
+      construct->shared()->set_feedback_vector(*feedback_vector);
+    }
+
+    apply->shared()->set_internal_formal_parameter_count(3);
+    apply->shared()->set_length(3);
+
+    construct->shared()->set_internal_formal_parameter_count(3);
+    construct->shared()->set_length(2);
+  }
+
+  Handle<JSGlobalObject> global(JSGlobalObject::cast(
+      native_context()->global_object()));
+  Handle<String> reflect_string =
+      factory()->NewStringFromStaticChars("Reflect");
+  Handle<Object> reflect =
+      factory()->NewJSObject(isolate()->object_function(), TENURED);
+  JSObject::AddProperty(global, reflect_string, reflect, DONT_ENUM);
 }
 
 
@@ -2023,6 +2110,13 @@ bool Genesis::InstallNatives() {
     native_context()->set_strict_generator_function_map(
         *strict_generator_function_map);
 
+    Handle<Map> strong_function_map(native_context()->strong_function_map());
+    Handle<Map> strong_generator_function_map =
+        Map::Copy(strong_function_map, "StrongGeneratorFunction");
+    strong_generator_function_map->SetPrototype(generator_function_prototype);
+    native_context()->set_strong_generator_function_map(
+        *strong_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->SetPrototype(generator_object_prototype);
@@ -2047,14 +2141,12 @@ bool Genesis::InstallNatives() {
   }
 
   // Install natives.
-  for (int i = Natives::GetDebuggerCount();
-       i < Natives::GetBuiltinsCount();
-       i++) {
+  int i = Natives::GetDebuggerCount();
+  if (!CompileBuiltin(isolate(), i)) return false;
+  if (!InstallJSBuiltins(builtins)) return false;
+
+  for (++i; i < Natives::GetBuiltinsCount(); ++i) {
     if (!CompileBuiltin(isolate(), i)) return false;
-    // TODO(ager): We really only need to install the JS builtin
-    // functions on the builtins object after compiling and running
-    // runtime.js.
-    if (!InstallJSBuiltins(builtins)) return false;
   }
 
   InstallNativeFunctions();
@@ -2090,10 +2182,9 @@ bool Genesis::InstallNatives() {
     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);
+      FeedbackVectorSpec spec(0, Code::CALL_IC);
       Handle<TypeFeedbackVector> feedback_vector =
-          factory()->NewTypeFeedbackVector(spec);
+          factory()->NewTypeFeedbackVector(&spec);
       apply->shared()->set_feedback_vector(*feedback_vector);
     }
 
@@ -2126,7 +2217,7 @@ bool Genesis::InstallNatives() {
     // Add initial map.
     Handle<Map> initial_map =
         factory()->NewMap(JS_ARRAY_TYPE, JSRegExpResult::kSize);
-    initial_map->set_constructor(*array_constructor);
+    initial_map->SetConstructor(*array_constructor);
 
     // Set prototype on map.
     initial_map->set_non_instance_prototype(false);
@@ -2213,11 +2304,8 @@ bool Genesis::InstallExperimentalNatives() {
   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[] = {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};
@@ -2225,13 +2313,13 @@ bool Genesis::InstallExperimentalNatives() {
   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};
   static const char* harmony_unicode_regexps_natives[] = {NULL};
   static const char* harmony_computed_property_names_natives[] = {NULL};
   static const char* harmony_rest_parameters_natives[] = {NULL};
+  static const char* harmony_reflect_natives[] = {"native harmony-reflect.js",
+                                                  NULL};
 
   for (int i = ExperimentalNatives::GetDebuggerCount();
        i < ExperimentalNatives::GetBuiltinsCount(); i++) {
@@ -2269,15 +2357,24 @@ static void InstallBuiltinFunctionId(Handle<JSObject> holder,
 
 void Genesis::InstallBuiltinFunctionIds() {
   HandleScope scope(isolate());
+  struct BuiltinFunctionIds {
+    const char* holder_expr;
+    const char* fun_name;
+    BuiltinFunctionId id;
+  };
+
 #define INSTALL_BUILTIN_ID(holder_expr, fun_name, name) \
-  {                                                     \
-    Handle<JSObject> holder = ResolveBuiltinIdHolder(   \
-        native_context(), #holder_expr);                \
-    BuiltinFunctionId id = k##name;                     \
-    InstallBuiltinFunctionId(holder, #fun_name, id);    \
-  }
-  FUNCTIONS_WITH_ID_LIST(INSTALL_BUILTIN_ID)
+  { #holder_expr, #fun_name, k##name }                  \
+  ,
+  const BuiltinFunctionIds builtins[] = {
+      FUNCTIONS_WITH_ID_LIST(INSTALL_BUILTIN_ID)};
 #undef INSTALL_BUILTIN_ID
+
+  for (const BuiltinFunctionIds& builtin : builtins) {
+    Handle<JSObject> holder =
+        ResolveBuiltinIdHolder(native_context(), builtin.holder_expr);
+    InstallBuiltinFunctionId(holder, builtin.fun_name, builtin.id);
+  }
 }
 
 
@@ -2543,15 +2640,7 @@ bool Genesis::InstallJSBuiltins(Handle<JSBuiltinsObject> builtins) {
     Handle<Object> function_object = Object::GetProperty(
         isolate(), builtins, Builtins::GetName(id)).ToHandleChecked();
     Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);
-    // TODO(mstarzinger): This is just a temporary hack to make TurboFan work,
-    // the correct solution is to restore the context register after invoking
-    // builtins from full-codegen.
-    function->shared()->DisableOptimization(kBuiltinFunctionCannotBeOptimized);
     builtins->set_javascript_builtin(id, *function);
-    if (!Compiler::EnsureCompiled(function, CLEAR_EXCEPTION)) {
-      return false;
-    }
-    builtins->set_javascript_builtin_code(id, function->shared()->code());
   }
   return true;
 }
@@ -2650,7 +2739,8 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
           DCHECK(!to->HasFastProperties());
           // Add to dictionary.
           Handle<Object> callbacks(descs->GetCallbacksObject(i), isolate());
-          PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1);
+          PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
+                            PropertyCellType::kMutable);
           JSObject::SetNormalizedProperty(to, key, callbacks, d);
           break;
         }
@@ -2674,8 +2764,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
                                               isolate());
         DCHECK(!value->IsCell());
         if (value->IsPropertyCell()) {
-          value = Handle<Object>(PropertyCell::cast(*value)->value(),
-                                 isolate());
+          value = handle(PropertyCell::cast(*value)->value(), isolate());
         }
         PropertyDetails details = properties->DetailsAt(i);
         DCHECK_EQ(kData, details.kind());
@@ -2813,6 +2902,7 @@ Genesis::Genesis(Isolate* isolate,
     CreateRoots();
     Handle<JSFunction> empty_function = CreateEmptyFunction(isolate);
     CreateStrictModeFunctionMaps(empty_function);
+    CreateStrongModeFunctionMaps(empty_function);
     Handle<GlobalObject> global_object =
         CreateNewGlobals(global_proxy_template, global_proxy);
     HookUpGlobalProxy(global_object, global_proxy);
@@ -2827,9 +2917,13 @@ Genesis::Genesis(Isolate* isolate,
     isolate->counters()->contexts_created_from_scratch()->Increment();
   }
 
-  // Install experimental natives.
-  if (!InstallExperimentalNatives()) return;
-  InitializeExperimentalGlobal();
+  // Install experimental natives. Do not include them into the snapshot as we
+  // should be able to turn them off at runtime. Re-installing them after
+  // they have already been deserialized would also fail.
+  if (!isolate->serializer_enabled()) {
+    InitializeExperimentalGlobal();
+    if (!InstallExperimentalNatives()) return;
+  }
 
   // The serializer cannot serialize typed arrays. Reset those typed arrays
   // for each new context.
index 21c246c..2457a95 100644 (file)
@@ -1044,6 +1044,17 @@ MUST_USE_RESULT static MaybeHandle<Object> HandleApiCallHelper(
   DCHECK(!args[0]->IsNull());
   if (args[0]->IsUndefined()) args[0] = function->global_proxy();
 
+  if (!is_construct && !fun_data->accept_any_receiver()) {
+    Handle<Object> receiver(&args[0]);
+    if (receiver->IsJSObject() && receiver->IsAccessCheckNeeded()) {
+      Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver);
+      if (!isolate->MayAccess(js_receiver)) {
+        isolate->ReportFailedAccessCheck(js_receiver);
+        RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
+      }
+    }
+  }
+
   Object* raw_holder = fun_data->GetCompatibleReceiver(isolate, args[0]);
 
   if (raw_holder->IsNull()) {
@@ -1185,7 +1196,7 @@ MUST_USE_RESULT static Object* HandleApiCallAsFunctionOrConstructor(
   // Get the invocation callback from the function descriptor that was
   // used to create the called object.
   DCHECK(obj->map()->has_instance_call_handler());
-  JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
+  JSFunction* constructor = JSFunction::cast(obj->map()->GetConstructor());
   // TODO(ishell): turn this back to a DCHECK.
   CHECK(constructor->shared()->IsApiFunction());
   Object* handler =
index cfbb77d..c00a1a9 100644 (file)
@@ -109,6 +109,8 @@ enum BuiltinExtraArguments {
   /* Uses KeyedLoadIC_Initialize; must be after in list. */                    \
   V(FunctionCall, BUILTIN, UNINITIALIZED, kNoExtraICState)                     \
   V(FunctionApply, BUILTIN, UNINITIALIZED, kNoExtraICState)                    \
+  V(ReflectApply, BUILTIN, UNINITIALIZED, kNoExtraICState)                     \
+  V(ReflectConstruct, BUILTIN, UNINITIALIZED, kNoExtraICState)                 \
                                                                                \
   V(InternalArrayCode, BUILTIN, UNINITIALIZED, kNoExtraICState)                \
   V(ArrayCode, BUILTIN, UNINITIALIZED, kNoExtraICState)                        \
@@ -193,6 +195,8 @@ enum BuiltinExtraArguments {
   V(STRING_ADD_LEFT, 1)                    \
   V(STRING_ADD_RIGHT, 1)                   \
   V(APPLY_PREPARE, 1)                      \
+  V(REFLECT_APPLY_PREPARE, 1)              \
+  V(REFLECT_CONSTRUCT_PREPARE, 2)          \
   V(STACK_OVERFLOW, 1)
 
 class BuiltinFunctionTable;
@@ -316,6 +320,8 @@ class Builtins {
 
   static void Generate_FunctionCall(MacroAssembler* masm);
   static void Generate_FunctionApply(MacroAssembler* masm);
+  static void Generate_ReflectApply(MacroAssembler* masm);
+  static void Generate_ReflectConstruct(MacroAssembler* masm);
 
   static void Generate_InternalArrayCode(MacroAssembler* masm);
   static void Generate_ArrayCode(MacroAssembler* masm);
index 71d1b06..d90f919 100644 (file)
@@ -35,6 +35,13 @@ inline bool IsInRange(int value, int lower_limit, int higher_limit) {
       static_cast<unsigned int>(higher_limit - lower_limit);
 }
 
+inline bool IsAsciiIdentifier(uc32 c) {
+  return IsAlphaNumeric(c) || c == '$' || c == '_';
+}
+
+inline bool IsAlphaNumeric(uc32 c) {
+  return IsInRange(AsciiAlphaToLower(c), 'a', 'z') || IsDecimalDigit(c);
+}
 
 inline bool IsDecimalDigit(uc32 c) {
   // ECMA-262, 3rd, 7.8.3 (p 16)
index 5ecb07d..c68ad74 100644 (file)
@@ -15,6 +15,8 @@ namespace internal {
 
 inline bool IsCarriageReturn(uc32 c);
 inline bool IsLineFeed(uc32 c);
+inline bool IsAsciiIdentifier(uc32 c);
+inline bool IsAlphaNumeric(uc32 c);
 inline bool IsDecimalDigit(uc32 c);
 inline bool IsHexDigit(uc32 c);
 inline bool IsOctalDigit(uc32 c);
index 590dbbb..71c5449 100644 (file)
@@ -12,6 +12,15 @@ namespace v8 {
 namespace internal {
 
 // static
+Callable CodeFactory::LoadGlobalIC(Isolate* isolate,
+                                   Handle<GlobalObject> global,
+                                   Handle<String> name) {
+  return Callable(LoadIC::load_global(isolate, global, name),
+                  LoadDescriptor(isolate));
+}
+
+
+// static
 Callable CodeFactory::LoadIC(Isolate* isolate, ContextualMode mode) {
   return Callable(
       LoadIC::initialize_stub(isolate, LoadICState(mode).GetExtraICState()),
@@ -20,14 +29,15 @@ Callable CodeFactory::LoadIC(Isolate* isolate, ContextualMode mode) {
 
 
 // static
-Callable CodeFactory::LoadICInOptimizedCode(Isolate* isolate,
-                                            ContextualMode mode) {
+Callable CodeFactory::LoadICInOptimizedCode(
+    Isolate* isolate, ContextualMode mode,
+    InlineCacheState initialization_state) {
+  auto code = LoadIC::initialize_stub_in_optimized_code(
+      isolate, LoadICState(mode).GetExtraICState(), initialization_state);
   if (FLAG_vector_ics) {
-    return Callable(LoadIC::initialize_stub_in_optimized_code(
-                        isolate, LoadICState(mode).GetExtraICState()),
-                    VectorLoadICDescriptor(isolate));
+    return Callable(code, VectorLoadICDescriptor(isolate));
   }
-  return CodeFactory::LoadIC(isolate, mode);
+  return Callable(code, LoadDescriptor(isolate));
 }
 
 
@@ -39,12 +49,14 @@ Callable CodeFactory::KeyedLoadIC(Isolate* isolate) {
 
 
 // static
-Callable CodeFactory::KeyedLoadICInOptimizedCode(Isolate* isolate) {
+Callable CodeFactory::KeyedLoadICInOptimizedCode(
+    Isolate* isolate, InlineCacheState initialization_state) {
+  auto code = KeyedLoadIC::initialize_stub_in_optimized_code(
+      isolate, initialization_state);
   if (FLAG_vector_ics) {
-    return Callable(KeyedLoadIC::initialize_stub_in_optimized_code(isolate),
-                    VectorLoadICDescriptor(isolate));
+    return Callable(code, VectorLoadICDescriptor(isolate));
   }
-  return CodeFactory::KeyedLoadIC(isolate);
+  return Callable(code, LoadDescriptor(isolate));
 }
 
 
@@ -67,25 +79,35 @@ Callable CodeFactory::CallICInOptimizedCode(Isolate* isolate, int argc,
 
 // static
 Callable CodeFactory::StoreIC(Isolate* isolate, LanguageMode language_mode) {
-  return Callable(StoreIC::initialize_stub(isolate, language_mode),
-                  StoreDescriptor(isolate));
+  return Callable(
+      StoreIC::initialize_stub(isolate, language_mode, UNINITIALIZED),
+      StoreDescriptor(isolate));
 }
 
 
 // static
 Callable CodeFactory::KeyedStoreIC(Isolate* isolate,
                                    LanguageMode language_mode) {
-  Handle<Code> ic = is_strict(language_mode)
-                        ? isolate->builtins()->KeyedStoreIC_Initialize_Strict()
-                        : isolate->builtins()->KeyedStoreIC_Initialize();
-  return Callable(ic, StoreDescriptor(isolate));
+  return Callable(
+      KeyedStoreIC::initialize_stub(isolate, language_mode, UNINITIALIZED),
+      StoreDescriptor(isolate));
+}
+
+
+// static
+Callable CodeFactory::KeyedStoreICInOptimizedCode(
+    Isolate* isolate, LanguageMode language_mode,
+    InlineCacheState initialization_state) {
+  return Callable(KeyedStoreIC::initialize_stub(isolate, language_mode,
+                                                initialization_state),
+                  StoreDescriptor(isolate));
 }
 
 
 // static
 Callable CodeFactory::CompareIC(Isolate* isolate, Token::Value op) {
   Handle<Code> code = CompareIC::GetUninitialized(isolate, op);
-  return Callable(code, BinaryOpDescriptor(isolate));
+  return Callable(code, CompareDescriptor(isolate));
 }
 
 
index 5fd1646..f8af73b 100644 (file)
@@ -32,16 +32,23 @@ class Callable FINAL BASE_EMBEDDED {
 class CodeFactory FINAL {
  public:
   // Initial states for ICs.
+  static Callable LoadGlobalIC(Isolate* isolate, Handle<GlobalObject> global,
+                               Handle<String> name);
   static Callable LoadIC(Isolate* isolate, ContextualMode mode);
-  static Callable LoadICInOptimizedCode(Isolate* isolate, ContextualMode mode);
+  static Callable LoadICInOptimizedCode(Isolate* isolate, ContextualMode mode,
+                                        InlineCacheState initialization_state);
   static Callable KeyedLoadIC(Isolate* isolate);
-  static Callable KeyedLoadICInOptimizedCode(Isolate* isolate);
+  static Callable KeyedLoadICInOptimizedCode(
+      Isolate* isolate, InlineCacheState initialization_state);
   static Callable CallIC(Isolate* isolate, int argc,
                          CallICState::CallType call_type);
   static Callable CallICInOptimizedCode(Isolate* isolate, int argc,
                                         CallICState::CallType call_type);
   static Callable StoreIC(Isolate* isolate, LanguageMode mode);
   static Callable KeyedStoreIC(Isolate* isolate, LanguageMode mode);
+  static Callable KeyedStoreICInOptimizedCode(
+      Isolate* isolate, LanguageMode mode,
+      InlineCacheState initialization_state);
 
   static Callable CompareIC(Isolate* isolate, Token::Value op);
 
index f776abc..8168aac 100644 (file)
@@ -35,7 +35,7 @@ static LChunk* OptimizeGraph(HGraph* graph) {
 
 class CodeStubGraphBuilderBase : public HGraphBuilder {
  public:
-  explicit CodeStubGraphBuilderBase(CompilationInfoWithZone* info)
+  explicit CodeStubGraphBuilderBase(CompilationInfo* info)
       : HGraphBuilder(info),
         arguments_length_(NULL),
         info_(info),
@@ -100,21 +100,6 @@ class CodeStubGraphBuilderBase : public HGraphBuilder {
                                         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,
@@ -122,7 +107,7 @@ class CodeStubGraphBuilderBase : public HGraphBuilder {
 
   SmartArrayPointer<HParameter*> parameters_;
   HValue* arguments_length_;
-  CompilationInfoWithZone* info_;
+  CompilationInfo* info_;
   CodeStubDescriptor descriptor_;
   HContext* context_;
 };
@@ -205,7 +190,7 @@ bool CodeStubGraphBuilderBase::BuildGraph() {
 template <class Stub>
 class CodeStubGraphBuilder: public CodeStubGraphBuilderBase {
  public:
-  explicit CodeStubGraphBuilder(CompilationInfoWithZone* info)
+  explicit CodeStubGraphBuilder(CompilationInfo* info)
       : CodeStubGraphBuilderBase(info) {}
 
  protected:
@@ -287,7 +272,8 @@ static Handle<Code> DoGenerateCode(Stub* stub) {
   if (FLAG_profile_hydrogen_code_stub_compilation) {
     timer.Start();
   }
-  CompilationInfoWithZone info(stub, isolate);
+  Zone zone;
+  CompilationInfo info(stub, isolate, &zone);
   CodeStubGraphBuilder<Stub> builder(&info);
   LChunk* chunk = OptimizeGraph(builder.CreateGraph());
   Handle<Code> code = chunk->Codegen();
@@ -1354,7 +1340,8 @@ HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() {
       StoreGlobalStub::property_cell_placeholder(isolate())));
   HValue* cell = Add<HLoadNamedField>(weak_cell, nullptr,
                                       HObjectAccess::ForWeakCellValue());
-  HObjectAccess access(HObjectAccess::ForCellPayload(isolate()));
+  Add<HCheckHeapObject>(cell);
+  HObjectAccess access = HObjectAccess::ForPropertyCellValue();
   HValue* cell_contents = Add<HLoadNamedField>(cell, nullptr, access);
 
   if (stub->is_constant()) {
@@ -1374,8 +1361,7 @@ HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() {
     builder.Then();
     builder.Deopt(Deoptimizer::kUnexpectedCellContentsInGlobalStore);
     builder.Else();
-    HStoreNamedField* store = Add<HStoreNamedField>(cell, access, value);
-    store->MarkReceiverAsCell();
+    Add<HStoreNamedField>(cell, access, value);
     builder.End();
   }
 
@@ -1726,7 +1712,7 @@ template <>
 class CodeStubGraphBuilder<KeyedLoadGenericStub>
     : public CodeStubGraphBuilderBase {
  public:
-  explicit CodeStubGraphBuilder(CompilationInfoWithZone* info)
+  explicit CodeStubGraphBuilder(CompilationInfo* info)
       : CodeStubGraphBuilderBase(info) {}
 
  protected:
@@ -2029,211 +2015,6 @@ Handle<Code> KeyedLoadGenericStub::GenerateCode() {
 }
 
 
-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) {
-  HConstant* constant_two = Add<HConstant>(2);
-  HConstant* constant_three = Add<HConstant>(3);
-
-  IfBuilder if_receiver_heap_object(this);
-  if_receiver_heap_object.IfNot<HIsSmiAndBranch>(receiver);
-  if_receiver_heap_object.Then();
-  Push(AddLoadMap(receiver, nullptr));
-  if_receiver_heap_object.Else();
-  HConstant* heap_number_map =
-      Add<HConstant>(isolate()->factory()->heap_number_map());
-  Push(heap_number_map);
-  if_receiver_heap_object.End();
-  HValue* receiver_map = Pop();
-
-  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);
-  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();
-}
-
-
-Handle<Code> VectorLoadStub::GenerateCode() { return DoGenerateCode(this); }
-
-
-template <>
-HValue* CodeStubGraphBuilder<VectorKeyedLoadStub>::BuildCodeStub() {
-  HValue* receiver = GetParameter(VectorLoadICDescriptor::kReceiverIndex);
-  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 megamorphic state.
-    IfBuilder megamorphic_checker(this);
-    HConstant* megamorphic_symbol =
-        Add<HConstant>(isolate()->factory()->megamorphic_symbol());
-    megamorphic_checker.If<HCompareObjectEqAndBranch>(feedback,
-                                                      megamorphic_symbol);
-    megamorphic_checker.Then();
-    {
-      // Tail-call to the megamorphic KeyedLoadIC, treating it like a handler.
-      Handle<Code> stub = KeyedLoadIC::ChooseMegamorphicStub(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.
-    }
-    megamorphic_checker.End();
-  }
-  array_checker.End();
-
-  TailCallMiss(receiver, name, slot, vector, true);
-  return zero;
-}
-
-
-Handle<Code> VectorKeyedLoadStub::GenerateCode() {
-  return DoGenerateCode(this);
-}
-
-
 Handle<Code> MegamorphicLoadStub::GenerateCode() {
   return DoGenerateCode(this);
 }
index 6c68271..f600cf3 100644 (file)
@@ -620,26 +620,6 @@ CallInterfaceDescriptor StoreTransitionStub::GetCallInterfaceDescriptor() {
 }
 
 
-static void InitializeVectorLoadStub(Isolate* isolate,
-                                     CodeStubDescriptor* descriptor,
-                                     Address deoptimization_handler) {
-  DCHECK(FLAG_vector_ics);
-  descriptor->Initialize(deoptimization_handler);
-}
-
-
-void VectorLoadStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
-  InitializeVectorLoadStub(isolate(), descriptor,
-                           FUNCTION_ADDR(LoadIC_MissFromStubFailure));
-}
-
-
-void VectorKeyedLoadStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
-  InitializeVectorLoadStub(isolate(), descriptor,
-                           FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure));
-}
-
-
 void MegamorphicLoadStub::InitializeDescriptor(CodeStubDescriptor* d) {}
 
 
@@ -684,7 +664,7 @@ void CreateWeakCellStub::InitializeDescriptor(CodeStubDescriptor* d) {}
 void RegExpConstructResultStub::InitializeDescriptor(
     CodeStubDescriptor* descriptor) {
   descriptor->Initialize(
-      Runtime::FunctionForId(Runtime::kRegExpConstructResult)->entry);
+      Runtime::FunctionForId(Runtime::kRegExpConstructResultRT)->entry);
 }
 
 
@@ -730,7 +710,7 @@ void BinaryOpWithAllocationSiteStub::InitializeDescriptor(
 
 
 void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
-  descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAdd)->entry);
+  descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAddRT)->entry);
 }
 
 
index 2ae4ba7..0054113 100644 (file)
@@ -85,8 +85,8 @@ namespace internal {
   V(StringAdd)                              \
   V(ToBoolean)                              \
   V(TransitionElementsKind)                 \
-  V(VectorKeyedLoad)                        \
-  V(VectorLoad)                             \
+  V(VectorRawKeyedLoad)                     \
+  V(VectorRawLoad)                          \
   /* IC Handler stubs */                    \
   V(LoadConstant)                           \
   V(LoadField)                              \
@@ -614,7 +614,7 @@ class FastNewClosureStub : public HydrogenCodeStub {
  private:
   STATIC_ASSERT(LANGUAGE_END == 3);
   class LanguageModeBits : public BitField<LanguageMode, 0, 2> {};
-  class FunctionKindBits : public BitField<FunctionKind, 2, 7> {};
+  class FunctionKindBits : public BitField<FunctionKind, 2, 8> {};
 
   DEFINE_CALL_INTERFACE_DESCRIPTOR(FastNewClosure);
   DEFINE_HYDROGEN_CODE_STUB(FastNewClosure, HydrogenCodeStub);
@@ -1777,6 +1777,15 @@ enum ReceiverCheckMode {
 };
 
 
+enum EmbedMode {
+  // The code being generated is part of an IC handler, which may MISS
+  // to an IC in failure cases.
+  PART_OF_IC_HANDLER,
+
+  NOT_PART_OF_IC_HANDLER
+};
+
+
 // Generates code implementing String.prototype.charCodeAt.
 //
 // Only supports the case when the receiver is a string and the index
@@ -1813,7 +1822,7 @@ class StringCharCodeAtGenerator {
   // Generates the slow case code. Must not be naturally
   // reachable. Expected to be put after a ret instruction (e.g., in
   // deferred code). Always jumps back to the fast case.
-  void GenerateSlow(MacroAssembler* masm,
+  void GenerateSlow(MacroAssembler* masm, EmbedMode embed_mode,
                     const RuntimeCallHelper& call_helper);
 
   // Skip handling slow case and directly jump to bailout.
@@ -1913,9 +1922,9 @@ class StringCharAtGenerator {
   // Generates the slow case code. Must not be naturally
   // reachable. Expected to be put after a ret instruction (e.g., in
   // deferred code). Always jumps back to the fast case.
-  void GenerateSlow(MacroAssembler* masm,
+  void GenerateSlow(MacroAssembler* masm, EmbedMode embed_mode,
                     const RuntimeCallHelper& call_helper) {
-    char_code_at_generator_.GenerateSlow(masm, call_helper);
+    char_code_at_generator_.GenerateSlow(masm, embed_mode, call_helper);
     char_from_code_generator_.GenerateSlow(masm, call_helper);
   }
 
@@ -2062,38 +2071,49 @@ class MegamorphicLoadStub : public HydrogenCodeStub {
 };
 
 
-class VectorLoadStub : public HydrogenCodeStub {
+class VectorRawLoadStub : public PlatformCodeStub {
  public:
-  explicit VectorLoadStub(Isolate* isolate, const LoadICState& state)
-      : HydrogenCodeStub(isolate) {
-    set_sub_minor_key(state.GetExtraICState());
+  explicit VectorRawLoadStub(Isolate* isolate, const LoadICState& state)
+      : PlatformCodeStub(isolate) {
+    minor_key_ = state.GetExtraICState();
   }
 
-  Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
+  void GenerateForTrampoline(MacroAssembler* masm);
 
-  InlineCacheState GetICState() const FINAL { return DEFAULT; }
+  virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
 
-  ExtraICState GetExtraICState() const FINAL {
-    return static_cast<ExtraICState>(sub_minor_key());
-  }
+  virtual InlineCacheState GetICState() const FINAL OVERRIDE { return DEFAULT; }
 
- private:
-  LoadICState state() const { return LoadICState(GetExtraICState()); }
+  virtual ExtraICState GetExtraICState() const FINAL OVERRIDE {
+    return static_cast<ExtraICState>(minor_key_);
+  }
 
   DEFINE_CALL_INTERFACE_DESCRIPTOR(VectorLoadIC);
-  DEFINE_HYDROGEN_CODE_STUB(VectorLoad, HydrogenCodeStub);
+  DEFINE_PLATFORM_CODE_STUB(VectorRawLoad, PlatformCodeStub);
+
+ protected:
+  void GenerateImpl(MacroAssembler* masm, bool in_frame);
 };
 
 
-class VectorKeyedLoadStub : public VectorLoadStub {
+class VectorRawKeyedLoadStub : public PlatformCodeStub {
  public:
-  explicit VectorKeyedLoadStub(Isolate* isolate)
-      : VectorLoadStub(isolate, LoadICState(0)) {}
+  explicit VectorRawKeyedLoadStub(Isolate* isolate)
+      : PlatformCodeStub(isolate) {}
 
-  Code::Kind GetCodeKind() const OVERRIDE { return Code::KEYED_LOAD_IC; }
+  void GenerateForTrampoline(MacroAssembler* masm);
+
+  virtual Code::Kind GetCodeKind() const OVERRIDE {
+    return Code::KEYED_LOAD_IC;
+  }
+
+  virtual InlineCacheState GetICState() const FINAL OVERRIDE { return DEFAULT; }
 
   DEFINE_CALL_INTERFACE_DESCRIPTOR(VectorLoadIC);
-  DEFINE_HYDROGEN_CODE_STUB(VectorKeyedLoad, VectorLoadStub);
+  DEFINE_PLATFORM_CODE_STUB(VectorRawKeyedLoad, PlatformCodeStub);
+
+ protected:
+  void GenerateImpl(MacroAssembler* masm, bool in_frame);
 };
 
 
index 178ba4a..796e39a 100644 (file)
@@ -12,6 +12,7 @@
 #include "src/compiler.h"
 #include "src/cpu-profiler.h"
 #include "src/debug.h"
+#include "src/parser.h"
 #include "src/prettyprinter.h"
 #include "src/rewriter.h"
 #include "src/runtime/runtime.h"
@@ -134,13 +135,13 @@ void CodeGenerator::MakeCodePrologue(CompilationInfo* info, const char* kind) {
   }
 
 #ifdef DEBUG
-  if (!info->IsStub() && print_source) {
+  if (info->parse_info() && print_source) {
     PrintF("--- Source from AST ---\n%s\n",
            PrettyPrinter(info->isolate(), info->zone())
                .PrintProgram(info->function()));
   }
 
-  if (!info->IsStub() && print_ast) {
+  if (info->parse_info() && print_ast) {
     PrintF("--- AST ---\n%s\n", AstPrinter(info->isolate(), info->zone())
                                     .PrintProgram(info->function()));
   }
@@ -181,14 +182,27 @@ void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) {
          (info->IsStub() && FLAG_print_code_stubs) ||
          (info->IsOptimizing() && FLAG_print_opt_code));
   if (print_code) {
-    // Print the source code if available.
-    FunctionLiteral* function = info->function();
-    bool print_source = code->kind() == Code::OPTIMIZED_FUNCTION ||
-        code->kind() == Code::FUNCTION;
+    const char* debug_name;
+    SmartArrayPointer<char> debug_name_holder;
+    if (info->IsStub()) {
+      CodeStub::Major major_key = info->code_stub()->MajorKey();
+      debug_name = CodeStub::MajorName(major_key, false);
+    } else {
+      debug_name_holder =
+          info->parse_info()->function()->debug_name()->ToCString();
+      debug_name = debug_name_holder.get();
+    }
 
     CodeTracer::Scope tracing_scope(info->isolate()->GetCodeTracer());
     OFStream os(tracing_scope.file());
+
+    // Print the source code if available.
+    FunctionLiteral* function = nullptr;
+    bool print_source =
+        info->parse_info() && (code->kind() == Code::OPTIMIZED_FUNCTION ||
+                               code->kind() == Code::FUNCTION);
     if (print_source) {
+      function = info->function();
       Handle<Script> script = info->script();
       if (!script->IsUndefined() && !script->source()->IsUndefined()) {
         os << "--- Raw source ---\n";
@@ -207,10 +221,9 @@ void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) {
       }
     }
     if (info->IsOptimizing()) {
-      if (FLAG_print_unopt_code) {
+      if (FLAG_print_unopt_code && info->parse_info()) {
         os << "--- Unoptimized code ---\n";
-        info->closure()->shared()->code()->Disassemble(
-            function->debug_name()->ToCString().get(), os);
+        info->closure()->shared()->code()->Disassemble(debug_name, os);
       }
       os << "--- Optimized code ---\n"
          << "optimization_id = " << info->optimization_id() << "\n";
@@ -220,12 +233,7 @@ void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) {
     if (print_source) {
       os << "source_position = " << function->start_position() << "\n";
     }
-    if (info->IsStub()) {
-      CodeStub::Major major_key = info->code_stub()->MajorKey();
-      code->Disassemble(CodeStub::MajorName(major_key, false), os);
-    } else {
-      code->Disassemble(function->debug_name()->ToCString().get(), os);
-    }
+    code->Disassemble(debug_name, os);
     os << "--- End code ---\n";
   }
 #endif  // ENABLE_DISASSEMBLER
index 94bda70..c8cf639 100644 (file)
@@ -20,26 +20,17 @@ function SetConstructor(iterable) {
     throw MakeTypeError('constructor_not_function', ['Set']);
   }
 
-  var iter, adder;
+  %_SetInitialize(this);
 
   if (!IS_NULL_OR_UNDEFINED(iterable)) {
-    iter = GetIterator(ToObject(iterable));
-    adder = this.add;
+    var adder = this.add;
     if (!IS_SPEC_FUNCTION(adder)) {
       throw MakeTypeError('property_not_function', ['add', this]);
     }
-  }
-
-  %_SetInitialize(this);
-
-  if (IS_UNDEFINED(iter)) return;
 
-  var next, done;
-  while (!(next = iter.next()).done) {
-    if (!IS_SPEC_OBJECT(next)) {
-      throw MakeTypeError('iterator_result_not_an_object', [next]);
+    for (var value of iterable) {
+      %_CallFunction(this, value, adder);
     }
-    %_CallFunction(this, next.value, adder);
   }
 }
 
@@ -160,30 +151,20 @@ function MapConstructor(iterable) {
     throw MakeTypeError('constructor_not_function', ['Map']);
   }
 
-  var iter, adder;
+  %_MapInitialize(this);
 
   if (!IS_NULL_OR_UNDEFINED(iterable)) {
-    iter = GetIterator(ToObject(iterable));
-    adder = this.set;
+    var adder = this.set;
     if (!IS_SPEC_FUNCTION(adder)) {
       throw MakeTypeError('property_not_function', ['set', this]);
     }
-  }
-
-  %_MapInitialize(this);
 
-  if (IS_UNDEFINED(iter)) return;
-
-  var next, done, nextItem;
-  while (!(next = iter.next()).done) {
-    if (!IS_SPEC_OBJECT(next)) {
-      throw MakeTypeError('iterator_result_not_an_object', [next]);
-    }
-    nextItem = next.value;
-    if (!IS_SPEC_OBJECT(nextItem)) {
-      throw MakeTypeError('iterator_value_not_an_object', [nextItem]);
+    for (var nextItem of iterable) {
+      if (!IS_SPEC_OBJECT(nextItem)) {
+        throw MakeTypeError('iterator_value_not_an_object', [nextItem]);
+      }
+      %_CallFunction(this, nextItem[0], nextItem[1], adder);
     }
-    %_CallFunction(this, nextItem[0], nextItem[1], adder);
   }
 }
 
index b696ea5..f2cb4c9 100644 (file)
@@ -6,7 +6,6 @@
 
 #include "src/assembler.h"
 #include "src/compilation-cache.h"
-#include "src/serialize.h"
 
 namespace v8 {
 namespace internal {
index 2bad9e6..3077736 100644 (file)
@@ -2,10 +2,10 @@
 // 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.h"
 
+#include <algorithm>
+
 #include "src/ast-numbering.h"
 #include "src/bootstrapper.h"
 #include "src/codegen.h"
 #include "src/scanner-character-streams.h"
 #include "src/scopeinfo.h"
 #include "src/scopes.h"
+#include "src/snapshot/serialize.h"
 #include "src/typing.h"
 #include "src/vm-state-inl.h"
 
 namespace v8 {
 namespace internal {
 
-
 std::ostream& operator<<(std::ostream& os, const SourcePosition& p) {
   if (p.IsUnknown()) {
     return os << "<?>";
@@ -46,137 +46,65 @@ std::ostream& operator<<(std::ostream& os, const SourcePosition& p) {
 }
 
 
-ScriptData::ScriptData(const byte* data, int 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));
-    CopyBytes(copy, data, length);
-    data_ = copy;
-    AcquireDataOwnership();
+#define PARSE_INFO_GETTER(type, name)  \
+  type CompilationInfo::name() const { \
+    CHECK(parse_info());               \
+    return parse_info()->name();       \
   }
-}
 
 
-CompilationInfo::CompilationInfo(Handle<Script> script, Zone* zone)
-    : flags_(kThisHasUses),
-      script_(script),
-      source_stream_(NULL),
-      osr_ast_id_(BailoutId::None()),
-      parameter_count_(0),
-      optimization_id_(-1),
-      ast_value_factory_(NULL),
-      ast_value_factory_owned_(false),
-      aborted_due_to_dependency_change_(false),
-      osr_expr_stack_height_(0) {
-  Initialize(script->GetIsolate(), BASE, zone);
-}
+#define PARSE_INFO_GETTER_WITH_DEFAULT(type, name, def) \
+  type CompilationInfo::name() const {                  \
+    return parse_info() ? parse_info()->name() : def;   \
+  }
 
 
-CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info,
-                                 Zone* zone)
-    : flags_(kLazy | kThisHasUses),
-      shared_info_(shared_info),
-      script_(Handle<Script>(Script::cast(shared_info->script()))),
-      source_stream_(NULL),
-      osr_ast_id_(BailoutId::None()),
-      parameter_count_(0),
-      optimization_id_(-1),
-      ast_value_factory_(NULL),
-      ast_value_factory_owned_(false),
-      aborted_due_to_dependency_change_(false),
-      osr_expr_stack_height_(0) {
-  Initialize(script_->GetIsolate(), BASE, zone);
-}
+PARSE_INFO_GETTER(Handle<Script>, script)
+PARSE_INFO_GETTER(bool, is_eval)
+PARSE_INFO_GETTER(bool, is_native)
+PARSE_INFO_GETTER(bool, is_module)
+PARSE_INFO_GETTER(LanguageMode, language_mode)
+PARSE_INFO_GETTER_WITH_DEFAULT(Handle<JSFunction>, closure,
+                               Handle<JSFunction>::null())
+PARSE_INFO_GETTER(FunctionLiteral*, function)
+PARSE_INFO_GETTER_WITH_DEFAULT(Scope*, scope, nullptr)
+PARSE_INFO_GETTER(Handle<Context>, context)
+PARSE_INFO_GETTER(Handle<SharedFunctionInfo>, shared_info)
 
+#undef PARSE_INFO_GETTER
+#undef PARSE_INFO_GETTER_WITH_DEFAULT
 
-CompilationInfo::CompilationInfo(Handle<JSFunction> closure, Zone* zone)
-    : flags_(kLazy | kThisHasUses),
-      closure_(closure),
-      shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
-      script_(Handle<Script>(Script::cast(shared_info_->script()))),
-      source_stream_(NULL),
-      context_(closure->context()),
-      osr_ast_id_(BailoutId::None()),
-      parameter_count_(0),
-      optimization_id_(-1),
-      ast_value_factory_(NULL),
-      ast_value_factory_owned_(false),
-      aborted_due_to_dependency_change_(false),
-      osr_expr_stack_height_(0) {
-  Initialize(script_->GetIsolate(), BASE, zone);
-}
 
+// Exactly like a CompilationInfo, except being allocated via {new} and it also
+// creates and enters a Zone on construction and deallocates it on destruction.
+class CompilationInfoWithZone : public CompilationInfo {
+ public:
+  explicit CompilationInfoWithZone(Handle<JSFunction> function)
+      : CompilationInfo(new ParseInfo(&zone_, function)) {}
 
-CompilationInfo::CompilationInfo(CodeStub* stub, Isolate* isolate, Zone* zone)
-    : flags_(kLazy | kThisHasUses),
-      source_stream_(NULL),
-      osr_ast_id_(BailoutId::None()),
-      parameter_count_(0),
-      optimization_id_(-1),
-      ast_value_factory_(NULL),
-      ast_value_factory_owned_(false),
-      aborted_due_to_dependency_change_(false),
-      osr_expr_stack_height_(0) {
-  Initialize(isolate, STUB, zone);
-  code_stub_ = stub;
-}
+  // Virtual destructor because a CompilationInfoWithZone has to exit the
+  // zone scope and get rid of dependent maps even when the destructor is
+  // called when cast as a CompilationInfo.
+  virtual ~CompilationInfoWithZone() {
+    DisableFutureOptimization();
+    RollbackDependencies();
+    delete parse_info_;
+    parse_info_ = nullptr;
+  }
 
+ private:
+  Zone zone_;
+};
 
-CompilationInfo::CompilationInfo(
-    ScriptCompiler::ExternalSourceStream* stream,
-    ScriptCompiler::StreamedSource::Encoding encoding, Isolate* isolate,
-    Zone* zone)
-    : flags_(kThisHasUses),
-      source_stream_(stream),
-      source_stream_encoding_(encoding),
-      osr_ast_id_(BailoutId::None()),
-      parameter_count_(0),
-      optimization_id_(-1),
-      ast_value_factory_(NULL),
-      ast_value_factory_owned_(false),
-      aborted_due_to_dependency_change_(false),
-      osr_expr_stack_height_(0) {
-  Initialize(isolate, BASE, zone);
+
+bool CompilationInfo::has_shared_info() const {
+  return parse_info_ && !parse_info_->shared_info().is_null();
 }
 
 
-void CompilationInfo::Initialize(Isolate* isolate,
-                                 Mode mode,
-                                 Zone* zone) {
-  isolate_ = isolate;
-  function_ = NULL;
-  scope_ = NULL;
-  script_scope_ = NULL;
-  extension_ = NULL;
-  cached_data_ = NULL;
-  compile_options_ = ScriptCompiler::kNoCompileOptions;
-  zone_ = zone;
-  deferred_handles_ = NULL;
-  code_stub_ = NULL;
-  prologue_offset_ = Code::kPrologueOffsetNotSet;
-  opt_count_ = shared_info().is_null() ? 0 : shared_info()->opt_count();
-  no_frame_ranges_ = isolate->cpu_profiler()->is_profiling()
-                   ? new List<OffsetRange>(2) : NULL;
-  if (FLAG_hydrogen_track_positions) {
-    inlined_function_infos_ = new List<InlinedFunctionInfo>(5);
-    inlining_id_to_function_id_ = new List<int>(5);
-  } else {
-    inlined_function_infos_ = NULL;
-    inlining_id_to_function_id_ = NULL;
-  }
-
-  for (int i = 0; i < DependentCode::kGroupCount; i++) {
-    dependencies_[i] = NULL;
-  }
-  if (mode == STUB) {
-    mode_ = STUB;
-    return;
-  }
-  mode_ = mode;
-  if (!script_.is_null() && script_->type()->value() == Script::TYPE_NATIVE) {
-    MarkAsNative();
-  }
+CompilationInfo::CompilationInfo(ParseInfo* parse_info)
+    : CompilationInfo(parse_info, nullptr, BASE, parse_info->isolate(),
+                      parse_info->zone()) {
   // 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::
@@ -187,34 +115,54 @@ void CompilationInfo::Initialize(Isolate* isolate,
 
   if (isolate_->debug()->is_active()) MarkAsDebug();
   if (FLAG_context_specialization) MarkAsContextSpecializing();
+  if (FLAG_turbo_builtin_inlining) MarkAsBuiltinInliningEnabled();
   if (FLAG_turbo_inlining) MarkAsInliningEnabled();
   if (FLAG_turbo_splitting) MarkAsSplittingEnabled();
   if (FLAG_turbo_types) MarkAsTypingEnabled();
 
-  if (!shared_info_.is_null()) {
-    DCHECK(is_sloppy(language_mode()));
-    SetLanguageMode(shared_info_->language_mode());
-  }
-  bailout_reason_ = kNoReason;
-
-  if (!shared_info().is_null() && shared_info()->is_compiled()) {
+  if (has_shared_info() && shared_info()->is_compiled()) {
     // We should initialize the CompilationInfo feedback vector from the
     // passed in shared info, rather than creating a new one.
-    feedback_vector_ =
-        Handle<TypeFeedbackVector>(shared_info()->feedback_vector(), isolate);
+    feedback_vector_ = Handle<TypeFeedbackVector>(
+        shared_info()->feedback_vector(), parse_info->isolate());
   }
 }
 
 
+CompilationInfo::CompilationInfo(CodeStub* stub, Isolate* isolate, Zone* zone)
+    : CompilationInfo(nullptr, stub, STUB, isolate, zone) {}
+
+
+CompilationInfo::CompilationInfo(ParseInfo* parse_info, CodeStub* code_stub,
+                                 Mode mode, Isolate* isolate, Zone* zone)
+    : parse_info_(parse_info),
+      isolate_(isolate),
+      flags_(0),
+      code_stub_(code_stub),
+      mode_(mode),
+      osr_ast_id_(BailoutId::None()),
+      zone_(zone),
+      deferred_handles_(nullptr),
+      bailout_reason_(kNoReason),
+      prologue_offset_(Code::kPrologueOffsetNotSet),
+      no_frame_ranges_(isolate->cpu_profiler()->is_profiling()
+                           ? new List<OffsetRange>(2)
+                           : nullptr),
+      track_positions_(FLAG_hydrogen_track_positions ||
+                       isolate->cpu_profiler()->is_profiling()),
+      opt_count_(has_shared_info() ? shared_info()->opt_count() : 0),
+      parameter_count_(0),
+      optimization_id_(-1),
+      aborted_due_to_dependency_change_(false),
+      osr_expr_stack_height_(0) {
+  std::fill_n(dependencies_, DependentCode::kGroupCount, nullptr);
+}
+
+
 CompilationInfo::~CompilationInfo() {
-  if (GetFlag(kDisableFutureOptimization)) {
-    shared_info()->DisableOptimization(bailout_reason());
-  }
+  DisableFutureOptimization();
   delete deferred_handles_;
   delete no_frame_ranges_;
-  delete inlined_function_infos_;
-  delete inlining_id_to_function_id_;
-  if (ast_value_factory_owned_) delete ast_value_factory_;
 #ifdef DEBUG
   // Check that no dependent maps have been added or added dependent maps have
   // been rolled back or committed.
@@ -273,33 +221,21 @@ void CompilationInfo::RollbackDependencies() {
 
 
 int CompilationInfo::num_parameters() const {
-  if (IsStub()) {
-    DCHECK(parameter_count_ > 0);
-    return parameter_count_;
-  } else {
-    return scope()->num_parameters();
-  }
+  return has_scope() ? scope()->num_parameters() : parameter_count_;
 }
 
 
 int CompilationInfo::num_heap_slots() const {
-  if (IsStub()) {
-    return 0;
-  } else {
-    return scope()->num_heap_slots();
-  }
+  return has_scope() ? scope()->num_heap_slots() : 0;
 }
 
 
 Code::Flags CompilationInfo::flags() const {
-  if (IsStub()) {
-    return Code::ComputeFlags(code_stub()->GetCodeKind(),
-                              code_stub()->GetICState(),
-                              code_stub()->GetExtraICState(),
-                              code_stub()->GetStubType());
-  } else {
-    return Code::ComputeFlags(Code::OPTIMIZED_FUNCTION);
-  }
+  return code_stub() != nullptr
+             ? Code::ComputeFlags(
+                   code_stub()->GetCodeKind(), code_stub()->GetICState(),
+                   code_stub()->GetExtraICState(), code_stub()->GetStubType())
+             : Code::ComputeFlags(Code::OPTIMIZED_FUNCTION);
 }
 
 
@@ -307,17 +243,10 @@ Code::Flags CompilationInfo::flags() const {
 // profiler, so they trigger their own optimization when they're called
 // for the SharedFunctionInfo::kCallsUntilPrimitiveOptimization-th time.
 bool CompilationInfo::ShouldSelfOptimize() {
-  return FLAG_crankshaft &&
-      !function()->flags()->Contains(kDontSelfOptimize) &&
-      !function()->dont_optimize() &&
-      function()->scope()->AllowsLazyCompilation() &&
-      (shared_info().is_null() || !shared_info()->optimization_disabled());
-}
-
-
-void CompilationInfo::PrepareForCompilation(Scope* scope) {
-  DCHECK(scope_ == NULL);
-  scope_ = scope;
+  return FLAG_crankshaft && !function()->flags()->Contains(kDontSelfOptimize) &&
+         !function()->dont_optimize() &&
+         function()->scope()->AllowsLazyCompilation() &&
+         (!has_shared_info() || !shared_info()->optimization_disabled());
 }
 
 
@@ -330,87 +259,95 @@ void CompilationInfo::EnsureFeedbackVector() {
 
 
 bool CompilationInfo::is_simple_parameter_list() {
-  return scope_->is_simple_parameter_list();
+  return scope()->is_simple_parameter_list();
 }
 
 
 int CompilationInfo::TraceInlinedFunction(Handle<SharedFunctionInfo> shared,
-                                          SourcePosition position) {
-  if (!FLAG_hydrogen_track_positions) {
-    return 0;
-  }
-
-  DCHECK(inlined_function_infos_);
-  DCHECK(inlining_id_to_function_id_);
-  int id = 0;
-  for (; id < inlined_function_infos_->length(); id++) {
-    if (inlined_function_infos_->at(id).shared().is_identical_to(shared)) {
-      break;
-    }
-  }
-  if (id == inlined_function_infos_->length()) {
-    inlined_function_infos_->Add(InlinedFunctionInfo(shared));
-
-    if (!shared->script()->IsUndefined()) {
-      Handle<Script> script(Script::cast(shared->script()));
-      if (!script->source()->IsUndefined()) {
-        CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
-        OFStream os(tracing_scope.file());
-        os << "--- FUNCTION SOURCE (" << shared->DebugName()->ToCString().get()
-           << ") id{" << optimization_id() << "," << id << "} ---\n";
-        {
-          DisallowHeapAllocation no_allocation;
-          int start = shared->start_position();
-          int len = shared->end_position() - start;
-          String::SubStringRange source(String::cast(script->source()), start,
-                                        len);
-          for (const auto& c : source) {
-            os << AsReversiblyEscapedUC16(c);
-          }
+                                          SourcePosition position,
+                                          int parent_id) {
+  DCHECK(track_positions_);
+
+  int inline_id = static_cast<int>(inlined_function_infos_.size());
+  InlinedFunctionInfo info(parent_id, position, UnboundScript::kNoScriptId,
+      shared->start_position());
+  if (!shared->script()->IsUndefined()) {
+    Handle<Script> script(Script::cast(shared->script()));
+    info.script_id = script->id()->value();
+
+    if (FLAG_hydrogen_track_positions && !script->source()->IsUndefined()) {
+      CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
+      OFStream os(tracing_scope.file());
+      os << "--- FUNCTION SOURCE (" << shared->DebugName()->ToCString().get()
+         << ") id{" << optimization_id() << "," << inline_id << "} ---\n";
+      {
+        DisallowHeapAllocation no_allocation;
+        int start = shared->start_position();
+        int len = shared->end_position() - start;
+        String::SubStringRange source(String::cast(script->source()), start,
+                                      len);
+        for (const auto& c : source) {
+          os << AsReversiblyEscapedUC16(c);
         }
-
-        os << "\n--- END ---\n";
       }
+
+      os << "\n--- END ---\n";
     }
   }
 
-  int inline_id = inlining_id_to_function_id_->length();
-  inlining_id_to_function_id_->Add(id);
+  inlined_function_infos_.push_back(info);
 
-  if (inline_id != 0) {
+  if (FLAG_hydrogen_track_positions && inline_id != 0) {
     CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
     OFStream os(tracing_scope.file());
     os << "INLINE (" << shared->DebugName()->ToCString().get() << ") id{"
-       << optimization_id() << "," << id << "} AS " << inline_id << " AT "
-       << position << std::endl;
+       << optimization_id() << "," << inline_id << "} AS " << inline_id
+       << " AT " << position << std::endl;
   }
 
   return inline_id;
 }
 
 
+void CompilationInfo::LogDeoptCallPosition(int pc_offset, int inlining_id) {
+  if (!track_positions_ || IsStub()) return;
+  DCHECK_LT(static_cast<size_t>(inlining_id), inlined_function_infos_.size());
+  inlined_function_infos_.at(inlining_id).deopt_pc_offsets.push_back(pc_offset);
+}
+
+
 class HOptimizedGraphBuilderWithPositions: public HOptimizedGraphBuilder {
  public:
   explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info)
       : HOptimizedGraphBuilder(info) {
   }
 
-#define DEF_VISIT(type)                               \
-  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 {                    \
+    SourcePosition old_position = SourcePosition::Unknown(); \
+    if (node->position() != RelocInfo::kNoPosition) {        \
+      old_position = source_position();                      \
+      SetSourcePosition(node->position());                   \
+    }                                                        \
+    HOptimizedGraphBuilder::Visit##type(node);               \
+    if (!old_position.IsUnknown()) {                         \
+      set_source_position(old_position);                     \
+    }                                                        \
   }
   EXPRESSION_NODE_LIST(DEF_VISIT)
 #undef DEF_VISIT
 
-#define DEF_VISIT(type)                               \
-  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 {                    \
+    SourcePosition old_position = SourcePosition::Unknown(); \
+    if (node->position() != RelocInfo::kNoPosition) {        \
+      old_position = source_position();                      \
+      SetSourcePosition(node->position());                   \
+    }                                                        \
+    HOptimizedGraphBuilder::Visit##type(node);               \
+    if (!old_position.IsUnknown()) {                         \
+      set_source_position(old_position);                     \
+    }                                                        \
   }
   STATEMENT_NODE_LIST(DEF_VISIT)
 #undef DEF_VISIT
@@ -501,6 +438,13 @@ OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
       if (info()->is_osr()) os << " OSR";
       os << "]" << std::endl;
     }
+
+    if (info()->shared_info()->asm_function()) {
+      info()->MarkAsContextSpecializing();
+    } else if (FLAG_turbo_type_feedback) {
+      info()->MarkAsTypeFeedbackEnabled();
+    }
+
     Timer t(this, &time_taken_to_create_graph_);
     compiler::Pipeline pipeline(info());
     pipeline.GenerateCode();
@@ -509,6 +453,9 @@ OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
     }
   }
 
+  // Do not use Crankshaft if the code is intended to be serialized.
+  if (!isolate()->use_crankshaft()) return SetLastStatus(FAILED);
+
   if (FLAG_trace_opt) {
     OFStream os(stdout);
     os << "[compiling method " << Brief(*info()->closure())
@@ -531,12 +478,12 @@ OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
         info()->shared_info()->disable_optimization_reason());
   }
 
-  graph_builder_ = (FLAG_hydrogen_track_positions || FLAG_trace_ic)
-      ? new(info()->zone()) HOptimizedGraphBuilderWithPositions(info())
-      : new(info()->zone()) HOptimizedGraphBuilder(info());
+  graph_builder_ = (info()->is_tracking_positions() || FLAG_trace_ic)
+                       ? new (info()->zone())
+                             HOptimizedGraphBuilderWithPositions(info())
+                       : new (info()->zone()) HOptimizedGraphBuilder(info());
 
   Timer t(this, &time_taken_to_create_graph_);
-  info()->set_this_has_uses(false);
   graph_ = graph_builder_->CreateGraph();
 
   if (isolate()->has_pending_exception()) {
@@ -586,7 +533,8 @@ OptimizedCompileJob::Status OptimizedCompileJob::GenerateCode() {
   // 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());
+      info()->parse_info()->context()->native_context()->AddOptimizedCode(
+          *info()->code());
     }
     RecordOptimizationStats();
     return last_status();
@@ -698,7 +646,7 @@ static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
   // enabled as finding the line number is not free.
   if (info->isolate()->logger()->is_logging_code_events() ||
       info->isolate()->cpu_profiler()->is_profiling()) {
-    Handle<Script> script = info->script();
+    Handle<Script> script = info->parse_info()->script();
     Handle<Code> code = info->code();
     if (code.is_identical_to(info->isolate()->builtins()->CompileLazy())) {
       return;
@@ -714,16 +662,13 @@ static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
             CodeCreateEvent(log_tag, *code, *shared, info, script_name,
                             line_num, column_num));
   }
-
-  GDBJIT(AddCode(Handle<String>(shared->DebugName()),
-                 Handle<Script>(info->script()), Handle<Code>(info->code()),
-                 info));
 }
 
 
 static bool CompileUnoptimizedCode(CompilationInfo* info) {
   DCHECK(AllowCompilation::IsAllowed(info->isolate()));
-  if (!Compiler::Analyze(info) || !FullCodeGenerator::MakeCode(info)) {
+  if (!Compiler::Analyze(info->parse_info()) ||
+      !FullCodeGenerator::MakeCode(info)) {
     Isolate* isolate = info->isolate();
     if (!isolate->has_pending_exception()) isolate->StackOverflow();
     return false;
@@ -738,7 +683,7 @@ MUST_USE_RESULT static MaybeHandle<Code> GetUnoptimizedCodeCommon(
   PostponeInterruptsScope postpone(info->isolate());
 
   // Parse and update CompilationInfo with the results.
-  if (!Parser::ParseStatic(info)) return MaybeHandle<Code>();
+  if (!Parser::ParseStatic(info->parse_info())) return MaybeHandle<Code>();
   Handle<SharedFunctionInfo> shared = info->shared_info();
   FunctionLiteral* lit = info->function();
   shared->set_language_mode(lit->language_mode());
@@ -814,22 +759,23 @@ static void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) {
 }
 
 
-static bool Renumber(CompilationInfo* info) {
-  if (!AstNumbering::Renumber(info->isolate(), info->zone(),
-                              info->function())) {
+static bool Renumber(ParseInfo* parse_info) {
+  if (!AstNumbering::Renumber(parse_info->isolate(), parse_info->zone(),
+                              parse_info->function())) {
     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));
+  Handle<SharedFunctionInfo> shared_info = parse_info->shared_info();
+  if (!shared_info.is_null()) {
+    FunctionLiteral* lit = parse_info->function();
+    shared_info->set_ast_node_count(lit->ast_node_count());
+    MaybeDisableOptimization(shared_info, lit->dont_optimize_reason());
+    shared_info->set_dont_cache(lit->flags()->Contains(kDontCache));
   }
   return true;
 }
 
 
-bool Compiler::Analyze(CompilationInfo* info) {
+bool Compiler::Analyze(ParseInfo* info) {
   DCHECK(info->function() != NULL);
   if (!Rewriter::Rewrite(info)) return false;
   if (!Scope::Analyze(info)) return false;
@@ -839,14 +785,14 @@ bool Compiler::Analyze(CompilationInfo* info) {
 }
 
 
-bool Compiler::ParseAndAnalyze(CompilationInfo* info) {
+bool Compiler::ParseAndAnalyze(ParseInfo* info) {
   if (!Parser::ParseStatic(info)) return false;
   return Compiler::Analyze(info);
 }
 
 
 static bool GetOptimizedCodeNow(CompilationInfo* info) {
-  if (!Compiler::ParseAndAnalyze(info)) return false;
+  if (!Compiler::ParseAndAnalyze(info->parse_info())) return false;
 
   TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate());
 
@@ -883,8 +829,11 @@ static bool GetOptimizedCodeLater(CompilationInfo* info) {
   }
 
   CompilationHandleScope handle_scope(info);
-  if (!Compiler::ParseAndAnalyze(info)) return false;
-  info->SaveHandles();  // Copy handles to the compilation handle scope.
+  if (!Compiler::ParseAndAnalyze(info->parse_info())) return false;
+
+  // Reopen handles in the new CompilationHandleScope.
+  info->ReopenHandlesInNewHandleScope();
+  info->parse_info()->ReopenHandlesInNewHandleScope();
 
   TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate());
 
@@ -930,14 +879,14 @@ MaybeHandle<Code> Compiler::GetLazyCode(Handle<JSFunction> 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())) {
+      (FLAG_turbo_deoptimization || !isolate->debug()->is_active()) &&
+      !FLAG_turbo_osr) {
     CompilationInfoWithZone info(function);
 
     VMState<COMPILER> state(isolate);
     PostponeInterruptsScope postpone(isolate);
 
     info.SetOptimizing(BailoutId::None(), handle(function->shared()->code()));
-    info.MarkAsContextSpecializing();
 
     if (GetOptimizedCodeNow(&info)) {
       DCHECK(function->shared()->is_compiled());
@@ -957,7 +906,7 @@ MaybeHandle<Code> Compiler::GetLazyCode(Handle<JSFunction> function) {
   ASSIGN_RETURN_ON_EXCEPTION(isolate, result, GetUnoptimizedCodeCommon(&info),
                              Code);
 
-  if (FLAG_always_opt && isolate->use_crankshaft()) {
+  if (FLAG_always_opt) {
     Handle<Code> opt_code;
     if (Compiler::GetOptimizedCode(
             function, result,
@@ -975,7 +924,9 @@ MaybeHandle<Code> Compiler::GetUnoptimizedCode(
   DCHECK(!shared->GetIsolate()->has_pending_exception());
   DCHECK(!shared->is_compiled());
 
-  CompilationInfoWithZone info(shared);
+  Zone zone;
+  ParseInfo parse_info(&zone, shared);
+  CompilationInfo info(&parse_info);
   return GetUnoptimizedCodeCommon(&info);
 }
 
@@ -1002,14 +953,16 @@ bool Compiler::EnsureCompiled(Handle<JSFunction> function,
 bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) {
   DCHECK(info->function() != NULL);
   DCHECK(info->scope() != NULL);
-  if (!info->shared_info()->has_deoptimization_support()) {
-    Handle<SharedFunctionInfo> shared = info->shared_info();
-    CompilationInfoWithZone unoptimized(shared);
+  Handle<SharedFunctionInfo> shared = info->shared_info();
+  if (!shared->has_deoptimization_support()) {
+    // TODO(titzer): just reuse the ParseInfo for the unoptimized compile.
+    CompilationInfoWithZone unoptimized(info->closure());
     // 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());
+    ParseInfo* parse_info = unoptimized.parse_info();
+    parse_info->set_literal(info->function());
+    parse_info->set_scope(info->scope());
+    parse_info->set_context(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
@@ -1079,16 +1032,18 @@ MaybeHandle<Code> Compiler::GetDebugCode(Handle<JSFunction> function) {
 
 void Compiler::CompileForLiveEdit(Handle<Script> script) {
   // TODO(635): support extensions.
-  CompilationInfoWithZone info(script);
+  Zone zone;
+  ParseInfo parse_info(&zone, script);
+  CompilationInfo info(&parse_info);
   PostponeInterruptsScope postpone(info.isolate());
   VMState<COMPILER> state(info.isolate());
 
-  info.MarkAsGlobal();
-  if (!Parser::ParseStatic(&info)) return;
+  info.parse_info()->set_global();
+  if (!Parser::ParseStatic(info.parse_info())) return;
 
   LiveEditFunctionTracker tracker(info.isolate(), info.function());
   if (!CompileUnoptimizedCode(&info)) return;
-  if (!info.shared_info().is_null()) {
+  if (info.has_shared_info()) {
     Handle<ScopeInfo> scope_info =
         ScopeInfo::Create(info.isolate(), info.zone(), info.scope());
     info.shared_info()->set_scope_info(*scope_info);
@@ -1101,40 +1056,44 @@ static Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) {
   Isolate* isolate = info->isolate();
   PostponeInterruptsScope postpone(isolate);
   DCHECK(!isolate->native_context().is_null());
-  Handle<Script> script = info->script();
+  ParseInfo* parse_info = info->parse_info();
+  Handle<Script> script = parse_info->script();
 
   // TODO(svenpanne) Obscure place for this, perhaps move to OnBeforeCompile?
   FixedArray* array = isolate->native_context()->embedder_data();
-  script->set_context_data(array->get(0));
+  script->set_context_data(array->get(v8::Context::kDebugIdIndex));
 
   isolate->debug()->OnBeforeCompile(script);
 
-  DCHECK(info->is_eval() || info->is_global() || info->is_module());
+  DCHECK(parse_info->is_eval() || parse_info->is_global() ||
+         parse_info->is_module());
 
-  info->MarkAsToplevel();
+  parse_info->set_toplevel();
 
   Handle<SharedFunctionInfo> result;
 
   { VMState<COMPILER> state(info->isolate());
-    if (info->function() == NULL) {
+    if (parse_info->literal() == NULL) {
       // Parse the script if needed (if it's already parsed, function() is
       // non-NULL).
-      bool parse_allow_lazy =
-          (info->compile_options() == ScriptCompiler::kConsumeParserCache ||
-           String::cast(script->source())->length() >
-               FLAG_min_preparse_length) &&
-          !Compiler::DebuggerWantsEagerCompilation(info);
+      ScriptCompiler::CompileOptions options = parse_info->compile_options();
+      bool parse_allow_lazy = (options == ScriptCompiler::kConsumeParserCache ||
+                               String::cast(script->source())->length() >
+                                   FLAG_min_preparse_length) &&
+                              !Compiler::DebuggerWantsEagerCompilation(isolate);
 
+      parse_info->set_allow_lazy_parsing(parse_allow_lazy);
       if (!parse_allow_lazy &&
-          (info->compile_options() == ScriptCompiler::kProduceParserCache ||
-           info->compile_options() == ScriptCompiler::kConsumeParserCache)) {
+          (options == ScriptCompiler::kProduceParserCache ||
+           options == ScriptCompiler::kConsumeParserCache)) {
         // We are going to parse eagerly, but we either 1) have cached data
         // produced by lazy parsing or 2) are asked to generate cached data.
         // Eager parsing cannot benefit from cached data, and producing cached
         // data while parsing eagerly is not implemented.
-        info->SetCachedData(NULL, ScriptCompiler::kNoCompileOptions);
+        parse_info->set_cached_data(nullptr);
+        parse_info->set_compile_options(ScriptCompiler::kNoCompileOptions);
       }
-      if (!Parser::ParseStatic(info, parse_allow_lazy)) {
+      if (!Parser::ParseStatic(parse_info)) {
         return Handle<SharedFunctionInfo>::null();
       }
     }
@@ -1177,7 +1136,6 @@ static Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) {
 
     PROFILE(isolate, CodeCreateEvent(
                 log_tag, *info->code(), *result, info, *script_name));
-    GDBJIT(AddCode(script_name, script, info->code(), info));
 
     // Hint to the runtime system used when allocating space for initial
     // property space by setting the expected number of properties for
@@ -1214,12 +1172,14 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
 
   if (!maybe_shared_info.ToHandle(&shared_info)) {
     Handle<Script> script = isolate->factory()->NewScript(source);
-    CompilationInfoWithZone info(script);
-    info.MarkAsEval();
-    if (context->IsNativeContext()) info.MarkAsGlobal();
-    info.SetLanguageMode(language_mode);
-    info.SetParseRestriction(restriction);
-    info.SetContext(context);
+    Zone zone;
+    ParseInfo parse_info(&zone, script);
+    CompilationInfo info(&parse_info);
+    parse_info.set_eval();
+    if (context->IsNativeContext()) parse_info.set_global();
+    parse_info.set_language_mode(language_mode);
+    parse_info.set_parse_restriction(restriction);
+    parse_info.set_context(context);
 
     Debug::RecordEvalCaller(script);
 
@@ -1254,8 +1214,8 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
 Handle<SharedFunctionInfo> Compiler::CompileScript(
     Handle<String> source, Handle<Object> script_name, int line_offset,
     int column_offset, bool is_embedder_debug_script,
-    bool is_shared_cross_origin, Handle<Context> context,
-    v8::Extension* extension, ScriptData** cached_data,
+    bool is_shared_cross_origin, Handle<Object> source_map_url,
+    Handle<Context> context, v8::Extension* extension, ScriptData** cached_data,
     ScriptCompiler::CompileOptions compile_options, NativesFlag natives,
     bool is_module) {
   Isolate* isolate = source->GetIsolate();
@@ -1331,23 +1291,31 @@ Handle<SharedFunctionInfo> Compiler::CompileScript(
     }
     script->set_is_shared_cross_origin(is_shared_cross_origin);
     script->set_is_embedder_debug_script(is_embedder_debug_script);
+    if (!source_map_url.is_null()) {
+      script->set_source_mapping_url(*source_map_url);
+    }
 
     // Compile the function and add it to the cache.
-    CompilationInfoWithZone info(script);
+    Zone zone;
+    ParseInfo parse_info(&zone, script);
+    CompilationInfo info(&parse_info);
     if (FLAG_harmony_modules && is_module) {
-      info.MarkAsModule();
+      parse_info.set_module();
     } else {
-      info.MarkAsGlobal();
+      parse_info.set_global();
     }
-    info.SetCachedData(cached_data, compile_options);
-    info.SetExtension(extension);
-    info.SetContext(context);
+    if (compile_options != ScriptCompiler::kNoCompileOptions) {
+      parse_info.set_cached_data(cached_data);
+    }
+    parse_info.set_compile_options(compile_options);
+    parse_info.set_extension(extension);
+    parse_info.set_context(context);
     if (FLAG_serialize_toplevel &&
         compile_options == ScriptCompiler::kProduceCodeCache) {
       info.PrepareForSerializing();
     }
 
-    info.SetLanguageMode(
+    parse_info.set_language_mode(
         static_cast<LanguageMode>(info.language_mode() | language_mode));
     result = CompileToplevel(&info);
     if (extension == NULL && !result.is_null() && !result->dont_cache()) {
@@ -1373,19 +1341,21 @@ Handle<SharedFunctionInfo> Compiler::CompileScript(
 
 
 Handle<SharedFunctionInfo> Compiler::CompileStreamedScript(
-    CompilationInfo* info, int source_length) {
-  Isolate* isolate = info->isolate();
+    Handle<Script> script, ParseInfo* parse_info, int source_length) {
+  Isolate* isolate = script->GetIsolate();
+  // TODO(titzer): increment the counters in caller.
   isolate->counters()->total_load_size()->Increment(source_length);
   isolate->counters()->total_compile_size()->Increment(source_length);
 
   LanguageMode language_mode =
       construct_language_mode(FLAG_use_strict, FLAG_use_strong);
-  info->SetLanguageMode(
-      static_cast<LanguageMode>(info->language_mode() | language_mode));
+  parse_info->set_language_mode(
+      static_cast<LanguageMode>(parse_info->language_mode() | language_mode));
 
+  CompilationInfo compile_info(parse_info);
   // TODO(marja): FLAG_serialize_toplevel is not honoured and won't be; when the
   // real code caching lands, streaming needs to be adapted to use it.
-  return CompileToplevel(info);
+  return CompileToplevel(&compile_info);
 }
 
 
@@ -1393,10 +1363,12 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(
     FunctionLiteral* literal, Handle<Script> script,
     CompilationInfo* outer_info) {
   // Precondition: code has been parsed and scopes have been analyzed.
-  CompilationInfoWithZone info(script);
-  info.SetFunction(literal);
-  info.PrepareForCompilation(literal->scope());
-  info.SetLanguageMode(literal->scope()->language_mode());
+  Zone zone;
+  ParseInfo parse_info(&zone, script);
+  CompilationInfo info(&parse_info);
+  parse_info.set_literal(literal);
+  parse_info.set_scope(literal->scope());
+  parse_info.set_language_mode(literal->scope()->language_mode());
   if (outer_info->will_serialize()) info.PrepareForSerializing();
 
   Isolate* isolate = info.isolate();
@@ -1412,10 +1384,11 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(
   // of functions without an outer context when setting a breakpoint through
   // Debug::FindSharedFunctionInfoInScript.
   bool allow_lazy_without_ctx = literal->AllowsLazyCompilationWithoutContext();
-  bool allow_lazy = literal->AllowsLazyCompilation() &&
-      !DebuggerWantsEagerCompilation(&info, allow_lazy_without_ctx);
+  bool allow_lazy =
+      literal->AllowsLazyCompilation() &&
+      !DebuggerWantsEagerCompilation(isolate, allow_lazy_without_ctx);
 
-  if (outer_info->is_toplevel() && outer_info->will_serialize()) {
+  if (outer_info->parse_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.
@@ -1436,7 +1409,8 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(
     // called.
     info.EnsureFeedbackVector();
     scope_info = Handle<ScopeInfo>(ScopeInfo::Empty(isolate));
-  } else if (Renumber(&info) && FullCodeGenerator::MakeCode(&info)) {
+  } else if (Renumber(info.parse_info()) &&
+             FullCodeGenerator::MakeCode(&info)) {
     // MakeCode will ensure that the feedback vector is present and
     // appropriately sized.
     DCHECK(!info.code().is_null());
@@ -1481,7 +1455,6 @@ MaybeHandle<Code> Compiler::GetOptimizedCode(Handle<JSFunction> function,
   Isolate* isolate = info->isolate();
   DCHECK(AllowCompilation::IsAllowed(isolate));
   VMState<COMPILER> state(isolate);
-  DCHECK(isolate->use_crankshaft());
   DCHECK(!isolate->has_pending_exception());
   PostponeInterruptsScope postpone(isolate);
 
@@ -1565,10 +1538,10 @@ Handle<Code> Compiler::GetConcurrentlyOptimizedCode(OptimizedCompileJob* job) {
 }
 
 
-bool Compiler::DebuggerWantsEagerCompilation(CompilationInfo* info,
+bool Compiler::DebuggerWantsEagerCompilation(Isolate* isolate,
                                              bool allow_lazy_without_ctx) {
-  if (LiveEditFunctionTracker::IsActive(info->isolate())) return true;
-  Debug* debug = info->isolate()->debug();
+  if (LiveEditFunctionTracker::IsActive(isolate)) return true;
+  Debug* debug = isolate->debug();
   bool debugging = debug->is_active() || debug->has_break_points();
   return debugging && !allow_lazy_without_ctx;
 }
index 8ef2e0a..fb91a9e 100644 (file)
@@ -15,13 +15,8 @@ namespace internal {
 
 class AstValueFactory;
 class HydrogenCodeStub;
-
-// ParseRestriction is used to restrict the set of valid statements in a
-// unit of compilation.  Restriction violations cause a syntax error.
-enum ParseRestriction {
-  NO_PARSE_RESTRICTION,         // All expressions are allowed.
-  ONLY_SINGLE_FUNCTION_LITERAL  // Only a single FunctionLiteral expression.
-};
+class ParseInfo;
+class ScriptData;
 
 struct OffsetRange {
   OffsetRange(int from, int to) : from(from), to(to) {}
@@ -39,9 +34,9 @@ struct OffsetRange {
 // script start.
 class SourcePosition {
  public:
-  SourcePosition(const SourcePosition& other) : value_(other.value_) {}
-
-  static SourcePosition Unknown() { return SourcePosition(kNoPosition); }
+  static SourcePosition Unknown() {
+    return SourcePosition::FromRaw(kNoPosition);
+  }
 
   bool IsUnknown() const { return value_ == kNoPosition; }
 
@@ -72,10 +67,14 @@ class SourcePosition {
   // Offset from the start of the inlined function.
   typedef BitField<uint32_t, 9, 23> PositionField;
 
-  explicit SourcePosition(uint32_t value) : value_(value) {}
-
   friend class HPositionInfo;
-  friend class LCodeGenBase;
+  friend class Deoptimizer;
+
+  static SourcePosition FromRaw(uint32_t raw_position) {
+    SourcePosition position;
+    position.value_ = raw_position;
+    return position;
+  }
 
   // If FLAG_hydrogen_track_positions is set contains bitfields InliningIdField
   // and PositionField.
@@ -87,52 +86,23 @@ class SourcePosition {
 std::ostream& operator<<(std::ostream& os, const SourcePosition& p);
 
 
-class InlinedFunctionInfo {
- public:
-  explicit InlinedFunctionInfo(Handle<SharedFunctionInfo> shared)
-      : shared_(shared), start_position_(shared->start_position()) {}
-
-  Handle<SharedFunctionInfo> shared() const { return shared_; }
-  int start_position() const { return start_position_; }
-
- private:
-  Handle<SharedFunctionInfo> shared_;
-  int start_position_;
+struct InlinedFunctionInfo {
+  InlinedFunctionInfo(int parent_id, SourcePosition inline_position,
+                      int script_id, int start_position)
+      : parent_id(parent_id),
+        inline_position(inline_position),
+        script_id(script_id),
+        start_position(start_position) {}
+  int parent_id;
+  SourcePosition inline_position;
+  int script_id;
+  int start_position;
+  std::vector<size_t> deopt_pc_offsets;
+
+  static const int kNoParentId = -1;
 };
 
 
-class ScriptData {
- public:
-  ScriptData(const byte* data, int length);
-  ~ScriptData() {
-    if (owns_data_) DeleteArray(data_);
-  }
-
-  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_);
-    owns_data_ = true;
-  }
-
-  void ReleaseDataOwnership() {
-    DCHECK(owns_data_);
-    owns_data_ = false;
-  }
-
- private:
-  bool owns_data_ : 1;
-  bool rejected_ : 1;
-  const byte* data_;
-  int length_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScriptData);
-};
-
 // CompilationInfo encapsulates some information known at compile time.  It
 // is constructed based on the resources available at compile-time.
 class CompilationInfo {
@@ -140,113 +110,67 @@ class CompilationInfo {
   // Various configuration flags for a compilation, as well as some properties
   // of the compiled code produced by a compilation.
   enum Flag {
-    kLazy = 1 << 0,
-    kEval = 1 << 1,
-    kGlobal = 1 << 2,
-    kStrictMode = 1 << 3,
-    kStrongMode = 1 << 4,
-    kThisHasUses = 1 << 5,
-    kNative = 1 << 6,
-    kDeferredCalling = 1 << 7,
-    kNonDeferredCalling = 1 << 8,
-    kSavesCallerDoubles = 1 << 9,
-    kRequiresFrame = 1 << 10,
-    kMustNotHaveEagerFrame = 1 << 11,
-    kDeoptimizationSupport = 1 << 12,
-    kDebug = 1 << 13,
-    kCompilingForDebugging = 1 << 14,
-    kParseRestriction = 1 << 15,
-    kSerializing = 1 << 16,
-    kContextSpecializing = 1 << 17,
-    kInliningEnabled = 1 << 18,
-    kTypingEnabled = 1 << 19,
-    kDisableFutureOptimization = 1 << 20,
-    kModule = 1 << 21,
-    kToplevel = 1 << 22,
-    kSplittingEnabled = 1 << 23
+    kDeferredCalling = 1 << 0,
+    kNonDeferredCalling = 1 << 1,
+    kSavesCallerDoubles = 1 << 2,
+    kRequiresFrame = 1 << 3,
+    kMustNotHaveEagerFrame = 1 << 4,
+    kDeoptimizationSupport = 1 << 5,
+    kDebug = 1 << 6,
+    kCompilingForDebugging = 1 << 7,
+    kSerializing = 1 << 8,
+    kContextSpecializing = 1 << 9,
+    kInliningEnabled = 1 << 10,
+    kTypingEnabled = 1 << 11,
+    kDisableFutureOptimization = 1 << 12,
+    kSplittingEnabled = 1 << 13,
+    kBuiltinInliningEnabled = 1 << 14,
+    kTypeFeedbackEnabled = 1 << 15
   };
 
-  CompilationInfo(Handle<JSFunction> closure, Zone* zone);
-  CompilationInfo(Handle<Script> script, Zone* zone);
+  explicit CompilationInfo(ParseInfo* parse_info);
   CompilationInfo(CodeStub* stub, Isolate* isolate, Zone* zone);
   virtual ~CompilationInfo();
 
+  ParseInfo* parse_info() const { return parse_info_; }
+
+  // -----------------------------------------------------------
+  // TODO(titzer): inline and delete accessors of ParseInfo
+  // -----------------------------------------------------------
+  Handle<Script> script() const;
+  bool is_eval() const;
+  bool is_native() const;
+  bool is_module() const;
+  LanguageMode language_mode() const;
+  Handle<JSFunction> closure() const;
+  FunctionLiteral* function() const;
+  Scope* scope() const;
+  Handle<Context> context() const;
+  Handle<SharedFunctionInfo> shared_info() const;
+  bool has_shared_info() const;
+  // -----------------------------------------------------------
+
   Isolate* isolate() const {
     return isolate_;
   }
   Zone* zone() { return zone_; }
   bool is_osr() const { return !osr_ast_id_.IsNone(); }
-  bool is_lazy() const { return GetFlag(kLazy); }
-  bool is_eval() const { return GetFlag(kEval); }
-  bool is_global() const { return GetFlag(kGlobal); }
-  bool is_module() const { return GetFlag(kModule); }
-  LanguageMode language_mode() const {
-    STATIC_ASSERT(LANGUAGE_END == 3);
-    return construct_language_mode(GetFlag(kStrictMode), GetFlag(kStrongMode));
-  }
-  FunctionLiteral* function() const { return function_; }
-  Scope* scope() const { return 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_; }
-  Handle<Script> script() const { return script_; }
-  void set_script(Handle<Script> script) { script_ = script; }
   CodeStub* code_stub() const { return code_stub_; }
-  v8::Extension* extension() const { return extension_; }
-  ScriptData** cached_data() const { return cached_data_; }
-  ScriptCompiler::CompileOptions compile_options() const {
-    return compile_options_;
-  }
-  ScriptCompiler::ExternalSourceStream* source_stream() const {
-    return source_stream_;
-  }
-  ScriptCompiler::StreamedSource::Encoding source_stream_encoding() const {
-    return source_stream_encoding_;
-  }
-  Handle<Context> context() const { return context_; }
   BailoutId osr_ast_id() const { return osr_ast_id_; }
   Handle<Code> unoptimized_code() const { return unoptimized_code_; }
   int opt_count() const { return opt_count_; }
   int num_parameters() const;
   int num_heap_slots() const;
   Code::Flags flags() const;
-
-  void MarkAsEval() {
-    DCHECK(!is_lazy());
-    SetFlag(kEval);
-  }
-
-  void MarkAsGlobal() {
-    DCHECK(!is_lazy());
-    SetFlag(kGlobal);
-  }
-
-  void MarkAsModule() {
-    DCHECK(!is_lazy());
-    SetFlag(kModule);
-  }
+  bool has_scope() const { return scope() != nullptr; }
 
   void set_parameter_count(int parameter_count) {
     DCHECK(IsStub());
     parameter_count_ = parameter_count;
   }
 
-  void set_this_has_uses(bool has_no_uses) {
-    SetFlag(kThisHasUses, has_no_uses);
-  }
-
-  bool this_has_uses() { return GetFlag(kThisHasUses); }
-
-  void SetLanguageMode(LanguageMode language_mode) {
-    STATIC_ASSERT(LANGUAGE_END == 3);
-    SetFlag(kStrictMode, language_mode & STRICT_BIT);
-    SetFlag(kStrongMode, language_mode & STRONG_BIT);
-  }
-
-  void MarkAsNative() { SetFlag(kNative); }
-
-  bool is_native() const { return GetFlag(kNative); }
+  bool is_tracking_positions() const { return track_positions_; }
 
   bool is_calling() const {
     return GetFlag(kDeferredCalling) || GetFlag(kNonDeferredCalling);
@@ -286,17 +210,25 @@ class CompilationInfo {
 
   bool is_context_specializing() const { return GetFlag(kContextSpecializing); }
 
+  void MarkAsTypeFeedbackEnabled() { SetFlag(kTypeFeedbackEnabled); }
+
+  bool is_type_feedback_enabled() const {
+    return GetFlag(kTypeFeedbackEnabled);
+  }
+
   void MarkAsInliningEnabled() { SetFlag(kInliningEnabled); }
 
   bool is_inlining_enabled() const { return GetFlag(kInliningEnabled); }
 
-  void MarkAsTypingEnabled() { SetFlag(kTypingEnabled); }
+  void MarkAsBuiltinInliningEnabled() { SetFlag(kBuiltinInliningEnabled); }
 
-  bool is_typing_enabled() const { return GetFlag(kTypingEnabled); }
+  bool is_builtin_inlining_enabled() const {
+    return GetFlag(kBuiltinInliningEnabled);
+  }
 
-  void MarkAsToplevel() { SetFlag(kToplevel); }
+  void MarkAsTypingEnabled() { SetFlag(kTypingEnabled); }
 
-  bool is_toplevel() const { return GetFlag(kToplevel); }
+  bool is_typing_enabled() const { return GetFlag(kTypingEnabled); }
 
   void MarkAsSplittingEnabled() { SetFlag(kSplittingEnabled); }
 
@@ -307,46 +239,11 @@ class CompilationInfo {
            !is_debug();
   }
 
-  void SetParseRestriction(ParseRestriction restriction) {
-    SetFlag(kParseRestriction, restriction != NO_PARSE_RESTRICTION);
-  }
-
-  ParseRestriction parse_restriction() const {
-    return GetFlag(kParseRestriction) ? ONLY_SINGLE_FUNCTION_LITERAL
-                                      : NO_PARSE_RESTRICTION;
-  }
-
-  void SetFunction(FunctionLiteral* literal) {
-    DCHECK(function_ == NULL);
-    function_ = literal;
-  }
-  void PrepareForCompilation(Scope* scope);
-  void SetScriptScope(Scope* script_scope) {
-    DCHECK(script_scope_ == NULL);
-    script_scope_ = script_scope;
-  }
   void EnsureFeedbackVector();
   Handle<TypeFeedbackVector> feedback_vector() const {
     return feedback_vector_;
   }
   void SetCode(Handle<Code> code) { code_ = code; }
-  void SetExtension(v8::Extension* extension) {
-    DCHECK(!is_lazy());
-    extension_ = extension;
-  }
-  void SetCachedData(ScriptData** cached_data,
-                     ScriptCompiler::CompileOptions compile_options) {
-    compile_options_ = compile_options;
-    if (compile_options == ScriptCompiler::kNoCompileOptions) {
-      cached_data_ = NULL;
-    } else {
-      DCHECK(!is_lazy());
-      cached_data_ = cached_data;
-    }
-  }
-  void SetContext(Handle<Context> context) {
-    context_ = context;
-  }
 
   void MarkCompilingForDebugging() { SetFlag(kCompilingForDebugging); }
   bool IsCompilingForDebugging() { return GetFlag(kCompilingForDebugging); }
@@ -373,13 +270,18 @@ class CompilationInfo {
   bool IsOptimizable() const { return mode_ == BASE; }
   bool IsStub() const { return mode_ == STUB; }
   void SetOptimizing(BailoutId osr_ast_id, Handle<Code> unoptimized) {
-    DCHECK(!shared_info_.is_null());
+    DCHECK(!shared_info().is_null());
     SetMode(OPTIMIZE);
     osr_ast_id_ = osr_ast_id;
     unoptimized_code_ = unoptimized;
     optimization_id_ = isolate()->NextOptimizationId();
   }
 
+  void SetStub(CodeStub* code_stub) {
+    SetMode(STUB);
+    code_stub_ = code_stub;
+  }
+
   // Deoptimization support.
   bool HasDeoptimizationSupport() const {
     return GetFlag(kDeoptimizationSupport);
@@ -409,12 +311,8 @@ class CompilationInfo {
 
   void RollbackDependencies();
 
-  void SaveHandles() {
-    SaveHandle(&closure_);
-    SaveHandle(&shared_info_);
-    SaveHandle(&context_);
-    SaveHandle(&script_);
-    SaveHandle(&unoptimized_code_);
+  void ReopenHandlesInNewHandleScope() {
+    unoptimized_code_ = Handle<Code>(*unoptimized_code_);
   }
 
   void AbortOptimization(BailoutReason reason) {
@@ -454,14 +352,16 @@ class CompilationInfo {
     return result;
   }
 
-  List<InlinedFunctionInfo>* inlined_function_infos() {
-    return inlined_function_infos_;
+  int start_position_for(uint32_t inlining_id) {
+    return inlined_function_infos_.at(inlining_id).start_position;
   }
-  List<int>* inlining_id_to_function_id() {
-    return inlining_id_to_function_id_;
+  const std::vector<InlinedFunctionInfo>& inlined_function_infos() {
+    return inlined_function_infos_;
   }
+
+  void LogDeoptCallPosition(int pc_offset, int inlining_id);
   int TraceInlinedFunction(Handle<SharedFunctionInfo> shared,
-                           SourcePosition position);
+                           SourcePosition position, int pareint_id);
 
   Handle<Foreign> object_wrapper() {
     if (object_wrapper_.is_null()) {
@@ -482,18 +382,11 @@ class CompilationInfo {
   }
 
   bool HasSameOsrEntry(Handle<JSFunction> function, BailoutId osr_ast_id) {
-    return osr_ast_id_ == osr_ast_id && function.is_identical_to(closure_);
+    return osr_ast_id_ == osr_ast_id && function.is_identical_to(closure());
   }
 
   int optimization_id() const { return optimization_id_; }
 
-  AstValueFactory* ast_value_factory() const { return ast_value_factory_; }
-  void SetAstValueFactory(AstValueFactory* ast_value_factory,
-                          bool owned = true) {
-    ast_value_factory_ = ast_value_factory;
-    ast_value_factory_owned_ = owned;
-  }
-
   int osr_expr_stack_height() { return osr_expr_stack_height_; }
   void set_osr_expr_stack_height(int height) {
     DCHECK(height >= 0);
@@ -507,16 +400,15 @@ class CompilationInfo {
   bool is_simple_parameter_list();
 
  protected:
-  CompilationInfo(Handle<SharedFunctionInfo> shared_info,
-                  Zone* zone);
-  CompilationInfo(ScriptCompiler::ExternalSourceStream* source_stream,
-                  ScriptCompiler::StreamedSource::Encoding encoding,
-                  Isolate* isolate, Zone* zone);
+  ParseInfo* parse_info_;
 
+  void DisableFutureOptimization() {
+    if (GetFlag(kDisableFutureOptimization) && has_shared_info()) {
+      shared_info()->DisableOptimization(bailout_reason());
+    }
+  }
 
  private:
-  Isolate* isolate_;
-
   // Compilation mode.
   // BASE is generated by the full codegen, optionally prepared for bailouts.
   // OPTIMIZE is optimized code generated by the Hydrogen-based backend.
@@ -529,7 +421,10 @@ class CompilationInfo {
     STUB
   };
 
-  void Initialize(Isolate* isolate, Mode mode, Zone* zone);
+  CompilationInfo(ParseInfo* parse_info, CodeStub* code_stub, Mode mode,
+                  Isolate* isolate, Zone* zone);
+
+  Isolate* isolate_;
 
   void SetMode(Mode mode) {
     mode_ = mode;
@@ -545,35 +440,11 @@ class CompilationInfo {
 
   unsigned flags_;
 
-  // Fields filled in by the compilation pipeline.
-  // AST filled in by the parser.
-  FunctionLiteral* function_;
-  // The scope of the function literal as a convenience.  Set to indicate
-  // that scopes have been analyzed.
-  Scope* scope_;
-  // The script scope provided as a convenience.
-  Scope* script_scope_;
   // For compiled stubs, the stub object
   CodeStub* code_stub_;
   // The compiled code.
   Handle<Code> code_;
 
-  // Possible initial inputs to the compilation process.
-  Handle<JSFunction> closure_;
-  Handle<SharedFunctionInfo> shared_info_;
-  Handle<Script> script_;
-  ScriptCompiler::ExternalSourceStream* source_stream_;  // Not owned.
-  ScriptCompiler::StreamedSource::Encoding source_stream_encoding_;
-
-  // Fields possibly needed for eager compilation, NULL by default.
-  v8::Extension* extension_;
-  ScriptData** cached_data_;
-  ScriptCompiler::CompileOptions compile_options_;
-
-  // 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_;
-
   // Used by codegen, ultimately kept rooted by the SharedFunctionInfo.
   Handle<TypeFeedbackVector> feedback_vector_;
 
@@ -593,21 +464,13 @@ class CompilationInfo {
 
   ZoneList<Handle<HeapObject> >* dependencies_[DependentCode::kGroupCount];
 
-  template<typename T>
-  void SaveHandle(Handle<T> *object) {
-    if (!object->is_null()) {
-      Handle<T> handle(*(*object));
-      *object = handle;
-    }
-  }
-
   BailoutReason bailout_reason_;
 
   int prologue_offset_;
 
   List<OffsetRange>* no_frame_ranges_;
-  List<InlinedFunctionInfo>* inlined_function_infos_;
-  List<int>* inlining_id_to_function_id_;
+  std::vector<InlinedFunctionInfo> inlined_function_infos_;
+  bool track_positions_;
 
   // A copy of shared_info()->opt_count() to avoid handle deref
   // during graph optimization.
@@ -620,9 +483,6 @@ class CompilationInfo {
 
   int optimization_id_;
 
-  AstValueFactory* ast_value_factory_;
-  bool ast_value_factory_owned_;
-
   // This flag is used by the main thread to track whether this compilation
   // should be abandoned due to dependency change.
   bool aborted_due_to_dependency_change_;
@@ -633,35 +493,6 @@ class CompilationInfo {
 };
 
 
-// Exactly like a CompilationInfo, except also creates and enters a
-// Zone on construction and deallocates it on exit.
-class CompilationInfoWithZone: public CompilationInfo {
- public:
-  explicit CompilationInfoWithZone(Handle<Script> script)
-      : CompilationInfo(script, &zone_) {}
-  explicit CompilationInfoWithZone(Handle<SharedFunctionInfo> shared_info)
-      : CompilationInfo(shared_info, &zone_) {}
-  explicit CompilationInfoWithZone(Handle<JSFunction> closure)
-      : CompilationInfo(closure, &zone_) {}
-  CompilationInfoWithZone(CodeStub* stub, Isolate* isolate)
-      : CompilationInfo(stub, isolate, &zone_) {}
-  CompilationInfoWithZone(ScriptCompiler::ExternalSourceStream* stream,
-                          ScriptCompiler::StreamedSource::Encoding encoding,
-                          Isolate* isolate)
-      : CompilationInfo(stream, encoding, isolate, &zone_) {}
-
-  // Virtual destructor because a CompilationInfoWithZone has to exit the
-  // zone scope and get rid of dependent maps even when the destructor is
-  // called when cast as a CompilationInfo.
-  virtual ~CompilationInfoWithZone() {
-    RollbackDependencies();
-  }
-
- private:
-  Zone zone_;
-};
-
-
 // A wrapper around a CompilationInfo that detaches the Handles from
 // the underlying DeferredHandleScope and stores them in info_ on
 // destruction.
@@ -786,9 +617,9 @@ class Compiler : public AllStatic {
       Handle<JSFunction> function);
 
   // Parser::Parse, then Compiler::Analyze.
-  static bool ParseAndAnalyze(CompilationInfo* info);
+  static bool ParseAndAnalyze(ParseInfo* info);
   // Rewrite, analyze scopes, and renumber.
-  static bool Analyze(CompilationInfo* info);
+  static bool Analyze(ParseInfo* info);
   // Adds deoptimization support, requires ParseAndAnalyze.
   static bool EnsureDeoptimizationSupport(CompilationInfo* info);
 
@@ -807,11 +638,13 @@ class Compiler : public AllStatic {
   static Handle<SharedFunctionInfo> CompileScript(
       Handle<String> source, Handle<Object> script_name, int line_offset,
       int column_offset, bool is_debugger_script, bool is_shared_cross_origin,
-      Handle<Context> context, v8::Extension* extension,
-      ScriptData** cached_data, ScriptCompiler::CompileOptions compile_options,
+      Handle<Object> source_map_url, Handle<Context> context,
+      v8::Extension* extension, ScriptData** cached_data,
+      ScriptCompiler::CompileOptions compile_options,
       NativesFlag is_natives_code, bool is_module);
 
-  static Handle<SharedFunctionInfo> CompileStreamedScript(CompilationInfo* info,
+  static Handle<SharedFunctionInfo> CompileStreamedScript(Handle<Script> script,
+                                                          ParseInfo* info,
                                                           int source_length);
 
   // Create a shared function info object (the code may be lazily compiled).
@@ -834,8 +667,9 @@ class Compiler : public AllStatic {
   // On failure, return the empty handle.
   static Handle<Code> GetConcurrentlyOptimizedCode(OptimizedCompileJob* job);
 
+  // TODO(titzer): move this method out of the compiler.
   static bool DebuggerWantsEagerCompilation(
-      CompilationInfo* info, bool allow_lazy_without_ctx = false);
+      Isolate* isolate, bool allow_lazy_without_ctx = false);
 };
 
 
index 8c8e530..c69f22c 100644 (file)
@@ -61,7 +61,8 @@ FieldAccess AccessBuilder::ForMapInstanceType() {
 // static
 FieldAccess AccessBuilder::ForStringLength() {
   return {kTaggedBase, String::kLengthOffset, Handle<Name>(),
-          Type::SignedSmall(), kMachAnyTagged};
+          Type::Intersect(Type::UnsignedSmall(), Type::TaggedSigned()),
+          kMachAnyTagged};
 }
 
 
@@ -82,6 +83,12 @@ FieldAccess AccessBuilder::ForContextSlot(size_t index) {
 
 
 // static
+FieldAccess AccessBuilder::ForStatsCounter() {
+  return {kUntaggedBase, 0, MaybeHandle<Name>(), Type::Signed32(), kMachInt32};
+}
+
+
+// static
 ElementAccess AccessBuilder::ForFixedArrayElement() {
   return {kTaggedBase, FixedArray::kHeaderSize, Type::Any(), kMachAnyTagged};
 }
@@ -115,6 +122,21 @@ ElementAccess AccessBuilder::ForTypedArrayElement(ExternalArrayType type,
   return {kUntaggedBase, 0, Type::None(), kMachNone};
 }
 
+
+// static
+ElementAccess AccessBuilder::ForSeqStringChar(String::Encoding encoding) {
+  switch (encoding) {
+    case String::ONE_BYTE_ENCODING:
+      return {kTaggedBase, SeqString::kHeaderSize, Type::Unsigned32(),
+              kMachUint8};
+    case String::TWO_BYTE_ENCODING:
+      return {kTaggedBase, SeqString::kHeaderSize, Type::Unsigned32(),
+              kMachUint16};
+  }
+  UNREACHABLE();
+  return {kUntaggedBase, 0, Type::None(), kMachNone};
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index d6385e4..ddbad8c 100644 (file)
@@ -12,7 +12,7 @@ namespace internal {
 namespace compiler {
 
 // This access builder provides a set of static methods constructing commonly
-// used FieldAccess and ElementAccess descriptors. These descriptors server as
+// used FieldAccess and ElementAccess descriptors. These descriptors serve as
 // parameters to simplified load/store operators.
 class AccessBuilder FINAL : public AllStatic {
  public:
@@ -46,6 +46,9 @@ class AccessBuilder FINAL : public AllStatic {
   // Provides access Context slots.
   static FieldAccess ForContextSlot(size_t index);
 
+  // Provides access to the backing store of a StatsCounter.
+  static FieldAccess ForStatsCounter();
+
   // Provides access to FixedArray elements.
   static ElementAccess ForFixedArrayElement();
 
@@ -53,6 +56,9 @@ class AccessBuilder FINAL : public AllStatic {
   static ElementAccess ForTypedArrayElement(ExternalArrayType type,
                                             bool is_external);
 
+  // Provides access to the charaters of sequential strings.
+  static ElementAccess ForSeqStringChar(String::Encoding encoding);
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(AccessBuilder);
 };
index b055a68..ed4a218 100644 (file)
@@ -4,16 +4,16 @@
 
 #include "src/compiler/all-nodes.h"
 
+#include "src/compiler/graph.h"
+
 namespace v8 {
 namespace internal {
 namespace compiler {
 
 AllNodes::AllNodes(Zone* local_zone, const Graph* graph)
-    : live(local_zone),
-      gray(local_zone),
-      state(graph->NodeCount(), AllNodes::kDead, local_zone) {
+    : live(local_zone), is_live(graph->NodeCount(), false, local_zone) {
   Node* end = graph->end();
-  state[end->id()] = AllNodes::kLive;
+  is_live[end->id()] = true;
   live.push_back(end);
   // Find all live nodes reachable from end.
   for (size_t i = 0; i < live.size(); i++) {
@@ -26,23 +26,14 @@ AllNodes::AllNodes(Zone* local_zone, const Graph* graph)
         // TODO(titzer): print a warning.
         continue;
       }
-      if (state[input->id()] != AllNodes::kLive) {
+      if (!is_live[input->id()]) {
+        is_live[input->id()] = true;
         live.push_back(input);
-        state[input->id()] = AllNodes::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()] == AllNodes::kDead) {
-        gray.push_back(use);
-        state[use->id()] = AllNodes::kGray;
-      }
-    }
-  }
-}
 }
-}
-}  // namespace v8::internal::compiler
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
index e6a83ef..700f007 100644 (file)
@@ -5,7 +5,6 @@
 #ifndef V8_COMPILER_ALL_NODES_H_
 #define V8_COMPILER_ALL_NODES_H_
 
-#include "src/compiler/graph.h"
 #include "src/compiler/node.h"
 #include "src/zone-containers.h"
 
@@ -17,25 +16,23 @@ namespace compiler {
 // from end.
 class AllNodes {
  public:
-  // Constructor. Traverses the graph and builds the {live} and {gray} sets.
+  // Constructor. Traverses the graph and builds the {live} sets.
   AllNodes(Zone* local_zone, const Graph* graph);
 
   bool IsLive(Node* node) {
-    return node != nullptr && node->id() < static_cast<int>(state.size()) &&
-           state[node->id()] == kLive;
+    if (!node) return false;
+    size_t id = node->id();
+    return id < is_live.size() && is_live[id];
   }
 
   NodeVector live;  // Nodes reachable from end.
-  NodeVector gray;  // Nodes themselves not reachable from end, but that
-                    // appear in use lists of live nodes.
 
  private:
-  enum State { kDead, kGray, kLive };
-
-  ZoneVector<State> state;
+  BoolVector is_live;
 };
-}
-}
-}  // namespace v8::internal::compiler
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_ALL_NODES_H_
index 1ff7ea3..79767a8 100644 (file)
@@ -26,11 +26,11 @@ class ArmOperandConverter FINAL : public InstructionOperandConverter {
   ArmOperandConverter(CodeGenerator* gen, Instruction* instr)
       : InstructionOperandConverter(gen, instr) {}
 
-  SwVfpRegister OutputFloat32Register(int index = 0) {
+  SwVfpRegister OutputFloat32Register(size_t index = 0) {
     return ToFloat32Register(instr_->OutputAt(index));
   }
 
-  SwVfpRegister InputFloat32Register(int index) {
+  SwVfpRegister InputFloat32Register(size_t index) {
     return ToFloat32Register(instr_->InputAt(index));
   }
 
@@ -38,11 +38,11 @@ class ArmOperandConverter FINAL : public InstructionOperandConverter {
     return ToFloat64Register(op).low();
   }
 
-  LowDwVfpRegister OutputFloat64Register(int index = 0) {
+  LowDwVfpRegister OutputFloat64Register(size_t index = 0) {
     return ToFloat64Register(instr_->OutputAt(index));
   }
 
-  LowDwVfpRegister InputFloat64Register(int index) {
+  LowDwVfpRegister InputFloat64Register(size_t index) {
     return ToFloat64Register(instr_->InputAt(index));
   }
 
@@ -62,7 +62,7 @@ class ArmOperandConverter FINAL : public InstructionOperandConverter {
     return LeaveCC;
   }
 
-  Operand InputImmediate(int index) {
+  Operand InputImmediate(size_t index) {
     Constant constant = ToConstant(instr_->InputAt(index));
     switch (constant.type()) {
       case Constant::kInt32:
@@ -83,8 +83,8 @@ class ArmOperandConverter FINAL : public InstructionOperandConverter {
     return Operand::Zero();
   }
 
-  Operand InputOperand2(int first_index) {
-    const int index = first_index;
+  Operand InputOperand2(size_t first_index) {
+    const size_t index = first_index;
     switch (AddressingModeField::decode(instr_->opcode())) {
       case kMode_None:
       case kMode_Offset_RI:
@@ -115,8 +115,8 @@ class ArmOperandConverter FINAL : public InstructionOperandConverter {
     return Operand::Zero();
   }
 
-  MemOperand InputOffset(int* first_index) {
-    const int index = *first_index;
+  MemOperand InputOffset(size_t* first_index) {
+    const size_t index = *first_index;
     switch (AddressingModeField::decode(instr_->opcode())) {
       case kMode_None:
       case kMode_Operand2_I:
@@ -141,7 +141,7 @@ class ArmOperandConverter FINAL : public InstructionOperandConverter {
     return MemOperand(r0);
   }
 
-  MemOperand InputOffset(int first_index = 0) {
+  MemOperand InputOffset(size_t first_index = 0) {
     return InputOffset(&first_index);
   }
 
@@ -313,7 +313,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
                Operand(Code::kHeaderSize - kHeapObjectTag));
         __ Call(ip);
       }
-      AddSafepointAndDeopt(instr);
+      RecordCallPosition(instr);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
@@ -328,7 +328,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       }
       __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
       __ Call(ip);
-      AddSafepointAndDeopt(instr);
+      RecordCallPosition(instr);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
@@ -348,6 +348,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       // don't emit code for nops.
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
+    case kArchDeoptimize: {
+      int deopt_state_id =
+          BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
+      AssembleDeoptimizerCall(deopt_state_id, Deoptimizer::EAGER);
+      break;
+    }
     case kArchRet:
       AssembleReturn();
       DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -483,6 +489,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
                i.InputInt32(2));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
+    case kArmClz:
+      __ clz(i.OutputRegister(), i.InputRegister(0));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
     case kArmCmp:
       __ cmp(i.InputRegister(0), i.InputOperand2(1));
       DCHECK_EQ(SetCC, i.OutputSBit());
@@ -558,16 +568,16 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArmVsqrtF64:
       __ vsqrt(i.OutputFloat64Register(), i.InputFloat64Register(0));
       break;
-    case kArmVfloorF64:
+    case kArmVrintmF64:
       __ vrintm(i.OutputFloat64Register(), i.InputFloat64Register(0));
       break;
-    case kArmVceilF64:
+    case kArmVrintpF64:
       __ vrintp(i.OutputFloat64Register(), i.InputFloat64Register(0));
       break;
-    case kArmVroundTruncateF64:
+    case kArmVrintzF64:
       __ vrintz(i.OutputFloat64Register(), i.InputFloat64Register(0));
       break;
-    case kArmVroundTiesAwayF64:
+    case kArmVrintaF64:
       __ vrinta(i.OutputFloat64Register(), i.InputFloat64Register(0));
       break;
     case kArmVnegF64:
@@ -611,6 +621,27 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
+    case kArmVmovLowU32F64:
+      __ VmovLow(i.OutputRegister(), i.InputFloat64Register(0));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmVmovLowF64U32:
+      __ VmovLow(i.OutputFloat64Register(), i.InputRegister(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmVmovHighU32F64:
+      __ VmovHigh(i.OutputRegister(), i.InputFloat64Register(0));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmVmovHighF64U32:
+      __ VmovHigh(i.OutputFloat64Register(), i.InputRegister(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmVmovF64U32U32:
+      __ vmov(i.OutputFloat64Register(), i.InputRegister(0),
+              i.InputRegister(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
     case kArmLdrb:
       __ ldrb(i.OutputRegister(), i.InputOffset());
       DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -620,7 +651,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmStrb: {
-      int index = 0;
+      size_t index = 0;
       MemOperand operand = i.InputOffset(&index);
       __ strb(i.InputRegister(index), operand);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -633,7 +664,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ ldrsh(i.OutputRegister(), i.InputOffset());
       break;
     case kArmStrh: {
-      int index = 0;
+      size_t index = 0;
       MemOperand operand = i.InputOffset(&index);
       __ strh(i.InputRegister(index), operand);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -643,7 +674,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ ldr(i.OutputRegister(), i.InputOffset());
       break;
     case kArmStr: {
-      int index = 0;
+      size_t index = 0;
       MemOperand operand = i.InputOffset(&index);
       __ str(i.InputRegister(index), operand);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -655,7 +686,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       break;
     }
     case kArmVstrF32: {
-      int index = 0;
+      size_t index = 0;
       MemOperand operand = i.InputOffset(&index);
       __ vstr(i.InputFloat32Register(index), operand);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -666,7 +697,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVstrF64: {
-      int index = 0;
+      size_t index = 0;
       MemOperand operand = i.InputOffset(&index);
       __ vstr(i.InputFloat64Register(index), operand);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -740,7 +771,7 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
 }
 
 
-void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+void CodeGenerator::AssembleArchJump(RpoNumber target) {
   if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
 }
 
@@ -775,6 +806,7 @@ void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
   ArmOperandConverter i(this, instr);
   Register input = i.InputRegister(0);
   size_t const case_count = instr->InputCount() - 2;
+  __ CheckConstPool(true, true);
   __ cmp(input, Operand(case_count));
   __ BlockConstPoolFor(case_count + 2);
   __ ldr(pc, MemOperand(pc, input, LSL, 2), lo);
@@ -785,9 +817,10 @@ void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
 }
 
 
-void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
+void CodeGenerator::AssembleDeoptimizerCall(
+    int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
-      isolate(), deoptimization_id, Deoptimizer::LAZY);
+      isolate(), deoptimization_id, bailout_type);
   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
 }
 
@@ -839,6 +872,8 @@ void CodeGenerator::AssemblePrologue() {
     // remaining stack slots.
     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
     osr_pc_offset_ = __ pc_offset();
+    // TODO(titzer): cannot address target function == local #-1
+    __ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
     DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
     stack_slots -= frame()->GetOsrStackSlotCount();
   }
index ecd0b2d..404b1e0 100644 (file)
@@ -15,6 +15,7 @@ namespace compiler {
   V(ArmAdd)                        \
   V(ArmAnd)                        \
   V(ArmBic)                        \
+  V(ArmClz)                        \
   V(ArmCmp)                        \
   V(ArmCmn)                        \
   V(ArmTst)                        \
@@ -53,16 +54,21 @@ namespace compiler {
   V(ArmVmodF64)                    \
   V(ArmVnegF64)                    \
   V(ArmVsqrtF64)                   \
-  V(ArmVfloorF64)                  \
-  V(ArmVceilF64)                   \
-  V(ArmVroundTruncateF64)          \
-  V(ArmVroundTiesAwayF64)          \
+  V(ArmVrintmF64)                  \
+  V(ArmVrintpF64)                  \
+  V(ArmVrintzF64)                  \
+  V(ArmVrintaF64)                  \
   V(ArmVcvtF32F64)                 \
   V(ArmVcvtF64F32)                 \
   V(ArmVcvtF64S32)                 \
   V(ArmVcvtF64U32)                 \
   V(ArmVcvtS32F64)                 \
   V(ArmVcvtU32F64)                 \
+  V(ArmVmovLowU32F64)              \
+  V(ArmVmovLowF64U32)              \
+  V(ArmVmovHighU32F64)             \
+  V(ArmVmovHighF64U32)             \
+  V(ArmVmovF64U32U32)              \
   V(ArmVldrF32)                    \
   V(ArmVstrF32)                    \
   V(ArmVldrF64)                    \
index 47511a1..276b810 100644 (file)
@@ -239,9 +239,8 @@ void VisitBinop(InstructionSelector* selector, Node* node,
   DCHECK_GE(arraysize(outputs), output_count);
   DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
 
-  Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
-                                      outputs, input_count, inputs);
-  if (cont->IsBranch()) instr->MarkAsControl();
+  selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
+                 inputs);
 }
 
 
@@ -579,9 +578,8 @@ void VisitShift(InstructionSelector* selector, Node* node,
   DCHECK_GE(arraysize(outputs), output_count);
   DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
 
-  Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
-                                      outputs, input_count, inputs);
-  if (cont->IsBranch()) instr->MarkAsControl();
+  selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
+                 inputs);
 }
 
 
@@ -645,6 +643,12 @@ void InstructionSelector::VisitWord32Ror(Node* node) {
 }
 
 
+void InstructionSelector::VisitWord32Clz(Node* node) {
+  ArmOperandGenerator g(this);
+  Emit(kArmClz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitInt32Add(Node* node) {
   ArmOperandGenerator g(this);
   Int32BinopMatcher m(node);
@@ -956,6 +960,18 @@ void InstructionSelector::VisitFloat64Sub(Node* node) {
   ArmOperandGenerator g(this);
   Float64BinopMatcher m(node);
   if (m.left().IsMinusZero()) {
+    if (m.right().IsFloat64RoundDown() &&
+        CanCover(m.node(), m.right().node())) {
+      if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
+          CanCover(m.right().node(), m.right().InputAt(0))) {
+        Float64BinopMatcher mright0(m.right().InputAt(0));
+        if (mright0.left().IsMinusZero()) {
+          Emit(kArmVrintpF64, g.DefineAsRegister(node),
+               g.UseRegister(mright0.right().node()));
+          return;
+        }
+      }
+    }
     Emit(kArmVnegF64, g.DefineAsRegister(node),
          g.UseRegister(m.right().node()));
     return;
@@ -988,37 +1004,34 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64Max(Node* node) { UNREACHABLE(); }
+
+
+void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); }
+
+
 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
   ArmOperandGenerator g(this);
   Emit(kArmVsqrtF64, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
 }
 
 
-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::VisitFloat64RoundDown(Node* node) {
+  VisitRRFloat64(this, kArmVrintmF64, node);
 }
 
 
 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
-  DCHECK(CpuFeatures::IsSupported(ARMv8));
-  VisitRRFloat64(this, kArmVroundTruncateF64, node);
+  VisitRRFloat64(this, kArmVrintzF64, node);
 }
 
 
 void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
-  DCHECK(CpuFeatures::IsSupported(ARMv8));
-  VisitRRFloat64(this, kArmVroundTiesAwayF64, node);
+  VisitRRFloat64(this, kArmVrintaF64, node);
 }
 
 
-void InstructionSelector::VisitCall(Node* node) {
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
   ArmOperandGenerator g(this);
   const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
 
@@ -1043,6 +1056,13 @@ void InstructionSelector::VisitCall(Node* node) {
     Emit(kArmPush, g.NoOutput(), g.UseRegister(*i));
   }
 
+  // Pass label of exception handler block.
+  CallDescriptor::Flags flags = descriptor->flags();
+  if (handler != nullptr) {
+    flags |= CallDescriptor::kHasExceptionHandler;
+    buffer.instruction_args.push_back(g.Label(handler));
+  }
+
   // Select the appropriate opcode based on the call type.
   InstructionCode opcode;
   switch (descriptor->kind()) {
@@ -1057,7 +1077,7 @@ void InstructionSelector::VisitCall(Node* node) {
       UNREACHABLE();
       return;
   }
-  opcode |= MiscField::encode(descriptor->flags());
+  opcode |= MiscField::encode(flags);
 
   // Emit the call instruction.
   InstructionOperand* first_output =
@@ -1081,8 +1101,7 @@ void VisitFloat64Compare(InstructionSelector* selector, Node* node,
   if (cont->IsBranch()) {
     selector->Emit(cont->Encode(kArmVcmpF64), g.NoOutput(),
                    g.UseRegister(m.left().node()), rhs,
-                   g.Label(cont->true_block()),
-                   g.Label(cont->false_block()))->MarkAsControl();
+                   g.Label(cont->true_block()), g.Label(cont->false_block()));
   } else {
     DCHECK(cont->IsSet());
     selector->Emit(cont->Encode(kArmVcmpF64),
@@ -1129,9 +1148,8 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
   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();
+  selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
+                 inputs);
 }
 
 
@@ -1236,8 +1254,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
   InstructionOperand const value_operand = g.UseRegister(value);
   if (cont->IsBranch()) {
     selector->Emit(opcode, g.NoOutput(), value_operand, value_operand,
-                   g.Label(cont->true_block()),
-                   g.Label(cont->false_block()))->MarkAsControl();
+                   g.Label(cont->true_block()), g.Label(cont->false_block()));
   } else {
     selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
                    value_operand);
@@ -1254,64 +1271,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
 }
 
 
-void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
-                                      BasicBlock** case_branches,
-                                      int32_t* case_values, size_t case_count,
-                                      int32_t min_value, int32_t max_value) {
+void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
   ArmOperandGenerator g(this);
   InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
-  InstructionOperand default_operand = g.Label(default_branch);
 
-  // Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value}
-  // is 2^31-1, so don't assume that it's non-zero below.
-  size_t value_range =
-      1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
-
-  // Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
-  // instruction.
-  size_t table_space_cost = 4 + value_range;
+  // Emit either ArchTableSwitch or ArchLookupSwitch.
+  size_t table_space_cost = 4 + sw.value_range;
   size_t table_time_cost = 3;
-  size_t lookup_space_cost = 3 + 2 * case_count;
-  size_t lookup_time_cost = case_count;
-  if (case_count > 0 &&
+  size_t lookup_space_cost = 3 + 2 * sw.case_count;
+  size_t lookup_time_cost = sw.case_count;
+  if (sw.case_count > 0 &&
       table_space_cost + 3 * table_time_cost <=
           lookup_space_cost + 3 * lookup_time_cost &&
-      min_value > std::numeric_limits<int32_t>::min()) {
+      sw.min_value > std::numeric_limits<int32_t>::min()) {
     InstructionOperand index_operand = value_operand;
-    if (min_value) {
+    if (sw.min_value) {
       index_operand = g.TempRegister();
       Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_I),
-           index_operand, value_operand, g.TempImmediate(min_value));
-    }
-    size_t input_count = 2 + value_range;
-    auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
-    inputs[0] = index_operand;
-    std::fill(&inputs[1], &inputs[input_count], default_operand);
-    for (size_t index = 0; index < case_count; ++index) {
-      size_t value = case_values[index] - min_value;
-      BasicBlock* branch = case_branches[index];
-      DCHECK_LE(0u, value);
-      DCHECK_LT(value + 2, input_count);
-      inputs[value + 2] = g.Label(branch);
+           index_operand, value_operand, g.TempImmediate(sw.min_value));
     }
-    Emit(kArchTableSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
-        ->MarkAsControl();
-    return;
+    // Generate a table lookup.
+    return EmitTableSwitch(sw, index_operand);
   }
 
   // Generate a sequence of conditional jumps.
-  size_t input_count = 2 + case_count * 2;
-  auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
-  inputs[0] = value_operand;
-  inputs[1] = default_operand;
-  for (size_t index = 0; index < case_count; ++index) {
-    int32_t value = case_values[index];
-    BasicBlock* branch = case_branches[index];
-    inputs[index * 2 + 2 + 0] = g.TempImmediate(value);
-    inputs[index * 2 + 2 + 1] = g.Label(branch);
-  }
-  Emit(kArchLookupSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
-      ->MarkAsControl();
+  return EmitLookupSwitch(sw, value_operand);
 }
 
 
@@ -1387,6 +1371,52 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
+  ArmOperandGenerator g(this);
+  Emit(kArmVmovLowU32F64, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
+  ArmOperandGenerator g(this);
+  Emit(kArmVmovHighU32F64, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
+  ArmOperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 &&
+      CanCover(node, left)) {
+    left = left->InputAt(1);
+    Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(right),
+         g.UseRegister(left));
+    return;
+  }
+  Emit(kArmVmovLowF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
+       g.UseRegister(right));
+}
+
+
+void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
+  ArmOperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 &&
+      CanCover(node, left)) {
+    left = left->InputAt(1);
+    Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(left),
+         g.UseRegister(right));
+    return;
+  }
+  Emit(kArmVmovHighF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
+       g.UseRegister(right));
+}
+
+
 // static
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
@@ -1395,8 +1425,7 @@ InstructionSelector::SupportedMachineOperatorFlags() {
       MachineOperatorBuilder::kUint32DivIsSafe;
 
   if (CpuFeatures::IsSupported(ARMv8)) {
-    flags |= MachineOperatorBuilder::kFloat64Floor |
-             MachineOperatorBuilder::kFloat64Ceil |
+    flags |= MachineOperatorBuilder::kFloat64RoundDown |
              MachineOperatorBuilder::kFloat64RoundTruncate |
              MachineOperatorBuilder::kFloat64RoundTiesAway;
   }
index 57590d3..2b1faa2 100644 (file)
@@ -51,9 +51,10 @@ CallDescriptor* Linkage::GetRuntimeCallDescriptor(
 CallDescriptor* Linkage::GetStubCallDescriptor(
     Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
     int stack_parameter_count, CallDescriptor::Flags flags,
-    Operator::Properties properties) {
+    Operator::Properties properties, MachineType return_type) {
   return LH::GetStubCallDescriptor(isolate, zone, descriptor,
-                                   stack_parameter_count, flags, properties);
+                                   stack_parameter_count, flags, properties,
+                                   return_type);
 }
 
 
index 89c2ffb..1008ddc 100644 (file)
@@ -23,11 +23,11 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
   Arm64OperandConverter(CodeGenerator* gen, Instruction* instr)
       : InstructionOperandConverter(gen, instr) {}
 
-  DoubleRegister InputFloat32Register(int index) {
+  DoubleRegister InputFloat32Register(size_t index) {
     return InputDoubleRegister(index).S();
   }
 
-  DoubleRegister InputFloat64Register(int index) {
+  DoubleRegister InputFloat64Register(size_t index) {
     return InputDoubleRegister(index);
   }
 
@@ -35,21 +35,23 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
 
   DoubleRegister OutputFloat64Register() { return OutputDoubleRegister(); }
 
-  Register InputRegister32(int index) {
+  Register InputRegister32(size_t index) {
     return ToRegister(instr_->InputAt(index)).W();
   }
 
-  Register InputRegister64(int index) { return InputRegister(index); }
+  Register InputRegister64(size_t index) { return InputRegister(index); }
 
-  Operand InputImmediate(int index) {
+  Operand InputImmediate(size_t index) {
     return ToImmediate(instr_->InputAt(index));
   }
 
-  Operand InputOperand(int index) { return ToOperand(instr_->InputAt(index)); }
+  Operand InputOperand(size_t index) {
+    return ToOperand(instr_->InputAt(index));
+  }
 
-  Operand InputOperand64(int index) { return InputOperand(index); }
+  Operand InputOperand64(size_t index) { return InputOperand(index); }
 
-  Operand InputOperand32(int index) {
+  Operand InputOperand32(size_t index) {
     return ToOperand32(instr_->InputAt(index));
   }
 
@@ -57,7 +59,7 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
 
   Register OutputRegister32() { return ToRegister(instr_->Output()).W(); }
 
-  Operand InputOperand2_32(int index) {
+  Operand InputOperand2_32(size_t index) {
     switch (AddressingModeField::decode(instr_->opcode())) {
       case kMode_None:
         return InputOperand32(index);
@@ -69,6 +71,10 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
         return Operand(InputRegister32(index), ASR, InputInt5(index + 1));
       case kMode_Operand2_R_ROR_I:
         return Operand(InputRegister32(index), ROR, InputInt5(index + 1));
+      case kMode_Operand2_R_UXTB:
+        return Operand(InputRegister32(index), UXTB);
+      case kMode_Operand2_R_UXTH:
+        return Operand(InputRegister32(index), UXTH);
       case kMode_MRI:
       case kMode_MRR:
         break;
@@ -77,7 +83,7 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
     return Operand(-1);
   }
 
-  Operand InputOperand2_64(int index) {
+  Operand InputOperand2_64(size_t index) {
     switch (AddressingModeField::decode(instr_->opcode())) {
       case kMode_None:
         return InputOperand64(index);
@@ -89,6 +95,10 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
         return Operand(InputRegister64(index), ASR, InputInt6(index + 1));
       case kMode_Operand2_R_ROR_I:
         return Operand(InputRegister64(index), ROR, InputInt6(index + 1));
+      case kMode_Operand2_R_UXTB:
+        return Operand(InputRegister64(index), UXTB);
+      case kMode_Operand2_R_UXTH:
+        return Operand(InputRegister64(index), UXTH);
       case kMode_MRI:
       case kMode_MRR:
         break;
@@ -97,14 +107,16 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
     return Operand(-1);
   }
 
-  MemOperand MemoryOperand(int* first_index) {
-    const int index = *first_index;
+  MemOperand MemoryOperand(size_t* first_index) {
+    const size_t 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:
+      case kMode_Operand2_R_UXTB:
+      case kMode_Operand2_R_UXTH:
         break;
       case kMode_MRI:
         *first_index += 2;
@@ -117,7 +129,7 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
     return MemOperand(no_reg);
   }
 
-  MemOperand MemoryOperand(int first_index = 0) {
+  MemOperand MemoryOperand(size_t first_index = 0) {
     return MemoryOperand(&first_index);
   }
 
@@ -335,7 +347,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         __ Add(target, target, Code::kHeaderSize - kHeapObjectTag);
         __ Call(target);
       }
-      AddSafepointAndDeopt(instr);
+      RecordCallPosition(instr);
       break;
     }
     case kArchCallJSFunction: {
@@ -351,7 +363,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       }
       __ Ldr(x10, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
       __ Call(x10);
-      AddSafepointAndDeopt(instr);
+      RecordCallPosition(instr);
       break;
     }
     case kArchJmp:
@@ -366,6 +378,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArchNop:
       // don't emit code for nops.
       break;
+    case kArchDeoptimize: {
+      int deopt_state_id =
+          BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
+      AssembleDeoptimizerCall(deopt_state_id, Deoptimizer::EAGER);
+      break;
+    }
     case kArchRet:
       AssembleReturn();
       break;
@@ -375,17 +393,17 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArchTruncateDoubleToI:
       __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
       break;
-    case kArm64Float64Ceil:
-      __ Frintp(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
-      break;
-    case kArm64Float64Floor:
+    case kArm64Float64RoundDown:
       __ Frintm(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       break;
+    case kArm64Float64RoundTiesAway:
+      __ Frinta(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
+      break;
     case kArm64Float64RoundTruncate:
       __ Frintz(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       break;
-    case kArm64Float64RoundTiesAway:
-      __ Frinta(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
+    case kArm64Float64RoundUp:
+      __ Frintp(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       break;
     case kArm64Add:
       __ Add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
@@ -580,6 +598,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ Ubfx(i.OutputRegister32(), i.InputRegister32(0), i.InputInt8(1),
               i.InputInt8(2));
       break;
+    case kArm64Bfi:
+      __ Bfi(i.OutputRegister(), i.InputRegister(1), i.InputInt6(2),
+             i.InputInt6(3));
+      break;
     case kArm64TestAndBranch32:
     case kArm64TestAndBranch:
       // Pseudo instructions turned into tbz/tbnz in AssembleArchBranch.
@@ -588,27 +610,22 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       // Pseudo instruction turned into cbz/cbnz in AssembleArchBranch.
       break;
     case kArm64Claim: {
-      int words = MiscField::decode(instr->opcode());
-      __ Claim(words);
+      __ Claim(i.InputInt32(0));
       break;
     }
     case kArm64Poke: {
-      int slot = MiscField::decode(instr->opcode());
-      Operand operand(slot * kPointerSize);
+      Operand operand(i.InputInt32(1) * kPointerSize);
       __ Poke(i.InputRegister(0), operand);
       break;
     }
-    case kArm64PokePairZero: {
-      // TODO(dcarney): test slot offset and register order.
-      int slot = MiscField::decode(instr->opcode()) - 1;
-      __ PokePair(i.InputRegister(0), xzr, slot * kPointerSize);
-      break;
-    }
     case kArm64PokePair: {
-      int slot = MiscField::decode(instr->opcode()) - 1;
+      int slot = i.InputInt32(2) - 1;
       __ PokePair(i.InputRegister(1), i.InputRegister(0), slot * kPointerSize);
       break;
     }
+    case kArm64Clz32:
+      __ Clz(i.OutputRegister32(), i.InputRegister32(0));
+      break;
     case kArm64Cmp:
       __ Cmp(i.InputRegister(0), i.InputOperand(1));
       break;
@@ -685,6 +702,44 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArm64Uint32ToFloat64:
       __ Ucvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
       break;
+    case kArm64Float64ExtractLowWord32:
+      __ Fmov(i.OutputRegister32(), i.InputFloat32Register(0));
+      break;
+    case kArm64Float64ExtractHighWord32:
+      // TODO(arm64): This should use MOV (to general) when NEON is supported.
+      __ Fmov(i.OutputRegister(), i.InputFloat64Register(0));
+      __ Lsr(i.OutputRegister(), i.OutputRegister(), 32);
+      break;
+    case kArm64Float64InsertLowWord32: {
+      // TODO(arm64): This should use MOV (from general) when NEON is supported.
+      UseScratchRegisterScope scope(masm());
+      Register tmp = scope.AcquireX();
+      __ Fmov(tmp, i.InputFloat64Register(0));
+      __ Bfi(tmp, i.InputRegister(1), 0, 32);
+      __ Fmov(i.OutputFloat64Register(), tmp);
+      break;
+    }
+    case kArm64Float64InsertHighWord32: {
+      // TODO(arm64): This should use MOV (from general) when NEON is supported.
+      UseScratchRegisterScope scope(masm());
+      Register tmp = scope.AcquireX();
+      __ Fmov(tmp.W(), i.InputFloat32Register(0));
+      __ Bfi(tmp, i.InputRegister(1), 32, 32);
+      __ Fmov(i.OutputFloat64Register(), tmp);
+      break;
+    }
+    case kArm64Float64MoveU64: {
+      __ Fmov(i.OutputFloat64Register(), i.InputRegister(0));
+      break;
+    }
+    case kArm64Float64Max:
+      __ Fmax(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+              i.InputDoubleRegister(1));
+      break;
+    case kArm64Float64Min:
+      __ Fmin(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+              i.InputDoubleRegister(1));
+      break;
     case kArm64Ldrb:
       __ Ldrb(i.OutputRegister(), i.MemoryOperand());
       break;
@@ -787,7 +842,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       ASSEMBLE_CHECKED_STORE_FLOAT(64);
       break;
   }
-}
+}  // NOLINT(readability/fn_size)
 
 
 // Assemble branches after this instruction.
@@ -839,7 +894,7 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
 }
 
 
-void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+void CodeGenerator::AssembleArchJump(RpoNumber target) {
   if (!IsNextInAssemblyOrder(target)) __ B(GetLabel(target));
 }
 
@@ -890,9 +945,10 @@ void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
 }
 
 
-void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
+void CodeGenerator::AssembleDeoptimizerCall(
+    int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
-      isolate(), deoptimization_id, Deoptimizer::LAZY);
+      isolate(), deoptimization_id, bailout_type);
   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
 }
 
@@ -937,6 +993,8 @@ void CodeGenerator::AssemblePrologue() {
     // remaining stack slots.
     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
     osr_pc_offset_ = __ pc_offset();
+    // TODO(titzer): cannot address target function == local #-1
+    __ ldr(x1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
     DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
     stack_slots -= frame()->GetOsrStackSlotCount();
   }
index 863451f..31187f0 100644 (file)
@@ -18,6 +18,7 @@ namespace compiler {
   V(Arm64And32)                    \
   V(Arm64Bic)                      \
   V(Arm64Bic32)                    \
+  V(Arm64Clz32)                    \
   V(Arm64Cmp)                      \
   V(Arm64Cmp32)                    \
   V(Arm64Cmn)                      \
@@ -70,12 +71,12 @@ namespace compiler {
   V(Arm64Sxtw)                     \
   V(Arm64Ubfx)                     \
   V(Arm64Ubfx32)                   \
+  V(Arm64Bfi)                      \
   V(Arm64TestAndBranch32)          \
   V(Arm64TestAndBranch)            \
   V(Arm64CompareAndBranch32)       \
   V(Arm64Claim)                    \
   V(Arm64Poke)                     \
-  V(Arm64PokePairZero)             \
   V(Arm64PokePair)                 \
   V(Arm64Float64Cmp)               \
   V(Arm64Float64Add)               \
@@ -84,16 +85,23 @@ namespace compiler {
   V(Arm64Float64Div)               \
   V(Arm64Float64Mod)               \
   V(Arm64Float64Sqrt)              \
-  V(Arm64Float64Floor)             \
-  V(Arm64Float64Ceil)              \
-  V(Arm64Float64RoundTruncate)     \
+  V(Arm64Float64RoundDown)         \
   V(Arm64Float64RoundTiesAway)     \
+  V(Arm64Float64RoundTruncate)     \
+  V(Arm64Float64RoundUp)           \
   V(Arm64Float32ToFloat64)         \
   V(Arm64Float64ToFloat32)         \
   V(Arm64Float64ToInt32)           \
   V(Arm64Float64ToUint32)          \
   V(Arm64Int32ToFloat64)           \
   V(Arm64Uint32ToFloat64)          \
+  V(Arm64Float64ExtractLowWord32)  \
+  V(Arm64Float64ExtractHighWord32) \
+  V(Arm64Float64InsertLowWord32)   \
+  V(Arm64Float64InsertHighWord32)  \
+  V(Arm64Float64MoveU64)           \
+  V(Arm64Float64Max)               \
+  V(Arm64Float64Min)               \
   V(Arm64LdrS)                     \
   V(Arm64StrS)                     \
   V(Arm64LdrD)                     \
@@ -124,13 +132,15 @@ namespace compiler {
 // 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] */ \
-  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 */
+#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 */                       \
+  V(Operand2_R_UXTB)  /* %r0 UXTB (unsigned extend byte) */ \
+  V(Operand2_R_UXTH)  /* %r0 UXTH (unsigned extend halfword) */
 
 }  // namespace internal
 }  // namespace compiler
index 6afd3e8..427486b 100644 (file)
@@ -167,6 +167,25 @@ static bool TryMatchAnyShift(InstructionSelector* selector, Node* node,
 }
 
 
+static bool TryMatchAnyExtend(InstructionSelector* selector, Node* node,
+                              InstructionCode* opcode) {
+  NodeMatcher nm(node);
+  if (nm.IsWord32And()) {
+    Int32BinopMatcher m(node);
+    if (m.right().HasValue()) {
+      if (m.right().Value() == 0xff) {
+        *opcode |= AddressingModeField::encode(kMode_Operand2_R_UXTB);
+        return true;
+      } else if (m.right().Value() == 0xffff) {
+        *opcode |= AddressingModeField::encode(kMode_Operand2_R_UXTH);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+
 // Shared routine for multiple binary operations.
 template <typename Matcher>
 static void VisitBinop(InstructionSelector* selector, Node* node,
@@ -178,28 +197,38 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
   size_t input_count = 0;
   InstructionOperand outputs[2];
   size_t output_count = 0;
-  bool try_ror_operand = true;
+  bool is_add_sub = false;
 
   if (m.IsInt32Add() || m.IsInt64Add() || m.IsInt32Sub() || m.IsInt64Sub()) {
-    try_ror_operand = false;
+    is_add_sub = true;
   }
 
   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)) {
+                              !is_add_sub)) {
     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)) {
+                              !is_add_sub)) {
     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 if (is_add_sub &&
+             TryMatchAnyExtend(selector, m.right().node(), &opcode)) {
+    Matcher mright(m.right().node());
+    inputs[input_count++] = g.UseRegister(m.left().node());
+    inputs[input_count++] = g.UseRegister(mright.left().node());
+  } else if (is_add_sub && m.HasProperty(Operator::kCommutative) &&
+             TryMatchAnyExtend(selector, m.left().node(), &opcode)) {
+    Matcher mleft(m.left().node());
+    inputs[input_count++] = g.UseRegister(m.right().node());
+    inputs[input_count++] = g.UseRegister(mleft.left().node());
   } else {
     inputs[input_count++] = g.UseRegister(m.left().node());
     inputs[input_count++] = g.UseRegister(m.right().node());
@@ -220,9 +249,8 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
   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();
+  selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
+                 inputs);
 }
 
 
@@ -709,6 +737,12 @@ void InstructionSelector::VisitWord64Ror(Node* node) {
 }
 
 
+void InstructionSelector::VisitWord32Clz(Node* node) {
+  Arm64OperandGenerator g(this);
+  Emit(kArm64Clz32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitInt32Add(Node* node) {
   Arm64OperandGenerator g(this);
   Int32BinopMatcher m(node);
@@ -1033,6 +1067,20 @@ void InstructionSelector::VisitFloat64Add(Node* node) {
 
 
 void InstructionSelector::VisitFloat64Sub(Node* node) {
+  Arm64OperandGenerator g(this);
+  Float64BinopMatcher m(node);
+  if (m.left().IsMinusZero() && m.right().IsFloat64RoundDown() &&
+      CanCover(m.node(), m.right().node())) {
+    if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
+        CanCover(m.right().node(), m.right().InputAt(0))) {
+      Float64BinopMatcher mright0(m.right().InputAt(0));
+      if (mright0.left().IsMinusZero()) {
+        Emit(kArm64Float64RoundUp, g.DefineAsRegister(node),
+             g.UseRegister(mright0.right().node()));
+        return;
+      }
+    }
+  }
   VisitRRRFloat64(this, kArm64Float64Sub, node);
 }
 
@@ -1055,18 +1103,31 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
 }
 
 
-void InstructionSelector::VisitFloat64Sqrt(Node* node) {
-  VisitRRFloat64(this, kArm64Float64Sqrt, node);
+void InstructionSelector::VisitFloat64Max(Node* node) {
+  Arm64OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Emit(kArm64Float64Max, g.DefineAsRegister(node), g.UseRegister(left),
+       g.UseRegister(right));
 }
 
 
-void InstructionSelector::VisitFloat64Floor(Node* node) {
-  VisitRRFloat64(this, kArm64Float64Floor, node);
+void InstructionSelector::VisitFloat64Min(Node* node) {
+  Arm64OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Emit(kArm64Float64Min, g.DefineAsRegister(node), g.UseRegister(left),
+       g.UseRegister(right));
+}
+
+
+void InstructionSelector::VisitFloat64Sqrt(Node* node) {
+  VisitRRFloat64(this, kArm64Float64Sqrt, node);
 }
 
 
-void InstructionSelector::VisitFloat64Ceil(Node* node) {
-  VisitRRFloat64(this, kArm64Float64Ceil, node);
+void InstructionSelector::VisitFloat64RoundDown(Node* node) {
+  VisitRRFloat64(this, kArm64Float64RoundDown, node);
 }
 
 
@@ -1080,7 +1141,7 @@ void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
 }
 
 
-void InstructionSelector::VisitCall(Node* node) {
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
   Arm64OperandGenerator g(this);
   const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
 
@@ -1107,7 +1168,7 @@ void InstructionSelector::VisitCall(Node* node) {
   if (aligned_push_count > 0) {
     // TODO(dcarney): it would be better to bump the csp here only
     //                and emit paired stores with increment for non c frames.
-    Emit(kArm64Claim | MiscField::encode(aligned_push_count), g.NoOutput());
+    Emit(kArm64Claim, g.NoOutput(), g.TempImmediate(aligned_push_count));
   }
   // Move arguments to the stack.
   {
@@ -1115,18 +1176,26 @@ void InstructionSelector::VisitCall(Node* node) {
     // Emit the uneven pushes.
     if (pushed_count_uneven) {
       Node* input = buffer.pushed_nodes[slot];
-      Emit(kArm64Poke | MiscField::encode(slot), g.NoOutput(),
-           g.UseRegister(input));
+      Emit(kArm64Poke, g.NoOutput(), g.UseRegister(input),
+           g.TempImmediate(slot));
       slot--;
     }
     // Now all pushes can be done in pairs.
     for (; slot >= 0; slot -= 2) {
-      Emit(kArm64PokePair | MiscField::encode(slot), g.NoOutput(),
+      Emit(kArm64PokePair, g.NoOutput(),
            g.UseRegister(buffer.pushed_nodes[slot]),
-           g.UseRegister(buffer.pushed_nodes[slot - 1]));
+           g.UseRegister(buffer.pushed_nodes[slot - 1]),
+           g.TempImmediate(slot));
     }
   }
 
+  // Pass label of exception handler block.
+  CallDescriptor::Flags flags = descriptor->flags();
+  if (handler != nullptr) {
+    flags |= CallDescriptor::kHasExceptionHandler;
+    buffer.instruction_args.push_back(g.Label(handler));
+  }
+
   // Select the appropriate opcode based on the call type.
   InstructionCode opcode;
   switch (descriptor->kind()) {
@@ -1141,7 +1210,7 @@ void InstructionSelector::VisitCall(Node* node) {
       UNREACHABLE();
       return;
   }
-  opcode |= MiscField::encode(descriptor->flags());
+  opcode |= MiscField::encode(flags);
 
   // Emit the call instruction.
   InstructionOperand* first_output =
@@ -1161,8 +1230,7 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
   opcode = cont->Encode(opcode);
   if (cont->IsBranch()) {
     selector->Emit(opcode, g.NoOutput(), left, right,
-                   g.Label(cont->true_block()),
-                   g.Label(cont->false_block()))->MarkAsControl();
+                   g.Label(cont->true_block()), g.Label(cont->false_block()));
   } else {
     DCHECK(cont->IsSet());
     selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
@@ -1243,25 +1311,12 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
   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;
-      }
+  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;
     }
@@ -1354,8 +1409,7 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
                g.UseRegister(m.left().node()),
                g.TempImmediate(
                    base::bits::CountTrailingZeros32(m.right().Value())),
-               g.Label(cont.true_block()),
-               g.Label(cont.false_block()))->MarkAsControl();
+               g.Label(cont.true_block()), g.Label(cont.false_block()));
           return;
         }
         return VisitWordCompare(this, value, kArm64Tst32, &cont, true,
@@ -1372,8 +1426,7 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
                g.UseRegister(m.left().node()),
                g.TempImmediate(
                    base::bits::CountTrailingZeros64(m.right().Value())),
-               g.Label(cont.true_block()),
-               g.Label(cont.false_block()))->MarkAsControl();
+               g.Label(cont.true_block()), g.Label(cont.false_block()));
           return;
         }
         return VisitWordCompare(this, value, kArm64Tst, &cont, true,
@@ -1387,68 +1440,35 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
   // Branch could not be combined with a compare, compare against 0 and branch.
   Emit(cont.Encode(kArm64CompareAndBranch32), g.NoOutput(),
        g.UseRegister(value), g.Label(cont.true_block()),
-       g.Label(cont.false_block()))->MarkAsControl();
+       g.Label(cont.false_block()));
 }
 
 
-void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
-                                      BasicBlock** case_branches,
-                                      int32_t* case_values, size_t case_count,
-                                      int32_t min_value, int32_t max_value) {
+void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
   Arm64OperandGenerator g(this);
   InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
-  InstructionOperand default_operand = g.Label(default_branch);
-
-  // Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value}
-  // is 2^31-1, so don't assume that it's non-zero below.
-  size_t value_range =
-      1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
 
-  // Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
-  // instruction.
-  size_t table_space_cost = 4 + value_range;
+  // Emit either ArchTableSwitch or ArchLookupSwitch.
+  size_t table_space_cost = 4 + sw.value_range;
   size_t table_time_cost = 3;
-  size_t lookup_space_cost = 3 + 2 * case_count;
-  size_t lookup_time_cost = case_count;
-  if (case_count > 0 &&
+  size_t lookup_space_cost = 3 + 2 * sw.case_count;
+  size_t lookup_time_cost = sw.case_count;
+  if (sw.case_count > 0 &&
       table_space_cost + 3 * table_time_cost <=
           lookup_space_cost + 3 * lookup_time_cost &&
-      min_value > std::numeric_limits<int32_t>::min()) {
+      sw.min_value > std::numeric_limits<int32_t>::min()) {
     InstructionOperand index_operand = value_operand;
-    if (min_value) {
+    if (sw.min_value) {
       index_operand = g.TempRegister();
       Emit(kArm64Sub32, index_operand, value_operand,
-           g.TempImmediate(min_value));
+           g.TempImmediate(sw.min_value));
     }
-    size_t input_count = 2 + value_range;
-    auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
-    inputs[0] = index_operand;
-    std::fill(&inputs[1], &inputs[input_count], default_operand);
-    for (size_t index = 0; index < case_count; ++index) {
-      size_t value = case_values[index] - min_value;
-      BasicBlock* branch = case_branches[index];
-      DCHECK_LE(0u, value);
-      DCHECK_LT(value + 2, input_count);
-      inputs[value + 2] = g.Label(branch);
-    }
-    Emit(kArchTableSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
-        ->MarkAsControl();
-    return;
+    // Generate a table lookup.
+    return EmitTableSwitch(sw, index_operand);
   }
 
   // Generate a sequence of conditional jumps.
-  size_t input_count = 2 + case_count * 2;
-  auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
-  inputs[0] = value_operand;
-  inputs[1] = default_operand;
-  for (size_t index = 0; index < case_count; ++index) {
-    int32_t value = case_values[index];
-    BasicBlock* branch = case_branches[index];
-    inputs[index * 2 + 2 + 0] = g.TempImmediate(value);
-    inputs[index * 2 + 2 + 1] = g.Label(branch);
-  }
-  Emit(kArchLookupSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
-      ->MarkAsControl();
+  return EmitLookupSwitch(sw, value_operand);
 }
 
 
@@ -1582,13 +1602,63 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
+  Arm64OperandGenerator g(this);
+  Emit(kArm64Float64ExtractLowWord32, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
+  Arm64OperandGenerator g(this);
+  Emit(kArm64Float64ExtractHighWord32, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
+  Arm64OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 &&
+      CanCover(node, left)) {
+    Node* right_of_left = left->InputAt(1);
+    Emit(kArm64Bfi, g.DefineSameAsFirst(right), g.UseRegister(right),
+         g.UseRegister(right_of_left), g.TempImmediate(32),
+         g.TempImmediate(32));
+    Emit(kArm64Float64MoveU64, g.DefineAsRegister(node), g.UseRegister(right));
+    return;
+  }
+  Emit(kArm64Float64InsertLowWord32, g.DefineAsRegister(node),
+       g.UseRegister(left), g.UseRegister(right));
+}
+
+
+void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
+  Arm64OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 &&
+      CanCover(node, left)) {
+    Node* right_of_left = left->InputAt(1);
+    Emit(kArm64Bfi, g.DefineSameAsFirst(left), g.UseRegister(right_of_left),
+         g.UseRegister(right), g.TempImmediate(32), g.TempImmediate(32));
+    Emit(kArm64Float64MoveU64, g.DefineAsRegister(node), g.UseRegister(left));
+    return;
+  }
+  Emit(kArm64Float64InsertHighWord32, g.DefineAsRegister(node),
+       g.UseRegister(left), g.UseRegister(right));
+}
+
+
 // static
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
-  return MachineOperatorBuilder::kFloat64Floor |
-         MachineOperatorBuilder::kFloat64Ceil |
+  return MachineOperatorBuilder::kFloat64RoundDown |
          MachineOperatorBuilder::kFloat64RoundTruncate |
          MachineOperatorBuilder::kFloat64RoundTiesAway |
+         MachineOperatorBuilder::kFloat64Max |
+         MachineOperatorBuilder::kFloat64Min |
          MachineOperatorBuilder::kWord32ShiftIsSafe |
          MachineOperatorBuilder::kInt32DivIsSafe |
          MachineOperatorBuilder::kUint32DivIsSafe;
index 57945fd..745eb5c 100644 (file)
@@ -51,9 +51,10 @@ CallDescriptor* Linkage::GetRuntimeCallDescriptor(
 CallDescriptor* Linkage::GetStubCallDescriptor(
     Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
     int stack_parameter_count, CallDescriptor::Flags flags,
-    Operator::Properties properties) {
+    Operator::Properties properties, MachineType return_type) {
   return LH::GetStubCallDescriptor(isolate, zone, descriptor,
-                                   stack_parameter_count, flags, properties);
+                                   stack_parameter_count, flags, properties,
+                                   return_type);
 }
 
 
index f5a2e0f..e550f51 100644 (file)
@@ -7,11 +7,14 @@
 #include "src/compiler.h"
 #include "src/compiler/ast-loop-assignment-analyzer.h"
 #include "src/compiler/control-builders.h"
+#include "src/compiler/js-type-feedback.h"
 #include "src/compiler/linkage.h"
+#include "src/compiler/liveness-analyzer.h"
 #include "src/compiler/machine-operator.h"
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties.h"
 #include "src/compiler/operator-properties.h"
+#include "src/compiler/state-values-utils.h"
 #include "src/full-codegen.h"
 #include "src/parser.h"
 #include "src/scopes.h"
@@ -140,10 +143,10 @@ class AstGraphBuilder::ContextScope BASE_EMBEDDED {
 //  - TryFinallyStatement: Intercepts 'break', 'continue', 'throw' and 'return'.
 class AstGraphBuilder::ControlScope BASE_EMBEDDED {
  public:
-  ControlScope(AstGraphBuilder* builder, int stack_delta)
+  explicit ControlScope(AstGraphBuilder* builder)
       : builder_(builder),
         outer_(builder->execution_control()),
-        stack_delta_(stack_delta) {
+        stack_height_(builder->environment()->stack_height()) {
     builder_->set_execution_control(this);  // Push.
   }
 
@@ -190,12 +193,12 @@ class AstGraphBuilder::ControlScope BASE_EMBEDDED {
 
   Environment* environment() { return builder_->environment(); }
   AstGraphBuilder* builder() const { return builder_; }
-  int stack_delta() const { return stack_delta_; }
+  int stack_height() const { return stack_height_; }
 
  private:
   AstGraphBuilder* builder_;
   ControlScope* outer_;
-  int stack_delta_;
+  int stack_height_;
 };
 
 
@@ -212,7 +215,6 @@ class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject {
   struct Entry {
     Command command;       // The command type being applied on this path.
     Statement* statement;  // The target statement for the command or {NULL}.
-    Node* value;           // The passed value node for the command or {NULL}.
     Node* token;           // A token identifying this particular path.
   };
 
@@ -220,7 +222,7 @@ class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject {
   // generates a new dispatch token that identifies one particular path.
   Node* RecordCommand(Command cmd, Statement* stmt, Node* value) {
     Node* token = NewPathTokenForDeferredCommand();
-    deferred_.push_back({cmd, stmt, value, token});
+    deferred_.push_back({cmd, stmt, token});
     return token;
   }
 
@@ -230,7 +232,7 @@ class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject {
 
   // Applies all recorded control-flow commands after the finally-block again.
   // This generates a dynamic dispatch on the token from the entry point.
-  void ApplyDeferredCommands(Node* token) {
+  void ApplyDeferredCommands(Node* token, Node* value) {
     SwitchBuilder dispatch(owner_, static_cast<int>(deferred_.size()));
     dispatch.BeginSwitch();
     for (size_t i = 0; i < deferred_.size(); ++i) {
@@ -241,7 +243,7 @@ class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject {
     for (size_t i = 0; i < deferred_.size(); ++i) {
       dispatch.BeginCase(static_cast<int>(i));
       owner_->execution_control()->PerformCommand(
-          deferred_[i].command, deferred_[i].statement, deferred_[i].value);
+          deferred_[i].command, deferred_[i].statement, value);
       dispatch.EndCase();
     }
     dispatch.EndSwitch();
@@ -271,7 +273,7 @@ class AstGraphBuilder::ControlScopeForBreakable : public ControlScope {
  public:
   ControlScopeForBreakable(AstGraphBuilder* owner, BreakableStatement* target,
                            ControlBuilder* control)
-      : ControlScope(owner, 0), target_(target), control_(control) {}
+      : ControlScope(owner), target_(target), control_(control) {}
 
  protected:
   virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE {
@@ -298,8 +300,8 @@ class AstGraphBuilder::ControlScopeForBreakable : public ControlScope {
 class AstGraphBuilder::ControlScopeForIteration : public ControlScope {
  public:
   ControlScopeForIteration(AstGraphBuilder* owner, IterationStatement* target,
-                           LoopBuilder* control, int stack_delta)
-      : ControlScope(owner, stack_delta), target_(target), control_(control) {}
+                           LoopBuilder* control)
+      : ControlScope(owner), target_(target), control_(control) {}
 
  protected:
   virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE {
@@ -328,7 +330,12 @@ class AstGraphBuilder::ControlScopeForIteration : public ControlScope {
 class AstGraphBuilder::ControlScopeForCatch : public ControlScope {
  public:
   ControlScopeForCatch(AstGraphBuilder* owner, TryCatchBuilder* control)
-      : ControlScope(owner, 0), control_(control) {}
+      : ControlScope(owner), control_(control) {
+    builder()->try_nesting_level_++;  // Increment nesting.
+  }
+  ~ControlScopeForCatch() {
+    builder()->try_nesting_level_--;  // Decrement nesting.
+  }
 
  protected:
   virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE {
@@ -354,12 +361,17 @@ class AstGraphBuilder::ControlScopeForFinally : public ControlScope {
  public:
   ControlScopeForFinally(AstGraphBuilder* owner, DeferredCommands* commands,
                          TryFinallyBuilder* control)
-      : ControlScope(owner, 0), commands_(commands), control_(control) {}
+      : ControlScope(owner), commands_(commands), control_(control) {
+    builder()->try_nesting_level_++;  // Increment nesting.
+  }
+  ~ControlScopeForFinally() {
+    builder()->try_nesting_level_--;  // Decrement nesting.
+  }
 
  protected:
   virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE {
     Node* token = commands_->RecordCommand(cmd, target, value);
-    control_->LeaveTry(token);
+    control_->LeaveTry(token, value);
     return true;
   }
 
@@ -370,7 +382,8 @@ class AstGraphBuilder::ControlScopeForFinally : public ControlScope {
 
 
 AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
-                                 JSGraph* jsgraph, LoopAssignmentAnalysis* loop)
+                                 JSGraph* jsgraph, LoopAssignmentAnalysis* loop,
+                                 JSTypeFeedbackTable* js_type_feedback)
     : local_zone_(local_zone),
       info_(info),
       jsgraph_(jsgraph),
@@ -379,10 +392,15 @@ AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
       globals_(0, local_zone),
       execution_control_(nullptr),
       execution_context_(nullptr),
+      try_nesting_level_(0),
       input_buffer_size_(0),
       input_buffer_(nullptr),
       exit_control_(nullptr),
-      loop_assignment_analysis_(loop) {
+      loop_assignment_analysis_(loop),
+      state_values_cache_(jsgraph),
+      liveness_analyzer_(static_cast<size_t>(info->scope()->num_stack_slots()),
+                         local_zone),
+      js_type_feedback_(js_type_feedback) {
   InitializeAstVisitor(info->isolate(), local_zone);
 }
 
@@ -420,7 +438,7 @@ Node* AstGraphBuilder::NewCurrentContextOsrValue() {
 }
 
 
-bool AstGraphBuilder::CreateGraph(bool constant_context) {
+bool AstGraphBuilder::CreateGraph(bool constant_context, bool stack_check) {
   Scope* scope = info()->scope();
   DCHECK(graph() != NULL);
 
@@ -428,13 +446,13 @@ bool AstGraphBuilder::CreateGraph(bool constant_context) {
   int parameter_count = info()->num_parameters();
   graph()->SetStart(graph()->NewNode(common()->Start(parameter_count)));
 
-  // Initialize control scope.
-  ControlScope control(this, 0);
-
   // Initialize the top-level environment.
   Environment env(this, scope, graph()->start());
   set_environment(&env);
 
+  // Initialize control scope.
+  ControlScope control(this);
+
   if (info()->is_osr()) {
     // Use OSR normal entry as the start of the top-level environment.
     // It will be replaced with {Dead} after typing and optimizations.
@@ -459,21 +477,25 @@ bool AstGraphBuilder::CreateGraph(bool constant_context) {
     Node* inner_context =
         BuildLocalFunctionContext(function_context_.get(), closure);
     ContextScope top_context(this, scope, inner_context);
-    CreateGraphBody();
+    CreateGraphBody(stack_check);
   } else {
     // Simply use the outer function context in building the graph.
-    CreateGraphBody();
+    CreateGraphBody(stack_check);
   }
 
   // Finish the basic structure of the graph.
   graph()->SetEnd(graph()->NewNode(common()->End(), exit_control()));
 
+  // Compute local variable liveness information and use it to relax
+  // frame states.
+  ClearNonLiveSlotsInFrameStates();
+
   // Failures indicated by stack overflow.
   return !HasStackOverflow();
 }
 
 
-void AstGraphBuilder::CreateGraphBody() {
+void AstGraphBuilder::CreateGraphBody(bool stack_check) {
   Scope* scope = info()->scope();
 
   // Build the arguments object if it is used.
@@ -498,8 +520,10 @@ void AstGraphBuilder::CreateGraphBody() {
   VisitDeclarations(scope->declarations());
 
   // Build a stack-check before the body.
-  Node* node = BuildStackCheck();
-  PrepareFrameState(node, BailoutId::FunctionEntry());
+  if (stack_check) {
+    Node* node = NewNode(javascript()->StackCheck());
+    PrepareFrameState(node, BailoutId::FunctionEntry());
+  }
 
   // Visit statements in the function body.
   VisitStatements(info()->function()->body());
@@ -516,6 +540,24 @@ void AstGraphBuilder::CreateGraphBody() {
 }
 
 
+void AstGraphBuilder::ClearNonLiveSlotsInFrameStates() {
+  if (!FLAG_analyze_environment_liveness) return;
+
+  NonLiveFrameStateSlotReplacer replacer(
+      &state_values_cache_, jsgraph()->UndefinedConstant(),
+      liveness_analyzer()->local_count(), local_zone());
+  Variable* arguments = info()->scope()->arguments();
+  if (arguments != nullptr && arguments->IsStackAllocated()) {
+    replacer.MarkPermanentlyLive(arguments->index());
+  }
+  liveness_analyzer()->Run(&replacer);
+  if (FLAG_trace_environment_liveness) {
+    OFStream os(stdout);
+    liveness_analyzer()->Print(os);
+  }
+}
+
+
 // Left-hand side can only be a property, a global or a variable slot.
 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
 
@@ -538,6 +580,7 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
     : builder_(builder),
       parameters_count_(scope->num_parameters() + 1),
       locals_count_(scope->num_stack_slots()),
+      liveness_block_(builder_->liveness_analyzer()->NewBlock()),
       values_(builder_->local_zone()),
       contexts_(builder_->local_zone()),
       control_dependency_(control_dependency),
@@ -566,8 +609,7 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
 }
 
 
-AstGraphBuilder::Environment::Environment(
-    const AstGraphBuilder::Environment* copy)
+AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy)
     : builder_(copy->builder_),
       parameters_count_(copy->parameters_count_),
       locals_count_(copy->locals_count_),
@@ -584,13 +626,72 @@ AstGraphBuilder::Environment::Environment(
   contexts_.reserve(copy->contexts_.size());
   contexts_.insert(contexts_.begin(), copy->contexts_.begin(),
                    copy->contexts_.end());
+
+  if (FLAG_analyze_environment_liveness) {
+    // Split the liveness blocks.
+    copy->liveness_block_ =
+        builder_->liveness_analyzer()->NewBlock(copy->liveness_block());
+    liveness_block_ =
+        builder_->liveness_analyzer()->NewBlock(copy->liveness_block());
+  }
+}
+
+
+void AstGraphBuilder::Environment::Bind(Variable* variable, Node* node) {
+  DCHECK(variable->IsStackAllocated());
+  if (variable->IsParameter()) {
+    // The parameter indices are shifted by 1 (receiver is parameter
+    // index -1 but environment index 0).
+    values()->at(variable->index() + 1) = node;
+  } else {
+    DCHECK(variable->IsStackLocal());
+    values()->at(variable->index() + parameters_count_) = node;
+    if (FLAG_analyze_environment_liveness) {
+      liveness_block()->Bind(variable->index());
+    }
+  }
+}
+
+
+Node* AstGraphBuilder::Environment::Lookup(Variable* variable) {
+  DCHECK(variable->IsStackAllocated());
+  if (variable->IsParameter()) {
+    // The parameter indices are shifted by 1 (receiver is parameter
+    // index -1 but environment index 0).
+    return values()->at(variable->index() + 1);
+  } else {
+    DCHECK(variable->IsStackLocal());
+    if (FLAG_analyze_environment_liveness) {
+      liveness_block()->Lookup(variable->index());
+    }
+    return values()->at(variable->index() + parameters_count_);
+  }
+}
+
+
+void AstGraphBuilder::Environment::MarkAllLocalsLive() {
+  if (FLAG_analyze_environment_liveness) {
+    for (int i = 0; i < locals_count_; i++) {
+      liveness_block()->Lookup(i);
+    }
+  }
+}
+
+
+AstGraphBuilder::Environment*
+AstGraphBuilder::Environment::CopyAndShareLiveness() {
+  Environment* env = new (zone()) Environment(this);
+  if (FLAG_analyze_environment_liveness) {
+    env->liveness_block_ = liveness_block();
+  }
+  return env;
 }
 
 
 void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values,
                                                      int offset, int count) {
   bool should_update = false;
-  Node** env_values = (count == 0) ? NULL : &values()->at(offset);
+  Node** env_values = (count == 0) ? nullptr : &values()->at(offset);
   if (*state_values == NULL || (*state_values)->InputCount() != count) {
     should_update = true;
   } else {
@@ -609,18 +710,32 @@ void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values,
 }
 
 
+void AstGraphBuilder::Environment::UpdateStateValuesWithCache(
+    Node** state_values, int offset, int count) {
+  Node** env_values = (count == 0) ? nullptr : &values()->at(offset);
+  *state_values = builder_->state_values_cache_.GetNodeForValues(
+      env_values, static_cast<size_t>(count));
+}
+
+
 Node* AstGraphBuilder::Environment::Checkpoint(
     BailoutId ast_id, OutputFrameStateCombine combine) {
+  if (!FLAG_turbo_deoptimization) return nullptr;
+
   UpdateStateValues(&parameters_node_, 0, parameters_count());
-  UpdateStateValues(&locals_node_, parameters_count(), locals_count());
+  UpdateStateValuesWithCache(&locals_node_, parameters_count(), locals_count());
   UpdateStateValues(&stack_node_, parameters_count() + locals_count(),
                     stack_height());
 
   const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine);
 
-  return graph()->NewNode(op, parameters_node_, locals_node_, stack_node_,
-                          builder()->current_context(),
-                          builder()->jsgraph()->UndefinedConstant());
+  Node* result = graph()->NewNode(op, parameters_node_, locals_node_,
+                                  stack_node_, builder()->current_context(),
+                                  builder()->jsgraph()->UndefinedConstant());
+  if (FLAG_analyze_environment_liveness) {
+    liveness_block()->Checkpoint(result);
+  }
+  return result;
 }
 
 
@@ -698,8 +813,8 @@ void AstGraphBuilder::ControlScope::PerformCommand(Command command,
   Environment* env = environment()->CopyAsUnreachable();
   ControlScope* current = this;
   while (current != NULL) {
+    environment()->Trim(current->stack_height());
     if (current->Execute(command, target, value)) break;
-    environment()->Drop(current->stack_delta());
     current = current->outer_;
   }
   builder()->set_environment(env);
@@ -708,12 +823,12 @@ void AstGraphBuilder::ControlScope::PerformCommand(Command command,
 
 
 void AstGraphBuilder::ControlScope::BreakTo(BreakableStatement* stmt) {
-  PerformCommand(CMD_BREAK, stmt, nullptr);
+  PerformCommand(CMD_BREAK, stmt, builder()->jsgraph()->TheHoleConstant());
 }
 
 
 void AstGraphBuilder::ControlScope::ContinueTo(BreakableStatement* stmt) {
-  PerformCommand(CMD_CONTINUE, stmt, nullptr);
+  PerformCommand(CMD_CONTINUE, stmt, builder()->jsgraph()->TheHoleConstant());
 }
 
 
@@ -1008,7 +1123,7 @@ void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
 void AstGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
   LoopBuilder while_loop(this);
   while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
-  VisitIterationBody(stmt, &while_loop, 0);
+  VisitIterationBody(stmt, &while_loop);
   while_loop.EndBody();
   VisitForTest(stmt->cond());
   Node* condition = environment()->Pop();
@@ -1023,7 +1138,7 @@ void AstGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
   VisitForTest(stmt->cond());
   Node* condition = environment()->Pop();
   while_loop.BreakUnless(condition);
-  VisitIterationBody(stmt, &while_loop, 0);
+  VisitIterationBody(stmt, &while_loop);
   while_loop.EndBody();
   while_loop.EndLoop();
 }
@@ -1040,7 +1155,7 @@ void AstGraphBuilder::VisitForStatement(ForStatement* stmt) {
   } else {
     for_loop.BreakUnless(jsgraph()->TrueConstant());
   }
-  VisitIterationBody(stmt, &for_loop, 0);
+  VisitIterationBody(stmt, &for_loop);
   for_loop.EndBody();
   VisitIfNotNull(stmt->next());
   for_loop.EndLoop();
@@ -1165,7 +1280,9 @@ void AstGraphBuilder::VisitForInBody(ForInStatement* stmt) {
       Node* index_inc =
           NewNode(javascript()->Add(), index, jsgraph()->OneConstant());
       // TODO(jarin): provide real bailout id.
-      PrepareFrameState(index_inc, BailoutId::None());
+      PrepareFrameStateAfterAndBefore(index_inc, BailoutId::None(),
+                                      OutputFrameStateCombine::Ignore(),
+                                      jsgraph()->EmptyFrameState());
       environment()->Poke(0, index_inc);
       for_loop.Continue();
       is_property_missing.Else();
@@ -1179,13 +1296,17 @@ void AstGraphBuilder::VisitForInBody(ForInStatement* stmt) {
   value = environment()->Pop();
   // Bind value and do loop body.
   VisitForInAssignment(stmt->each(), value, stmt->AssignmentId());
-  VisitIterationBody(stmt, &for_loop, 5);
+  VisitIterationBody(stmt, &for_loop);
+  index = environment()->Peek(0);
   for_loop.EndBody();
+
   // Inc counter and continue.
   Node* index_inc =
       NewNode(javascript()->Add(), index, jsgraph()->OneConstant());
   // TODO(jarin): provide real bailout id.
-  PrepareFrameState(index_inc, BailoutId::None());
+  PrepareFrameStateAfterAndBefore(index_inc, BailoutId::None(),
+                                  OutputFrameStateCombine::Ignore(),
+                                  jsgraph()->EmptyFrameState());
   environment()->Poke(0, index_inc);
   for_loop.EndLoop();
   environment()->Drop(5);
@@ -1202,7 +1323,7 @@ void AstGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
   Node* condition = environment()->Pop();
   for_loop.BreakWhen(condition);
   VisitForEffect(stmt->assign_each());
-  VisitIterationBody(stmt, &for_loop, 0);
+  VisitIterationBody(stmt, &for_loop);
   for_loop.EndBody();
   for_loop.EndLoop();
 }
@@ -1216,7 +1337,10 @@ void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
   try_control.BeginTry();
   {
     ControlScopeForCatch scope(this, &try_control);
+    STATIC_ASSERT(TryBlockConstant::kElementCount == 1);
+    environment()->Push(current_context());
     Visit(stmt->try_block());
+    environment()->Pop();
   }
   try_control.EndTry();
 
@@ -1242,6 +1366,9 @@ void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
 void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
   TryFinallyBuilder try_control(this);
 
+  ExternalReference message_object =
+      ExternalReference::address_of_pending_message_obj(isolate());
+
   // We keep a record of all paths that enter the finally-block to be able to
   // dispatch to the correct continuation point after the statements in the
   // finally-block have been evaluated.
@@ -1251,6 +1378,7 @@ void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
   // 2. By exiting the try-block with a function-local control flow transfer
   //    (i.e. through break/continue/return statements).
   // 3. By exiting the try-block with a thrown exception.
+  Node* fallthrough_result = jsgraph()->TheHoleConstant();
   ControlScope::DeferredCommands* commands =
       new (zone()) ControlScope::DeferredCommands(this);
 
@@ -1259,17 +1387,41 @@ void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
   try_control.BeginTry();
   {
     ControlScopeForFinally scope(this, commands, &try_control);
+    STATIC_ASSERT(TryBlockConstant::kElementCount == 1);
+    environment()->Push(current_context());
     Visit(stmt->try_block());
+    environment()->Pop();
   }
-  try_control.EndTry(commands->GetFallThroughToken());
+  try_control.EndTry(commands->GetFallThroughToken(), fallthrough_result);
+
+  // The result value semantics depend on how the block was entered:
+  //  - ReturnStatement: It represents the return value being returned.
+  //  - ThrowStatement: It represents the exception being thrown.
+  //  - BreakStatement/ContinueStatement: Filled with the hole.
+  //  - Falling through into finally-block: Filled with the hole.
+  Node* result = try_control.GetResultValueNode();
+  Node* token = try_control.GetDispatchTokenNode();
+
+  // The result value, dispatch token and message is expected on the operand
+  // stack (this is in sync with FullCodeGenerator::EnterFinallyBlock).
+  Node* message = BuildLoadExternal(message_object, kMachAnyTagged);
+  environment()->Push(token);  // TODO(mstarzinger): Cook token!
+  environment()->Push(result);
+  environment()->Push(message);
 
   // Evaluate the finally-block.
   Visit(stmt->finally_block());
   try_control.EndFinally();
 
+  // The result value, dispatch token and message is restored from the operand
+  // stack (this is in sync with FullCodeGenerator::ExitFinallyBlock).
+  message = environment()->Pop();
+  result = environment()->Pop();
+  token = environment()->Pop();  // TODO(mstarzinger): Uncook token!
+  BuildStoreExternal(message_object, kMachAnyTagged, message);
+
   // Dynamic dispatch after the finally-block.
-  Node* token = try_control.GetDispatchTokenNode();
-  commands->ApplyDeferredCommands(token);
+  commands->ApplyDeferredCommands(token, result);
 
   // TODO(mstarzinger): Remove bailout once everything works.
   if (!FLAG_turbo_exceptions) SetStackOverflow();
@@ -1277,9 +1429,9 @@ void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
 
 
 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
-  // TODO(turbofan): Do we really need a separate reloc-info for this?
   Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0));
   PrepareFrameState(node, stmt->DebugBreakId());
+  environment()->MarkAllLocalsLive();
 }
 
 
@@ -1353,8 +1505,19 @@ void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) {
     environment()->Push(property->is_static() ? literal : proto);
 
     VisitForValue(property->key());
-    environment()->Push(
-        BuildToName(environment()->Pop(), expr->GetIdForProperty(i)));
+    Node* name = BuildToName(environment()->Pop(), expr->GetIdForProperty(i));
+    environment()->Push(name);
+
+    // The static prototype property is read only. We handle the non computed
+    // property name case in the parser. Since this is the only case where we
+    // need to check for an own read only property we special case this so we do
+    // not need to do this for every property.
+    if (property->is_static() && property->is_computed_name()) {
+      Node* check = BuildThrowIfStaticPrototype(environment()->Pop(),
+                                                expr->GetIdForProperty(i));
+      environment()->Push(check);
+    }
+
     VisitForValue(property->value());
     Node* value = environment()->Pop();
     Node* key = environment()->Pop();
@@ -1502,10 +1665,9 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
           if (property->emit_store()) {
             VisitForValue(property->value());
             Node* value = environment()->Pop();
-            Unique<Name> name = MakeUnique(key->AsPropertyName());
+            Handle<Name> name = key->AsPropertyName();
             Node* store =
-                NewNode(javascript()->StoreNamed(language_mode(), name),
-                        literal, value);
+                BuildNamedStore(literal, name, value, TypeFeedbackId::None());
             PrepareFrameState(store, key->id());
             BuildSetHomeObject(value, literal, property->value());
           } else {
@@ -1588,8 +1750,9 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
 
     environment()->Push(literal);  // Duplicate receiver.
     VisitForValue(property->key());
-    environment()->Push(BuildToName(environment()->Pop(),
-                                    expr->GetIdForProperty(property_index)));
+    Node* name = BuildToName(environment()->Pop(),
+                             expr->GetIdForProperty(property_index));
+    environment()->Push(name);
     // TODO(mstarzinger): For ObjectLiteral::Property::PROTOTYPE the key should
     // not be on the operand stack while the value is being evaluated. Come up
     // with a repro for this and fix it. Also find a nice way to do so. :)
@@ -1675,11 +1838,15 @@ void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
     if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
 
     VisitForValue(subexpr);
+    Node* frame_state_before = environment()->Checkpoint(
+        subexpr->id(), OutputFrameStateCombine::PokeAt(0));
     Node* value = environment()->Pop();
     Node* index = jsgraph()->Constant(i);
-    Node* store = NewNode(javascript()->StoreProperty(language_mode()), literal,
-                          index, value);
-    PrepareFrameState(store, expr->GetIdForElement(i));
+    Node* store =
+        BuildKeyedStore(literal, index, value, TypeFeedbackId::None());
+    PrepareFrameStateAfterAndBefore(store, expr->GetIdForElement(i),
+                                    OutputFrameStateCombine::Ignore(),
+                                    frame_state_before);
   }
 
   environment()->Pop();  // Array literal index.
@@ -1707,10 +1874,9 @@ void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value,
       VisitForValue(property->obj());
       Node* object = environment()->Pop();
       value = environment()->Pop();
-      Unique<Name> name =
-          MakeUnique(property->key()->AsLiteral()->AsPropertyName());
-      Node* store = NewNode(javascript()->StoreNamed(language_mode(), name),
-                            object, value);
+      Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
+      Node* store =
+          BuildNamedStore(object, name, value, TypeFeedbackId::None());
       PrepareFrameState(store, bailout_id);
       break;
     }
@@ -1721,9 +1887,11 @@ void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value,
       Node* key = environment()->Pop();
       Node* object = environment()->Pop();
       value = environment()->Pop();
-      Node* store = NewNode(javascript()->StoreProperty(language_mode()),
-                            object, key, value);
-      PrepareFrameState(store, bailout_id);
+      Node* store = BuildKeyedStore(object, key, value, TypeFeedbackId::None());
+      // TODO(jarin) Provide a real frame state before.
+      PrepareFrameStateAfterAndBefore(store, bailout_id,
+                                      OutputFrameStateCombine::Ignore(),
+                                      jsgraph()->EmptyFrameState());
       break;
     }
   }
@@ -1754,6 +1922,8 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
 
   // Evaluate the value and potentially handle compound assignments by loading
   // the left-hand side value and performing a binary operation.
+  Node* frame_state_before_store = nullptr;
+  bool needs_frame_state_before = (assign_type == KEYED_PROPERTY);
   if (expr->is_compound()) {
     Node* old_value = NULL;
     switch (assign_type) {
@@ -1766,11 +1936,11 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
       }
       case NAMED_PROPERTY: {
         Node* object = environment()->Top();
-        Unique<Name> name =
-            MakeUnique(property->key()->AsLiteral()->AsPropertyName());
+        Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
         VectorSlotPair pair =
             CreateVectorSlotPair(property->PropertyFeedbackSlot());
-        old_value = NewNode(javascript()->LoadNamed(name, pair), object);
+        old_value =
+            BuildNamedLoad(object, name, pair, property->PropertyFeedbackId());
         PrepareFrameState(old_value, property->LoadId(),
                           OutputFrameStateCombine::Push());
         break;
@@ -1780,7 +1950,8 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
         Node* object = environment()->Peek(1);
         VectorSlotPair pair =
             CreateVectorSlotPair(property->PropertyFeedbackSlot());
-        old_value = NewNode(javascript()->LoadProperty(pair), object, key);
+        old_value =
+            BuildKeyedLoad(object, key, pair, property->PropertyFeedbackId());
         PrepareFrameState(old_value, property->LoadId(),
                           OutputFrameStateCombine::Push());
         break;
@@ -1788,14 +1959,29 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
     }
     environment()->Push(old_value);
     VisitForValue(expr->value());
+    Node* frame_state_before = environment()->Checkpoint(expr->value()->id());
     Node* right = environment()->Pop();
     Node* left = environment()->Pop();
     Node* value = BuildBinaryOp(left, right, expr->binary_op());
-    PrepareFrameState(value, expr->binary_operation()->id(),
-                      OutputFrameStateCombine::Push());
+    PrepareFrameStateAfterAndBefore(value, expr->binary_operation()->id(),
+                                    OutputFrameStateCombine::Push(),
+                                    frame_state_before);
     environment()->Push(value);
+    if (needs_frame_state_before) {
+      frame_state_before_store = environment()->Checkpoint(
+          expr->binary_operation()->id(), OutputFrameStateCombine::PokeAt(0));
+    }
   } else {
     VisitForValue(expr->value());
+    if (needs_frame_state_before) {
+      // This frame state can be used for lazy-deopting from a to-number
+      // conversion if we are storing into a typed array. It is important
+      // that the frame state is usable for such lazy deopt (i.e., it has
+      // to specify how to override the value before the conversion, in this
+      // case, it overwrites the stack top).
+      frame_state_before_store = environment()->Checkpoint(
+          expr->value()->id(), OutputFrameStateCombine::PokeAt(0));
+    }
   }
 
   // Store the value.
@@ -1803,27 +1989,26 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
   switch (assign_type) {
     case VARIABLE: {
       Variable* variable = expr->target()->AsVariableProxy()->var();
-      BuildVariableAssignment(variable, value, expr->op(), expr->AssignmentId(),
+      BuildVariableAssignment(variable, value, expr->op(), expr->id(),
                               ast_context()->GetStateCombine());
       break;
     }
     case NAMED_PROPERTY: {
       Node* object = environment()->Pop();
-      Unique<Name> name =
-          MakeUnique(property->key()->AsLiteral()->AsPropertyName());
-      Node* store = NewNode(javascript()->StoreNamed(language_mode(), name),
-                            object, value);
-      PrepareFrameState(store, expr->AssignmentId(),
-                        ast_context()->GetStateCombine());
+      Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
+      Node* store =
+          BuildNamedStore(object, name, value, expr->AssignmentFeedbackId());
+      PrepareFrameState(store, expr->id(), ast_context()->GetStateCombine());
       break;
     }
     case KEYED_PROPERTY: {
       Node* key = environment()->Pop();
       Node* object = environment()->Pop();
-      Node* store = NewNode(javascript()->StoreProperty(language_mode()),
-                            object, key, value);
-      PrepareFrameState(store, expr->AssignmentId(),
-                        ast_context()->GetStateCombine());
+      Node* store =
+          BuildKeyedStore(object, key, value, expr->AssignmentFeedbackId());
+      PrepareFrameStateAfterAndBefore(store, expr->id(),
+                                      ast_context()->GetStateCombine(),
+                                      frame_state_before_store);
       break;
     }
   }
@@ -1842,16 +2027,8 @@ void AstGraphBuilder::VisitYield(Yield* expr) {
 void AstGraphBuilder::VisitThrow(Throw* expr) {
   VisitForValue(expr->exception());
   Node* exception = environment()->Pop();
-  if (FLAG_turbo_exceptions) {
-    execution_control()->ThrowValue(exception);
-    ast_context()->ProduceValue(exception);
-  } else {
-    // TODO(mstarzinger): Temporary workaround for bailout-id for debugger.
-    const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1);
-    Node* value = NewNode(op, exception);
-    PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
-    ast_context()->ProduceValue(value);
-  }
+  Node* value = BuildThrowError(exception, expr->id());
+  ast_context()->ProduceValue(value);
 }
 
 
@@ -1861,14 +2038,14 @@ void AstGraphBuilder::VisitProperty(Property* expr) {
   if (expr->key()->IsPropertyName()) {
     VisitForValue(expr->obj());
     Node* object = environment()->Pop();
-    Unique<Name> name = MakeUnique(expr->key()->AsLiteral()->AsPropertyName());
-    value = NewNode(javascript()->LoadNamed(name, pair), object);
+    Handle<Name> name = expr->key()->AsLiteral()->AsPropertyName();
+    value = BuildNamedLoad(object, name, pair, expr->PropertyFeedbackId());
   } else {
     VisitForValue(expr->obj());
     VisitForValue(expr->key());
     Node* key = environment()->Pop();
     Node* object = environment()->Pop();
-    value = NewNode(javascript()->LoadProperty(pair), object, key);
+    value = BuildKeyedLoad(object, key, pair, expr->PropertyFeedbackId());
   }
   PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
@@ -1915,13 +2092,14 @@ void AstGraphBuilder::VisitCall(Call* expr) {
       VectorSlotPair pair =
           CreateVectorSlotPair(property->PropertyFeedbackSlot());
       if (property->key()->IsPropertyName()) {
-        Unique<Name> name =
-            MakeUnique(property->key()->AsLiteral()->AsPropertyName());
-        callee_value = NewNode(javascript()->LoadNamed(name, pair), object);
+        Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
+        callee_value =
+            BuildNamedLoad(object, name, pair, property->PropertyFeedbackId());
       } else {
         VisitForValue(property->key());
         Node* key = environment()->Pop();
-        callee_value = NewNode(javascript()->LoadProperty(pair), object, key);
+        callee_value =
+            BuildKeyedLoad(object, key, pair, property->PropertyFeedbackId());
       }
       PrepareFrameState(callee_value, property->LoadId(),
                         OutputFrameStateCombine::Push());
@@ -2016,10 +2194,9 @@ void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) {
   // before arguments are being evaluated.
   CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS;
   Node* receiver_value = BuildLoadBuiltinsObject();
-  Unique<String> unique = MakeUnique(name);
   VectorSlotPair pair = CreateVectorSlotPair(expr->CallRuntimeFeedbackSlot());
   Node* callee_value =
-      NewNode(javascript()->LoadNamed(unique, pair), receiver_value);
+      BuildNamedLoad(receiver_value, name, pair, expr->CallRuntimeFeedbackId());
   // TODO(jarin): Find/create a bailout id to deoptimize to (crankshaft
   // refuses to optimize functions with jsruntime calls).
   PrepareFrameState(callee_value, BailoutId::None(),
@@ -2104,11 +2281,11 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
     case NAMED_PROPERTY: {
       VisitForValue(property->obj());
       Node* object = environment()->Top();
-      Unique<Name> name =
-          MakeUnique(property->key()->AsLiteral()->AsPropertyName());
+      Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
       VectorSlotPair pair =
           CreateVectorSlotPair(property->PropertyFeedbackSlot());
-      old_value = NewNode(javascript()->LoadNamed(name, pair), object);
+      old_value =
+          BuildNamedLoad(object, name, pair, property->PropertyFeedbackId());
       PrepareFrameState(old_value, property->LoadId(),
                         OutputFrameStateCombine::Push());
       stack_depth = 1;
@@ -2121,7 +2298,8 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
       Node* object = environment()->Peek(1);
       VectorSlotPair pair =
           CreateVectorSlotPair(property->PropertyFeedbackSlot());
-      old_value = NewNode(javascript()->LoadProperty(pair), object, key);
+      old_value =
+          BuildKeyedLoad(object, key, pair, property->PropertyFeedbackId());
       PrepareFrameState(old_value, property->LoadId(),
                         OutputFrameStateCombine::Push());
       stack_depth = 2;
@@ -2134,15 +2312,22 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
   PrepareFrameState(old_value, expr->ToNumberId(),
                     OutputFrameStateCombine::Push());
 
+  Node* frame_state_before_store =
+      assign_type == KEYED_PROPERTY
+          ? environment()->Checkpoint(expr->ToNumberId())
+          : nullptr;
+
   // Save result for postfix expressions at correct stack depth.
   if (is_postfix) environment()->Poke(stack_depth, old_value);
 
   // Create node to perform +1/-1 operation.
   Node* value =
       BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op());
-  // TODO(jarin) Insert proper bailout id here (will need to change
-  // full code generator).
-  PrepareFrameState(value, BailoutId::None());
+  // This should never deoptimize because we have converted to number
+  // before.
+  PrepareFrameStateAfterAndBefore(value, BailoutId::None(),
+                                  OutputFrameStateCombine::Ignore(),
+                                  jsgraph()->EmptyFrameState());
 
   // Store the value.
   switch (assign_type) {
@@ -2156,10 +2341,9 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
     }
     case NAMED_PROPERTY: {
       Node* object = environment()->Pop();
-      Unique<Name> name =
-          MakeUnique(property->key()->AsLiteral()->AsPropertyName());
-      Node* store = NewNode(javascript()->StoreNamed(language_mode(), name),
-                            object, value);
+      Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
+      Node* store =
+          BuildNamedStore(object, name, value, expr->CountStoreFeedbackId());
       environment()->Push(value);
       PrepareFrameState(store, expr->AssignmentId());
       environment()->Pop();
@@ -2168,10 +2352,12 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
     case KEYED_PROPERTY: {
       Node* key = environment()->Pop();
       Node* object = environment()->Pop();
-      Node* store = NewNode(javascript()->StoreProperty(language_mode()),
-                            object, key, value);
+      Node* store =
+          BuildKeyedStore(object, key, value, expr->CountStoreFeedbackId());
       environment()->Push(value);
-      PrepareFrameState(store, expr->AssignmentId());
+      PrepareFrameStateAfterAndBefore(store, expr->AssignmentId(),
+                                      OutputFrameStateCombine::Ignore(),
+                                      frame_state_before_store);
       environment()->Pop();
       break;
     }
@@ -2194,10 +2380,13 @@ void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
     default: {
       VisitForValue(expr->left());
       VisitForValue(expr->right());
+      Node* frame_state_before = environment()->Checkpoint(expr->right()->id());
       Node* right = environment()->Pop();
       Node* left = environment()->Pop();
       Node* value = BuildBinaryOp(left, right, expr->op());
-      PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
+      PrepareFrameStateAfterAndBefore(value, expr->id(),
+                                      ast_context()->GetStateCombine(),
+                                      frame_state_before);
       ast_context()->ProduceValue(value);
     }
   }
@@ -2293,8 +2482,8 @@ void AstGraphBuilder::VisitIfNotNull(Statement* stmt) {
 
 
 void AstGraphBuilder::VisitIterationBody(IterationStatement* stmt,
-                                         LoopBuilder* loop, int stack_delta) {
-  ControlScopeForIteration scope(this, stmt, loop, stack_delta);
+                                         LoopBuilder* loop) {
+  ControlScopeForIteration scope(this, stmt, loop);
   Visit(stmt->body());
 }
 
@@ -2431,7 +2620,8 @@ Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) {
   Node* check = NewNode(javascript()->StrictEqual(), receiver, undefined);
   receiver_check.If(check);
   receiver_check.Then();
-  environment()->Push(BuildLoadGlobalProxy());
+  Node* proxy = BuildLoadGlobalProxy();
+  environment()->Push(proxy);
   receiver_check.Else();
   environment()->Push(receiver);
   receiver_check.End();
@@ -2530,7 +2720,8 @@ Node* AstGraphBuilder::BuildHoleCheckThrow(Node* value, Variable* variable,
   Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
   hole_check.If(check);
   hole_check.Then();
-  environment()->Push(BuildThrowReferenceError(variable, bailout_id));
+  Node* error = BuildThrowReferenceError(variable, bailout_id);
+  environment()->Push(error);
   hole_check.Else();
   environment()->Push(not_hole);
   hole_check.End();
@@ -2538,6 +2729,28 @@ Node* AstGraphBuilder::BuildHoleCheckThrow(Node* value, Variable* variable,
 }
 
 
+Node* AstGraphBuilder::BuildThrowIfStaticPrototype(Node* name,
+                                                   BailoutId bailout_id) {
+  IfBuilder prototype_check(this);
+  Node* prototype_string =
+      jsgraph()->Constant(isolate()->factory()->prototype_string());
+  Node* check = NewNode(javascript()->StrictEqual(), name, prototype_string);
+  prototype_check.If(check);
+  prototype_check.Then();
+  {
+    const Operator* op =
+        javascript()->CallRuntime(Runtime::kThrowStaticPrototypeError, 0);
+    Node* call = NewNode(op);
+    PrepareFrameState(call, bailout_id);
+    environment()->Push(call);
+  }
+  prototype_check.Else();
+  environment()->Push(name);
+  prototype_check.End();
+  return environment()->Pop();
+}
+
+
 Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
                                          BailoutId bailout_id,
                                          const VectorSlotPair& feedback,
@@ -2548,10 +2761,9 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
     case Variable::UNALLOCATED: {
       // Global var, const, or let variable.
       Node* global = BuildLoadGlobalObject();
-      Unique<Name> name = MakeUnique(variable->name());
-      const Operator* op =
-          javascript()->LoadNamed(name, feedback, contextual_mode);
-      Node* node = NewNode(op, global);
+      Handle<Name> name = variable->name();
+      Node* node = BuildNamedLoad(global, name, feedback,
+                                  TypeFeedbackId::None(), contextual_mode);
       PrepareFrameState(node, bailout_id, OutputFrameStateCombine::Push());
       return node;
     }
@@ -2657,9 +2869,9 @@ Node* AstGraphBuilder::BuildVariableAssignment(
     case Variable::UNALLOCATED: {
       // Global var, const, or let variable.
       Node* global = BuildLoadGlobalObject();
-      Unique<Name> name = MakeUnique(variable->name());
-      const Operator* op = javascript()->StoreNamed(language_mode(), name);
-      Node* store = NewNode(op, global, value);
+      Handle<Name> name = variable->name();
+      Node* store =
+          BuildNamedStore(global, name, value, TypeFeedbackId::None());
       PrepareFrameState(store, bailout_id, combine);
       return store;
     }
@@ -2673,7 +2885,7 @@ Node* AstGraphBuilder::BuildVariableAssignment(
           value = BuildHoleCheckSilent(current, value, current);
         }
       } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
-        // Non-initializing assignments to legacy const is
+        // Non-initializing assignment to legacy const is
         // - exception in strict mode.
         // - ignored in sloppy mode.
         if (is_strict(language_mode())) {
@@ -2692,7 +2904,13 @@ Node* AstGraphBuilder::BuildVariableAssignment(
           value = BuildHoleCheckThrow(current, variable, value, bailout_id);
         }
       } else if (mode == CONST && op != Token::INIT_CONST) {
-        // Non-initializing assignments to const is exception in all modes.
+        // Assignment to const is exception in all modes.
+        Node* current = environment()->Lookup(variable);
+        if (current->op() == the_hole->op()) {
+          return BuildThrowReferenceError(variable, bailout_id);
+        } else if (value->opcode() == IrOpcode::kPhi) {
+          BuildHoleCheckThrow(current, variable, value, bailout_id);
+        }
         return BuildThrowConstAssignError(bailout_id);
       }
       environment()->Bind(variable, value);
@@ -2707,7 +2925,7 @@ Node* AstGraphBuilder::BuildVariableAssignment(
         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
+        // Non-initializing assignment to legacy const is
         // - exception in strict mode.
         // - ignored in sloppy mode.
         if (is_strict(language_mode())) {
@@ -2721,7 +2939,11 @@ Node* AstGraphBuilder::BuildVariableAssignment(
         Node* current = NewNode(op, current_context());
         value = BuildHoleCheckThrow(current, variable, value, bailout_id);
       } else if (mode == CONST && op != Token::INIT_CONST) {
-        // Non-initializing assignments to const is exception in all modes.
+        // Assignment to const is exception in all modes.
+        const Operator* op =
+            javascript()->LoadContext(depth, variable->index(), false);
+        Node* current = NewNode(op, current_context());
+        BuildHoleCheckThrow(current, variable, value, bailout_id);
         return BuildThrowConstAssignError(bailout_id);
       }
       const Operator* op = javascript()->StoreContext(depth, variable->index());
@@ -2745,10 +2967,48 @@ Node* AstGraphBuilder::BuildVariableAssignment(
 }
 
 
+static inline Node* Record(JSTypeFeedbackTable* js_type_feedback, Node* node,
+                           TypeFeedbackId id) {
+  if (js_type_feedback) js_type_feedback->Record(node, id);
+  return node;
+}
+
+
+Node* AstGraphBuilder::BuildKeyedLoad(Node* object, Node* key,
+                                      const VectorSlotPair& feedback,
+                                      TypeFeedbackId id) {
+  const Operator* op = javascript()->LoadProperty(feedback);
+  return Record(js_type_feedback_, NewNode(op, object, key), id);
+}
+
+
+Node* AstGraphBuilder::BuildNamedLoad(Node* object, Handle<Name> name,
+                                      const VectorSlotPair& feedback,
+                                      TypeFeedbackId id, ContextualMode mode) {
+  const Operator* op =
+      javascript()->LoadNamed(MakeUnique(name), feedback, mode);
+  return Record(js_type_feedback_, NewNode(op, object), id);
+}
+
+
+Node* AstGraphBuilder::BuildKeyedStore(Node* object, Node* key, Node* value,
+                                       TypeFeedbackId id) {
+  const Operator* op = javascript()->StoreProperty(language_mode());
+  return Record(js_type_feedback_, NewNode(op, object, key, value), id);
+}
+
+
+Node* AstGraphBuilder::BuildNamedStore(Node* object, Handle<Name> name,
+                                       Node* value, TypeFeedbackId id) {
+  const Operator* op =
+      javascript()->StoreNamed(language_mode(), MakeUnique(name));
+  return Record(js_type_feedback_, NewNode(op, object, value), id);
+}
+
+
 Node* AstGraphBuilder::BuildLoadObjectField(Node* object, int offset) {
-  Node* field_load = NewNode(jsgraph()->machine()->Load(kMachAnyTagged), object,
-                             jsgraph()->Int32Constant(offset - kHeapObjectTag));
-  return field_load;
+  return NewNode(jsgraph()->machine()->Load(kMachAnyTagged), object,
+                 jsgraph()->IntPtrConstant(offset - kHeapObjectTag));
 }
 
 
@@ -2775,6 +3035,23 @@ Node* AstGraphBuilder::BuildLoadGlobalProxy() {
 }
 
 
+Node* AstGraphBuilder::BuildLoadExternal(ExternalReference reference,
+                                         MachineType type) {
+  return NewNode(jsgraph()->machine()->Load(type),
+                 jsgraph()->ExternalConstant(reference),
+                 jsgraph()->IntPtrConstant(0));
+}
+
+
+Node* AstGraphBuilder::BuildStoreExternal(ExternalReference reference,
+                                          MachineType type, Node* value) {
+  StoreRepresentation representation(type, kNoWriteBarrier);
+  return NewNode(jsgraph()->machine()->Store(representation),
+                 jsgraph()->ExternalConstant(reference),
+                 jsgraph()->IntPtrConstant(0), value);
+}
+
+
 Node* AstGraphBuilder::BuildToBoolean(Node* input) {
   // TODO(titzer): This should be in a JSOperatorReducer.
   switch (input->opcode()) {
@@ -2813,17 +3090,24 @@ Node* AstGraphBuilder::BuildToName(Node* input, BailoutId bailout_id) {
 Node* AstGraphBuilder::BuildSetHomeObject(Node* value, Node* home_object,
                                           Expression* expr) {
   if (!FunctionLiteral::NeedsHomeObject(expr)) return value;
-  Unique<Name> name = MakeUnique(isolate()->factory()->home_object_symbol());
-  const Operator* op = javascript()->StoreNamed(language_mode(), name);
-  Node* store = NewNode(op, value, home_object);
+  Handle<Name> name = isolate()->factory()->home_object_symbol();
+  Node* store =
+      BuildNamedStore(value, name, home_object, TypeFeedbackId::None());
   PrepareFrameState(store, BailoutId::None());
   return store;
 }
 
 
+Node* AstGraphBuilder::BuildThrowError(Node* exception, BailoutId bailout_id) {
+  const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1);
+  Node* call = NewNode(op, exception);
+  PrepareFrameState(call, bailout_id);
+  return call;
+}
+
+
 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()->CallRuntime(Runtime::kThrowReferenceError, 1);
@@ -2834,7 +3118,6 @@ Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable,
 
 
 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);
@@ -2902,24 +3185,6 @@ Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) {
 }
 
 
-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;
-}
-
-
 bool AstGraphBuilder::CheckOsrEntry(IterationStatement* stmt) {
   if (info()->osr_ast_id() == stmt->OsrEntryId()) {
     info()->set_osr_expr_stack_height(std::max(
@@ -2932,11 +3197,31 @@ bool AstGraphBuilder::CheckOsrEntry(IterationStatement* stmt) {
 
 void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id,
                                         OutputFrameStateCombine combine) {
-  if (OperatorProperties::HasFrameStateInput(node->op())) {
-    DCHECK(NodeProperties::GetFrameStateInput(node)->opcode() ==
-           IrOpcode::kDead);
+  if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
+    DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
+
+    DCHECK_EQ(IrOpcode::kDead,
+              NodeProperties::GetFrameStateInput(node, 0)->opcode());
     NodeProperties::ReplaceFrameStateInput(
-        node, environment()->Checkpoint(ast_id, combine));
+        node, 0, environment()->Checkpoint(ast_id, combine));
+  }
+}
+
+
+void AstGraphBuilder::PrepareFrameStateAfterAndBefore(
+    Node* node, BailoutId ast_id, OutputFrameStateCombine combine,
+    Node* frame_state_before) {
+  if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
+    DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node->op()));
+
+    DCHECK_EQ(IrOpcode::kDead,
+              NodeProperties::GetFrameStateInput(node, 0)->opcode());
+    NodeProperties::ReplaceFrameStateInput(
+        node, 0, environment()->Checkpoint(ast_id, combine));
+
+    DCHECK_EQ(IrOpcode::kDead,
+              NodeProperties::GetFrameStateInput(node, 1)->opcode());
+    NodeProperties::ReplaceFrameStateInput(node, 1, frame_state_before);
   }
 }
 
@@ -2963,7 +3248,7 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
   DCHECK(op->ValueInputCount() == value_input_count);
 
   bool has_context = OperatorProperties::HasContextInput(op);
-  bool has_framestate = OperatorProperties::HasFrameStateInput(op);
+  int frame_state_count = OperatorProperties::GetFrameStateInputCount(op);
   bool has_control = op->ControlInputCount() == 1;
   bool has_effect = op->EffectInputCount() == 1;
 
@@ -2971,12 +3256,13 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
   DCHECK(op->EffectInputCount() < 2);
 
   Node* result = NULL;
-  if (!has_context && !has_framestate && !has_control && !has_effect) {
+  if (!has_context && frame_state_count == 0 && !has_control && !has_effect) {
     result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
   } else {
+    bool inside_try_scope = try_nesting_level_ > 0;
     int input_count_with_deps = value_input_count;
     if (has_context) ++input_count_with_deps;
-    if (has_framestate) ++input_count_with_deps;
+    input_count_with_deps += frame_state_count;
     if (has_control) ++input_count_with_deps;
     if (has_effect) ++input_count_with_deps;
     Node** buffer = EnsureInputBufferSize(input_count_with_deps);
@@ -2985,7 +3271,7 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
     if (has_context) {
       *current_input++ = current_context();
     }
-    if (has_framestate) {
+    for (int i = 0; i < frame_state_count; i++) {
       // The frame state will be inserted later. Here we misuse
       // the {DeadControl} node as a sentinel to be later overwritten
       // with the real frame state.
@@ -3001,9 +3287,22 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
     if (has_effect) {
       environment_->UpdateEffectDependency(result);
     }
-    if (result->op()->ControlOutputCount() > 0 &&
-        !environment()->IsMarkedAsUnreachable()) {
-      environment_->UpdateControlDependency(result);
+    if (!environment()->IsMarkedAsUnreachable()) {
+      // Update the current control dependency for control-producing nodes.
+      if (NodeProperties::IsControl(result)) {
+        environment_->UpdateControlDependency(result);
+      }
+      // Add implicit exception continuation for throwing nodes.
+      if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) {
+        Node* on_exception = graph()->NewNode(common()->IfException(), result);
+        environment_->UpdateControlDependency(on_exception);
+        execution_control()->ThrowValue(result);
+      }
+      // Add implicit success continuation for throwing nodes.
+      if (!result->op()->HasProperty(Operator::kNoThrow)) {
+        Node* on_success = graph()->NewNode(common()->IfSuccess(), result);
+        environment_->UpdateControlDependency(on_success);
+      }
     }
   }
 
@@ -3034,6 +3333,7 @@ void AstGraphBuilder::Environment::Merge(Environment* other) {
   if (this->IsMarkedAsUnreachable()) {
     Node* other_control = other->control_dependency_;
     Node* inputs[] = {other_control};
+    liveness_block_ = other->liveness_block_;
     control_dependency_ =
         graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true);
     effect_dependency_ = other->effect_dependency_;
@@ -3045,6 +3345,18 @@ void AstGraphBuilder::Environment::Merge(Environment* other) {
     return;
   }
 
+  // Record the merge for the local variable liveness calculation.
+  // Unfortunately, we have to mirror the logic in the MergeControl method:
+  // connect before merge or loop, or create a new merge otherwise.
+  if (FLAG_analyze_environment_liveness) {
+    if (GetControlDependency()->opcode() != IrOpcode::kLoop &&
+        GetControlDependency()->opcode() != IrOpcode::kMerge) {
+      liveness_block_ =
+          builder_->liveness_analyzer()->NewBlock(liveness_block());
+    }
+    liveness_block()->AddPredecessor(other->liveness_block());
+  }
+
   // Create a merge of the control dependencies of both environments and update
   // the current environment's control dependency accordingly.
   Node* control = builder_->MergeControl(this->GetControlDependency(),
index ebeb6c6..f752077 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "src/ast.h"
 #include "src/compiler/js-graph.h"
+#include "src/compiler/liveness-analyzer.h"
+#include "src/compiler/state-values-utils.h"
 
 namespace v8 {
 namespace internal {
@@ -17,6 +19,7 @@ namespace compiler {
 
 class ControlBuilder;
 class Graph;
+class JSTypeFeedbackTable;
 class LoopAssignmentAnalysis;
 class LoopBuilder;
 class Node;
@@ -28,10 +31,11 @@ class Node;
 class AstGraphBuilder : public AstVisitor {
  public:
   AstGraphBuilder(Zone* local_zone, CompilationInfo* info, JSGraph* jsgraph,
-                  LoopAssignmentAnalysis* loop_assignment = NULL);
+                  LoopAssignmentAnalysis* loop_assignment = NULL,
+                  JSTypeFeedbackTable* js_type_feedback = NULL);
 
   // Creates a graph by visiting the entire AST.
-  bool CreateGraph(bool constant_context);
+  bool CreateGraph(bool constant_context, bool stack_check = true);
 
   // Helpers to create new control nodes.
   Node* NewIfTrue() { return NewNode(common()->IfTrue()); }
@@ -84,6 +88,9 @@ class AstGraphBuilder : public AstVisitor {
   SetOncePointer<Node> function_closure_;
   SetOncePointer<Node> function_context_;
 
+  // Tracks how many try-blocks are currently entered.
+  int try_nesting_level_;
+
   // Temporary storage for building node input lists.
   int input_buffer_size_;
   Node** input_buffer_;
@@ -94,6 +101,15 @@ class AstGraphBuilder : public AstVisitor {
   // Result of loop assignment analysis performed before graph creation.
   LoopAssignmentAnalysis* loop_assignment_analysis_;
 
+  // Cache for StateValues nodes for frame states.
+  StateValuesCache state_values_cache_;
+
+  // Analyzer of local variable liveness.
+  LivenessAnalyzer liveness_analyzer_;
+
+  // Type feedback table.
+  JSTypeFeedbackTable* js_type_feedback_;
+
   // Growth increment for the temporary buffer used to construct input lists to
   // new nodes.
   static const int kInputBufferSizeIncrement = 64;
@@ -114,6 +130,7 @@ class AstGraphBuilder : public AstVisitor {
   Scope* current_scope() const;
   Node* current_context() const;
   Node* exit_control() const { return exit_control_; }
+  LivenessAnalyzer* liveness_analyzer() { return &liveness_analyzer_; }
 
   void set_environment(Environment* env) { environment_ = env; }
   void set_ast_context(AstContext* ctx) { ast_context_ = ctx; }
@@ -122,7 +139,7 @@ class AstGraphBuilder : public AstVisitor {
   void set_exit_control(Node* exit) { exit_control_ = exit; }
 
   // Create the main graph body by visiting the AST.
-  void CreateGraphBody();
+  void CreateGraphBody(bool stack_check);
 
   // Create the node that represents the outer context of the function.
   void CreateFunctionContext(bool constant_context);
@@ -191,11 +208,39 @@ class AstGraphBuilder : public AstVisitor {
   // Helper to indicate a node exits the function body.
   void UpdateControlDependencyToLeaveFunction(Node* exit);
 
-  //
+  // Builds deoptimization for a given node.
+  void PrepareFrameState(
+      Node* node, BailoutId ast_id,
+      OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore());
+  void PrepareFrameStateAfterAndBefore(Node* node, BailoutId ast_id,
+                                       OutputFrameStateCombine combine,
+                                       Node* frame_state_before);
+
+  BitVector* GetVariablesAssignedInLoop(IterationStatement* stmt);
+
+  // Check if the given statement is an OSR entry.
+  // If so, record the stack height into the compilation and return {true}.
+  bool CheckOsrEntry(IterationStatement* stmt);
+
+  // Computes local variable liveness and replaces dead variables in
+  // frame states with the undefined values.
+  void ClearNonLiveSlotsInFrameStates();
+
+  // Helper to wrap a Handle<T> into a Unique<T>.
+  template <class T>
+  Unique<T> MakeUnique(Handle<T> object) {
+    return Unique<T>::CreateUninitialized(object);
+  }
+
+  Node** EnsureInputBufferSize(int size);
+
+  // Named and keyed loads require a VectorSlotPair for successful lowering.
+  VectorSlotPair CreateVectorSlotPair(FeedbackVectorICSlot slot) const;
+
+  // ===========================================================================
   // The following build methods all generate graph fragments and return one
   // resulting node. The operand stack height remains the same, variables and
   // other dependencies tracked by the environment might be mutated though.
-  //
 
   // Builder to create a receiver check for sloppy mode.
   Node* BuildPatchReceiverToGlobalProxy(Node* receiver);
@@ -221,6 +266,17 @@ class AstGraphBuilder : public AstVisitor {
                           const VectorSlotPair& feedback,
                           ContextualMode mode = CONTEXTUAL);
 
+  // Builders for property loads and stores.
+  Node* BuildKeyedLoad(Node* receiver, Node* key,
+                       const VectorSlotPair& feedback, TypeFeedbackId id);
+  Node* BuildNamedLoad(Node* receiver, Handle<Name> name,
+                       const VectorSlotPair& feedback, TypeFeedbackId id,
+                       ContextualMode mode = NOT_CONTEXTUAL);
+  Node* BuildKeyedStore(Node* receiver, Node* key, Node* value,
+                        TypeFeedbackId id);
+  Node* BuildNamedStore(Node* receiver, Handle<Name>, Node* value,
+                        TypeFeedbackId id);
+
   // Builders for accessing the function context.
   Node* BuildLoadBuiltinsObject();
   Node* BuildLoadGlobalObject();
@@ -228,6 +284,10 @@ class AstGraphBuilder : public AstVisitor {
   Node* BuildLoadClosure();
   Node* BuildLoadObjectField(Node* object, int offset);
 
+  // Builders for accessing external references.
+  Node* BuildLoadExternal(ExternalReference ref, MachineType type);
+  Node* BuildStoreExternal(ExternalReference ref, MachineType type, Node* val);
+
   // Builders for automatic type conversion.
   Node* BuildToBoolean(Node* value);
   Node* BuildToName(Node* value, BailoutId bailout_id);
@@ -237,6 +297,7 @@ class AstGraphBuilder : public AstVisitor {
   Node* BuildSetHomeObject(Node* value, Node* home_object, Expression* expr);
 
   // Builders for error reporting at runtime.
+  Node* BuildThrowError(Node* exception, BailoutId bailout_id);
   Node* BuildThrowReferenceError(Variable* var, BailoutId bailout_id);
   Node* BuildThrowConstAssignError(BailoutId bailout_id);
 
@@ -245,6 +306,9 @@ class AstGraphBuilder : public AstVisitor {
   Node* BuildHoleCheckThrow(Node* value, Variable* var, Node* not_hole,
                             BailoutId bailout_id);
 
+  // Builders for conditional errors.
+  Node* BuildThrowIfStaticPrototype(Node* name, BailoutId bailout_id);
+
   // Builders for non-local control flow.
   Node* BuildReturn(Node* return_value);
   Node* BuildThrow(Node* exception_value);
@@ -252,28 +316,17 @@ class AstGraphBuilder : public AstVisitor {
   // Builders for binary operations.
   Node* BuildBinaryOp(Node* left, Node* right, Token::Value op);
 
-  // Builder for stack-check guards.
-  Node* BuildStackCheck();
-
-  // Check if the given statement is an OSR entry.
-  // If so, record the stack height into the compilation and return {true}.
-  bool CheckOsrEntry(IterationStatement* stmt);
-
-  // Helper to wrap a Handle<T> into a Unique<T>.
-  template <class T>
-  Unique<T> MakeUnique(Handle<T> object) {
-    return Unique<T>::CreateUninitialized(object);
-  }
-
-  Node** EnsureInputBufferSize(int size);
-
-  // 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);
 
+  // ===========================================================================
+  // The following visitation methods all recursively visit a subtree of the
+  // underlying AST and extent the graph. The operand stack is mutated in a way
+  // consistent with other compilers:
+  //  - Expressions pop operands and push result, depending on {AstContext}.
+  //  - Statements keep the operand stack balanced.
+
   // Visit statements.
   void VisitIfNotNull(Statement* stmt);
 
@@ -287,7 +340,7 @@ class AstGraphBuilder : public AstVisitor {
   void VisitForValues(ZoneList<Expression*>* exprs);
 
   // Common for all IterationStatement bodies.
-  void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop, int);
+  void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop);
 
   // Dispatched from VisitCallRuntime.
   void VisitCallJSRuntime(CallRuntime* expr);
@@ -311,13 +364,6 @@ class AstGraphBuilder : public AstVisitor {
   // Dispatched from VisitClassLiteral.
   void VisitClassLiteralContents(ClassLiteral* expr);
 
-  // Builds deoptimization for a given node.
-  void PrepareFrameState(
-      Node* node, BailoutId ast_id,
-      OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore());
-
-  BitVector* GetVariablesAssignedInLoop(IterationStatement* stmt);
-
   DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
   DISALLOW_COPY_AND_ASSIGN(AstGraphBuilder);
 };
@@ -342,26 +388,10 @@ class AstGraphBuilder::Environment : public ZoneObject {
            locals_count_;
   }
 
-  // Operations on parameter or local variables. The parameter indices are
-  // shifted by 1 (receiver is parameter index -1 but environment index 0).
-  void Bind(Variable* variable, Node* node) {
-    DCHECK(variable->IsStackAllocated());
-    if (variable->IsParameter()) {
-      values()->at(variable->index() + 1) = node;
-    } else {
-      DCHECK(variable->IsStackLocal());
-      values()->at(variable->index() + parameters_count_) = node;
-    }
-  }
-  Node* Lookup(Variable* variable) {
-    DCHECK(variable->IsStackAllocated());
-    if (variable->IsParameter()) {
-      return values()->at(variable->index() + 1);
-    } else {
-      DCHECK(variable->IsStackLocal());
-      return values()->at(variable->index() + parameters_count_);
-    }
-  }
+  // Operations on parameter or local variables.
+  void Bind(Variable* variable, Node* node);
+  Node* Lookup(Variable* variable);
+  void MarkAllLocalsLive();
 
   Node* Context() const { return contexts_.back(); }
   void PushContext(Node* context) { contexts()->push_back(context); }
@@ -397,10 +427,16 @@ class AstGraphBuilder::Environment : public ZoneObject {
     DCHECK(depth >= 0 && depth <= stack_height());
     values()->erase(values()->end() - depth, values()->end());
   }
+  void Trim(int trim_to_height) {
+    int depth = stack_height() - trim_to_height;
+    DCHECK(depth >= 0 && depth <= stack_height());
+    values()->erase(values()->end() - depth, values()->end());
+  }
 
   // Preserve a checkpoint of the environment for the IR graph. Any
   // further mutation of the environment will not affect checkpoints.
-  Node* Checkpoint(BailoutId ast_id, OutputFrameStateCombine combine);
+  Node* Checkpoint(BailoutId ast_id, OutputFrameStateCombine combine =
+                                         OutputFrameStateCombine::Ignore());
 
   // Control dependency tracked by this environment.
   Node* GetControlDependency() { return control_dependency_; }
@@ -438,7 +474,7 @@ class AstGraphBuilder::Environment : public ZoneObject {
   // Copies this environment at a loop header control-flow point.
   Environment* CopyForLoop(BitVector* assigned, bool is_osr = false) {
     PrepareForLoop(assigned, is_osr);
-    return Copy();
+    return CopyAndShareLiveness();
   }
 
   int ContextStackDepth() { return static_cast<int>(contexts_.size()); }
@@ -447,6 +483,7 @@ class AstGraphBuilder::Environment : public ZoneObject {
   AstGraphBuilder* builder_;
   int parameters_count_;
   int locals_count_;
+  LivenessAnalyzerBlock* liveness_block_;
   NodeVector values_;
   NodeVector contexts_;
   Node* control_dependency_;
@@ -455,15 +492,18 @@ class AstGraphBuilder::Environment : public ZoneObject {
   Node* locals_node_;
   Node* stack_node_;
 
-  explicit Environment(const Environment* copy);
+  explicit Environment(Environment* copy);
   Environment* Copy() { return new (zone()) Environment(this); }
+  Environment* CopyAndShareLiveness();
   void UpdateStateValues(Node** state_values, int offset, int count);
+  void UpdateStateValuesWithCache(Node** state_values, int offset, int count);
   Zone* zone() const { return builder_->local_zone(); }
   Graph* graph() const { return builder_->graph(); }
   AstGraphBuilder* builder() const { return builder_; }
   CommonOperatorBuilder* common() { return builder_->common(); }
   NodeVector* values() { return &values_; }
   NodeVector* contexts() { return &contexts_; }
+  LivenessAnalyzerBlock* liveness_block() { return liveness_block_; }
 
   // Prepare environment to be used as loop header.
   void PrepareForLoop(BitVector* assigned, bool is_osr = false);
index c81d548..4028b94 100644 (file)
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "src/compiler/ast-loop-assignment-analyzer.h"
+#include "src/compiler.h"
 #include "src/parser.h"
 
 namespace v8 {
index 54f9d6b..00291bb 100644 (file)
@@ -55,8 +55,7 @@ BasicBlockProfiler::Data* BasicBlockInstrumentor::Instrument(
   BasicBlockProfiler::Data* data =
       info->isolate()->GetOrCreateBasicBlockProfiler()->NewData(n_blocks);
   // Set the function name.
-  if (!info->shared_info().is_null() &&
-      info->shared_info()->name()->IsString()) {
+  if (info->has_shared_info() && info->shared_info()->name()->IsString()) {
     std::ostringstream os;
     String::cast(info->shared_info()->name())->PrintUC16(os);
     data->SetFunctionName(&os);
index 0057b10..81af22b 100644 (file)
@@ -5,7 +5,6 @@
 #include "src/compiler/change-lowering.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"
@@ -47,25 +46,17 @@ Reduction ChangeLowering::Reduce(Node* node) {
 
 
 Node* ChangeLowering::HeapNumberValueIndexConstant() {
-  STATIC_ASSERT(HeapNumber::kValueOffset % kPointerSize == 0);
-  const int heap_number_value_offset =
-      ((HeapNumber::kValueOffset / kPointerSize) * (machine()->Is64() ? 8 : 4));
-  return jsgraph()->IntPtrConstant(heap_number_value_offset - kHeapObjectTag);
+  return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag);
 }
 
 
 Node* ChangeLowering::SmiMaxValueConstant() {
-  const int smi_value_size = machine()->Is32() ? SmiTagging<4>::SmiValueSize()
-                                               : SmiTagging<8>::SmiValueSize();
-  return jsgraph()->Int32Constant(
-      -(static_cast<int>(0xffffffffu << (smi_value_size - 1)) + 1));
+  return jsgraph()->Int32Constant(Smi::kMaxValue);
 }
 
 
 Node* ChangeLowering::SmiShiftBitsConstant() {
-  const int smi_shift_size = machine()->Is32() ? SmiTagging<4>::SmiShiftSize()
-                                               : SmiTagging<8>::SmiShiftSize();
-  return jsgraph()->IntPtrConstant(smi_shift_size + kSmiTagSize);
+  return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
 }
 
 
@@ -73,14 +64,17 @@ Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node* control) {
   // 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(
-      isolate(), jsgraph()->zone(), callable.descriptor(), 0,
-      CallDescriptor::kNoFlags);
   Node* target = jsgraph()->HeapConstant(callable.code());
   Node* context = jsgraph()->NoContextConstant();
   Node* effect = graph()->NewNode(common()->ValueEffect(1), value);
-  Node* heap_number = graph()->NewNode(common()->Call(descriptor), target,
-                                       context, effect, control);
+  if (!allocate_heap_number_operator_.is_set()) {
+    CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
+        isolate(), jsgraph()->zone(), callable.descriptor(), 0,
+        CallDescriptor::kNoFlags, Operator::kNoThrow);
+    allocate_heap_number_operator_.set(common()->Call(descriptor));
+  }
+  Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(),
+                                       target, context, effect, control);
   Node* store = graph()->NewNode(
       machine()->Store(StoreRepresentation(kMachFloat64, kNoWriteBarrier)),
       heap_number, HeapNumberValueIndexConstant(), value, heap_number, control);
@@ -93,6 +87,14 @@ Node* ChangeLowering::ChangeInt32ToFloat64(Node* value) {
 }
 
 
+Node* ChangeLowering::ChangeInt32ToSmi(Node* value) {
+  if (machine()->Is64()) {
+    value = graph()->NewNode(machine()->ChangeInt32ToInt64(), value);
+  }
+  return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant());
+}
+
+
 Node* ChangeLowering::ChangeSmiToFloat64(Node* value) {
   return ChangeInt32ToFloat64(ChangeSmiToInt32(value));
 }
@@ -135,64 +137,80 @@ Node* ChangeLowering::TestNotSmi(Node* value) {
 }
 
 
-Node* ChangeLowering::Uint32LessThanOrEqual(Node* lhs, Node* rhs) {
-  return graph()->NewNode(machine()->Uint32LessThanOrEqual(), lhs, rhs);
-}
-
-
-Reduction ChangeLowering::ChangeBitToBool(Node* val, Node* control) {
-  MachineType const type = static_cast<MachineType>(kTypeBool | kRepTagged);
-  return Replace(graph()->NewNode(common()->Select(type), val,
+Reduction ChangeLowering::ChangeBitToBool(Node* value, Node* control) {
+  return Replace(graph()->NewNode(common()->Select(kMachAnyTagged), value,
                                   jsgraph()->TrueConstant(),
                                   jsgraph()->FalseConstant()));
 }
 
 
-Reduction ChangeLowering::ChangeBoolToBit(Node* val) {
-  return Replace(
-      graph()->NewNode(machine()->WordEqual(), val, jsgraph()->TrueConstant()));
+Reduction ChangeLowering::ChangeBoolToBit(Node* value) {
+  return Replace(graph()->NewNode(machine()->WordEqual(), value,
+                                  jsgraph()->TrueConstant()));
 }
 
 
-Reduction ChangeLowering::ChangeFloat64ToTagged(Node* val, Node* control) {
-  return Replace(AllocateHeapNumberWithValue(val, control));
+Reduction ChangeLowering::ChangeFloat64ToTagged(Node* value, Node* control) {
+  return Replace(AllocateHeapNumberWithValue(value, 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::Signed31())) {
-    return Replace(
-        graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant()));
+  if (machine()->Is64() ||
+      NodeProperties::GetBounds(value).upper->Is(Type::SignedSmall())) {
+    return Replace(ChangeInt32ToSmi(value));
   }
 
   Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value);
+
   Node* ovf = graph()->NewNode(common()->Projection(1), add);
+  Node* branch =
+      graph()->NewNode(common()->Branch(BranchHint::kFalse), ovf, control);
+
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* vtrue =
+      AllocateHeapNumberWithValue(ChangeInt32ToFloat64(value), if_true);
+
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  Node* vfalse = 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), vtrue, vfalse, merge);
 
-  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)));
+  return Replace(phi);
 }
 
 
 Reduction ChangeLowering::ChangeTaggedToUI32(Node* value, Node* control,
                                              Signedness signedness) {
+  if (NodeProperties::GetBounds(value).upper->Is(Type::TaggedSigned())) {
+    return Replace(ChangeSmiToInt32(value));
+  }
+
   const MachineType type = (signedness == kSigned) ? kMachInt32 : kMachUint32;
   const Operator* op = (signedness == kSigned)
                            ? machine()->ChangeFloat64ToInt32()
                            : machine()->ChangeFloat64ToUint32();
-  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)));
+
+  if (NodeProperties::GetBounds(value).upper->Is(Type::TaggedPointer())) {
+    return Replace(graph()->NewNode(op, LoadHeapNumberValue(value, control)));
+  }
+
+  Node* check = TestNotSmi(value);
+  Node* branch =
+      graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
+
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* vtrue = graph()->NewNode(op, LoadHeapNumberValue(value, if_true));
+
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  Node* vfalse = ChangeSmiToInt32(value);
+
+  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+  Node* phi = graph()->NewNode(common()->Phi(type, 2), vtrue, vfalse, merge);
+
+  return Replace(phi);
 }
 
 
@@ -202,6 +220,7 @@ 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::IsControlEdge(edge)) continue;
     if (NodeProperties::IsEffectEdge(edge)) continue;
     DCHECK(NodeProperties::IsValueEdge(edge));
     if (!first) return false;
@@ -225,48 +244,88 @@ Reduction ChangeLowering::ChangeTaggedToFloat64(Node* value, Node* control) {
     Node* const effect = NodeProperties::GetEffectInput(value);
     Node* const control = NodeProperties::GetControlInput(value);
 
-    Diamond d1(graph(), common(), TestNotSmi(object), BranchHint::kFalse);
-    d1.Chain(control);
+    const Operator* merge_op = common()->Merge(2);
+    const Operator* ephi_op = common()->EffectPhi(2);
+    const Operator* phi_op = common()->Phi(kMachFloat64, 2);
 
-    Node* number =
-        OperatorProperties::HasFrameStateInput(value->op())
+    Node* check1 = TestNotSmi(object);
+    Node* branch1 =
+        graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control);
+
+    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+    Node* vtrue1 =
+        FLAG_turbo_deoptimization
             ? graph()->NewNode(value->op(), object, context,
-                               NodeProperties::GetFrameStateInput(value),
-                               effect, d1.if_true)
-            : 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);
-      }
+                               NodeProperties::GetFrameStateInput(value, 0),
+                               effect, if_true1)
+            : graph()->NewNode(value->op(), object, context, effect, if_true1);
+    Node* etrue1 = vtrue1;
+    {
+      Node* check2 = TestNotSmi(vtrue1);
+      Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_true1);
+
+      Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
+      Node* vtrue2 = LoadHeapNumberValue(vtrue1, if_true2);
+
+      Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
+      Node* vfalse2 = ChangeSmiToFloat64(vtrue1);
+
+      if_true1 = graph()->NewNode(merge_op, if_true2, if_false2);
+      vtrue1 = graph()->NewNode(phi_op, vtrue2, vfalse2, if_true1);
     }
+
+    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+    Node* vfalse1 = ChangeSmiToFloat64(object);
+    Node* efalse1 = effect;
+
+    Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
+    Node* ephi1 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
+    Node* phi1 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
+
+    NodeProperties::ReplaceWithValue(value, phi1, ephi1, merge1);
     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));
+  Node* check = TestNotSmi(value);
+  Node* branch =
+      graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
+
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* vtrue = LoadHeapNumberValue(value, if_true);
+
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  Node* vfalse = ChangeSmiToFloat64(value);
+
+  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+  Node* phi =
+      graph()->NewNode(common()->Phi(kMachFloat64, 2), vtrue, vfalse, 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)));
+  if (NodeProperties::GetBounds(value).upper->Is(Type::UnsignedSmall())) {
+    return Replace(ChangeUint32ToSmi(value));
+  }
+
+  Node* check = graph()->NewNode(machine()->Uint32LessThanOrEqual(), value,
+                                 SmiMaxValueConstant());
+  Node* branch =
+      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
+
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* vtrue = ChangeUint32ToSmi(value);
+
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  Node* vfalse =
+      AllocateHeapNumberWithValue(ChangeUint32ToFloat64(value), if_false);
+
+  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+  Node* phi =
+      graph()->NewNode(common()->Phi(kMachAnyTagged, 2), vtrue, vfalse, merge);
+
+  return Replace(phi);
 }
 
 
index 40a3e15..0d498cc 100644 (file)
@@ -16,6 +16,7 @@ class CommonOperatorBuilder;
 class JSGraph;
 class Linkage;
 class MachineOperatorBuilder;
+class Operator;
 
 class ChangeLowering FINAL : public Reducer {
  public:
@@ -31,13 +32,13 @@ class ChangeLowering FINAL : public Reducer {
 
   Node* AllocateHeapNumberWithValue(Node* value, Node* control);
   Node* ChangeInt32ToFloat64(Node* value);
+  Node* ChangeInt32ToSmi(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* value, Node* control);
   Reduction ChangeBoolToBit(Node* value);
@@ -54,7 +55,8 @@ class ChangeLowering FINAL : public Reducer {
   CommonOperatorBuilder* common() const;
   MachineOperatorBuilder* machine() const;
 
-  JSGraph* jsgraph_;
+  JSGraph* const jsgraph_;
+  SetOncePointer<const Operator> allocate_heap_number_operator_;
 };
 
 }  // namespace compiler
index 129f940..74233ac 100644 (file)
@@ -27,49 +27,53 @@ class InstructionOperandConverter {
 
   // -- Instruction operand accesses with conversions --------------------------
 
-  Register InputRegister(int index) {
+  Register InputRegister(size_t index) {
     return ToRegister(instr_->InputAt(index));
   }
 
-  DoubleRegister InputDoubleRegister(int index) {
+  DoubleRegister InputDoubleRegister(size_t index) {
     return ToDoubleRegister(instr_->InputAt(index));
   }
 
-  double InputDouble(int index) { return ToDouble(instr_->InputAt(index)); }
+  double InputDouble(size_t index) { return ToDouble(instr_->InputAt(index)); }
 
-  int32_t InputInt32(int index) {
+  int32_t InputInt32(size_t index) {
     return ToConstant(instr_->InputAt(index)).ToInt32();
   }
 
-  int8_t InputInt8(int index) { return static_cast<int8_t>(InputInt32(index)); }
+  int8_t InputInt8(size_t index) {
+    return static_cast<int8_t>(InputInt32(index));
+  }
 
-  int16_t InputInt16(int index) {
+  int16_t InputInt16(size_t index) {
     return static_cast<int16_t>(InputInt32(index));
   }
 
-  uint8_t InputInt5(int index) {
+  uint8_t InputInt5(size_t index) {
     return static_cast<uint8_t>(InputInt32(index) & 0x1F);
   }
 
-  uint8_t InputInt6(int index) {
+  uint8_t InputInt6(size_t index) {
     return static_cast<uint8_t>(InputInt32(index) & 0x3F);
   }
 
-  Handle<HeapObject> InputHeapObject(int index) {
+  Handle<HeapObject> InputHeapObject(size_t index) {
     return ToHeapObject(instr_->InputAt(index));
   }
 
-  Label* InputLabel(int index) { return ToLabel(instr_->InputAt(index)); }
+  Label* InputLabel(size_t index) { return ToLabel(instr_->InputAt(index)); }
 
-  BasicBlock::RpoNumber InputRpo(int index) {
+  RpoNumber InputRpo(size_t index) {
     return ToRpoNumber(instr_->InputAt(index));
   }
 
-  Register OutputRegister(int index = 0) {
+  Register OutputRegister(size_t index = 0) {
     return ToRegister(instr_->OutputAt(index));
   }
 
-  Register TempRegister(int index) { return ToRegister(instr_->TempAt(index)); }
+  Register TempRegister(size_t index) {
+    return ToRegister(instr_->TempAt(index));
+  }
 
   DoubleRegister OutputDoubleRegister() {
     return ToDoubleRegister(instr_->Output());
@@ -81,7 +85,7 @@ class InstructionOperandConverter {
     return gen_->GetLabel(ToRpoNumber(op));
   }
 
-  BasicBlock::RpoNumber ToRpoNumber(InstructionOperand* op) {
+  RpoNumber ToRpoNumber(InstructionOperand* op) {
     return ToConstant(op).ToRpoNumber();
   }
 
index 1a4566d..47dce31 100644 (file)
@@ -37,11 +37,12 @@ CodeGenerator::CodeGenerator(Frame* frame, Linkage* linkage,
       code_(code),
       info_(info),
       labels_(zone()->NewArray<Label>(code->InstructionBlockCount())),
-      current_block_(BasicBlock::RpoNumber::Invalid()),
+      current_block_(RpoNumber::Invalid()),
       current_source_position_(SourcePosition::Invalid()),
       masm_(info->isolate(), NULL, 0),
       resolver_(this),
       safepoints_(code->zone()),
+      handlers_(code->zone()),
       deoptimization_states_(code->zone()),
       deoptimization_literals_(code->zone()),
       translations_(code->zone()),
@@ -84,7 +85,7 @@ Handle<Code> CodeGenerator::GenerateCode() {
       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());
+        SNPrintF(buffer, "-- B%d start --", block->rpo_number().ToInt());
         masm()->RecordComment(buffer.start());
       }
       masm()->bind(GetLabel(current_block_));
@@ -131,6 +132,19 @@ Handle<Code> CodeGenerator::GenerateCode() {
   result->set_stack_slots(frame()->GetSpillSlotCount());
   result->set_safepoint_table_offset(safepoints()->GetCodeOffset());
 
+  // Emit exception handler table.
+  if (!handlers_.empty()) {
+    Handle<HandlerTable> table =
+        Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray(
+            HandlerTable::LengthForReturn(static_cast<int>(handlers_.size())),
+            TENURED));
+    for (size_t i = 0; i < handlers_.size(); ++i) {
+      table->SetReturnOffset(static_cast<int>(i), handlers_[i].pc_offset);
+      table->SetReturnHandler(static_cast<int>(i), handlers_[i].handler->pos());
+    }
+    result->set_handler_table(*table);
+  }
+
   PopulateDeoptimizationData(result);
 
   // Ensure there is space for lazy deoptimization in the relocation info.
@@ -146,7 +160,7 @@ Handle<Code> CodeGenerator::GenerateCode() {
 }
 
 
-bool CodeGenerator::IsNextInAssemblyOrder(BasicBlock::RpoNumber block) const {
+bool CodeGenerator::IsNextInAssemblyOrder(RpoNumber block) const {
   return code()->InstructionBlockAt(current_block_)->ao_number().IsNext(
       code()->InstructionBlockAt(block)->ao_number());
 }
@@ -186,10 +200,8 @@ void CodeGenerator::AssembleInstruction(Instruction* instr) {
     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);
+      RpoNumber true_rpo = i.InputRpo(instr->InputCount() - 2);
+      RpoNumber false_rpo = i.InputRpo(instr->InputCount() - 1);
 
       if (true_rpo == false_rpo) {
         // redundant branch.
@@ -321,7 +333,7 @@ Label* CodeGenerator::AddJumpTable(Label** targets, size_t target_count) {
 }
 
 
-void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) {
+void CodeGenerator::RecordCallPosition(Instruction* instr) {
   CallDescriptor::Flags flags(MiscField::decode(instr->opcode()));
 
   bool needs_frame_state = (flags & CallDescriptor::kNeedsFrameState);
@@ -330,16 +342,21 @@ void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) {
       instr->pointer_map(), Safepoint::kSimple, 0,
       needs_frame_state ? Safepoint::kLazyDeopt : Safepoint::kNoLazyDeopt);
 
+  if (flags & CallDescriptor::kHasExceptionHandler) {
+    InstructionOperandConverter i(this, instr);
+    RpoNumber handler_rpo =
+        i.InputRpo(static_cast<int>(instr->InputCount()) - 1);
+    handlers_.push_back({GetLabel(handler_rpo), masm()->pc_offset()});
+  }
+
   if (flags & CallDescriptor::kNeedsNopAfterCall) {
     AddNopForSmiCodeInlining();
   }
 
   if (needs_frame_state) {
     MarkLazyDeoptSite();
-    // If the frame state is present, it starts at argument 1
-    // (just after the code address).
-    InstructionOperandConverter converter(this, instr);
-    // Deoptimization info starts at argument 1
+    // If the frame state is present, it starts at argument 1 (just after the
+    // code address).
     size_t frame_state_offset = 1;
     FrameStateDescriptor* descriptor =
         GetFrameStateDescriptor(instr, frame_state_offset);
@@ -383,8 +400,8 @@ int CodeGenerator::DefineDeoptimizationLiteral(Handle<Object> literal) {
 FrameStateDescriptor* CodeGenerator::GetFrameStateDescriptor(
     Instruction* instr, size_t frame_state_offset) {
   InstructionOperandConverter i(this, instr);
-  InstructionSequence::StateId state_id = InstructionSequence::StateId::FromInt(
-      i.InputInt32(static_cast<int>(frame_state_offset)));
+  InstructionSequence::StateId state_id =
+      InstructionSequence::StateId::FromInt(i.InputInt32(frame_state_offset));
   return code()->GetFrameStateDescriptor(state_id);
 }
 
@@ -493,8 +510,10 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation,
                                              InstructionOperand* op,
                                              MachineType type) {
   if (op->IsStackSlot()) {
-    if (type == kMachBool || type == kMachInt32 || type == kMachInt8 ||
-        type == kMachInt16) {
+    // TODO(jarin) kMachBool and kRepBit should materialize true and false
+    // rather than creating an int value.
+    if (type == kMachBool || type == kRepBit || type == kMachInt32 ||
+        type == kMachInt8 || type == kMachInt16) {
       translation->StoreInt32StackSlot(op->index());
     } else if (type == kMachUint32 || type == kMachUint16 ||
                type == kMachUint8) {
@@ -509,8 +528,10 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation,
     translation->StoreDoubleStackSlot(op->index());
   } else if (op->IsRegister()) {
     InstructionOperandConverter converter(this, instr);
-    if (type == kMachBool || type == kMachInt32 || type == kMachInt8 ||
-        type == kMachInt16) {
+    // TODO(jarin) kMachBool and kRepBit should materialize true and false
+    // rather than creating an int value.
+    if (type == kMachBool || type == kRepBit || type == kMachInt32 ||
+        type == kMachInt8 || type == kMachInt16) {
       translation->StoreInt32Register(converter.ToRegister(op));
     } else if (type == kMachUint32 || type == kMachUint16 ||
                type == kMachUint8) {
@@ -530,12 +551,14 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation,
     Handle<Object> constant_object;
     switch (constant.type()) {
       case Constant::kInt32:
-        DCHECK(type == kMachInt32 || type == kMachUint32);
+        DCHECK(type == kMachInt32 || type == kMachUint32 || type == kRepBit);
         constant_object =
             isolate()->factory()->NewNumberFromInt(constant.ToInt32());
         break;
       case Constant::kFloat64:
-        DCHECK(type == kMachFloat64 || type == kMachAnyTagged);
+        DCHECK(type == kMachFloat64 || type == kMachAnyTagged ||
+               type == kRepTagged || type == (kTypeInt32 | kRepTagged) ||
+               type == (kTypeUint32 | kRepTagged));
         constant_object = isolate()->factory()->NewNumber(constant.ToFloat64());
         break;
       case Constant::kHeapObject:
@@ -576,12 +599,11 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
 }
 
 
-void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
-  UNIMPLEMENTED();
-}
+void CodeGenerator::AssembleArchJump(RpoNumber target) { UNIMPLEMENTED(); }
 
 
-void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
+void CodeGenerator::AssembleDeoptimizerCall(
+    int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
   UNIMPLEMENTED();
 }
 
index 658394b..462b683 100644 (file)
@@ -41,7 +41,7 @@ class CodeGenerator FINAL : public GapResolver::Assembler {
   Isolate* isolate() const { return info_->isolate(); }
   Linkage* linkage() const { return linkage_; }
 
-  Label* GetLabel(BasicBlock::RpoNumber rpo) { return &labels_[rpo.ToSize()]; }
+  Label* GetLabel(RpoNumber rpo) { return &labels_[rpo.ToSize()]; }
 
  private:
   MacroAssembler* masm() { return &masm_; }
@@ -52,7 +52,7 @@ class CodeGenerator FINAL : public GapResolver::Assembler {
 
   // Checks if {block} will appear directly after {current_block_} when
   // assembling code, in which case, a fall-through can be used.
-  bool IsNextInAssemblyOrder(BasicBlock::RpoNumber block) const;
+  bool IsNextInAssemblyOrder(RpoNumber block) const;
 
   // Record a safepoint with the given pointer map.
   void RecordSafepoint(PointerMap* pointers, Safepoint::Kind kind,
@@ -68,13 +68,14 @@ class CodeGenerator FINAL : public GapResolver::Assembler {
   // ===========================================================================
 
   void AssembleArchInstruction(Instruction* instr);
-  void AssembleArchJump(BasicBlock::RpoNumber target);
+  void AssembleArchJump(RpoNumber target);
   void AssembleArchBranch(Instruction* instr, BranchInfo* branch);
   void AssembleArchBoolean(Instruction* instr, FlagsCondition condition);
   void AssembleArchLookupSwitch(Instruction* instr);
   void AssembleArchTableSwitch(Instruction* instr);
 
-  void AssembleDeoptimizerCall(int deoptimization_id);
+  void AssembleDeoptimizerCall(int deoptimization_id,
+                               Deoptimizer::BailoutType bailout_type);
 
   // Generates an architecture-specific, descriptor-specific prologue
   // to set up a stack frame.
@@ -106,8 +107,10 @@ class CodeGenerator FINAL : public GapResolver::Assembler {
   void AssembleJumpTable(Label** targets, size_t target_count);
 
   // ===========================================================================
-  // Deoptimization table construction
-  void AddSafepointAndDeopt(Instruction* instr);
+  // ================== Deoptimization table construction. =====================
+  // ===========================================================================
+
+  void RecordCallPosition(Instruction* instr);
   void PopulateDeoptimizationData(Handle<Code> code);
   int DefineDeoptimizationLiteral(Handle<Object> literal);
   FrameStateDescriptor* GetFrameStateDescriptor(Instruction* instr,
@@ -126,6 +129,7 @@ class CodeGenerator FINAL : public GapResolver::Assembler {
   void MarkLazyDeoptSite();
 
   // ===========================================================================
+
   struct DeoptimizationState : ZoneObject {
    public:
     BailoutId bailout_id() const { return bailout_id_; }
@@ -143,6 +147,11 @@ class CodeGenerator FINAL : public GapResolver::Assembler {
     int pc_offset_;
   };
 
+  struct HandlerInfo {
+    Label* handler;
+    int pc_offset;
+  };
+
   friend class OutOfLineCode;
 
   Frame* const frame_;
@@ -150,13 +159,14 @@ class CodeGenerator FINAL : public GapResolver::Assembler {
   InstructionSequence* const code_;
   CompilationInfo* const info_;
   Label* const labels_;
-  BasicBlock::RpoNumber current_block_;
+  RpoNumber current_block_;
   SourcePosition current_source_position_;
   MacroAssembler masm_;
   GapResolver resolver_;
   SafepointTableBuilder safepoints_;
+  ZoneVector<HandlerInfo> handlers_;
   ZoneDeque<DeoptimizationState*> deoptimization_states_;
-  ZoneDeque<Handle<Object> > deoptimization_literals_;
+  ZoneDeque<Handle<Object>> deoptimization_literals_;
   TranslationBuffer translations_;
   int last_lazy_deopt_pc_;
   JumpTable* jump_tables_;
index c3cbcde..b07383d 100644 (file)
@@ -4,8 +4,12 @@
 
 #include "src/compiler/common-operator-reducer.h"
 
+#include <algorithm>
+
 #include "src/compiler/common-operator.h"
+#include "src/compiler/js-graph.h"
 #include "src/compiler/node.h"
+#include "src/compiler/node-matchers.h"
 
 namespace v8 {
 namespace internal {
@@ -14,29 +18,119 @@ 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);
-      }
+      return ReduceEffectPhi(node);
+    case IrOpcode::kPhi:
+      return ReducePhi(node);
+    case IrOpcode::kSelect:
+      return ReduceSelect(node);
+    default:
       break;
+  }
+  return NoChange();
+}
+
+
+Reduction CommonOperatorReducer::ReduceEffectPhi(Node* node) {
+  DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode());
+  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();
     }
-    case IrOpcode::kSelect: {
-      if (node->InputAt(1) == node->InputAt(2)) {
-        return Replace(node->InputAt(1));
+    return Replace(replacement);
+  }
+  return NoChange();
+}
+
+
+Reduction CommonOperatorReducer::ReducePhi(Node* node) {
+  DCHECK_EQ(IrOpcode::kPhi, node->opcode());
+  int const input_count = node->InputCount();
+  if (input_count == 3) {
+    Node* vtrue = NodeProperties::GetValueInput(node, 0);
+    Node* vfalse = NodeProperties::GetValueInput(node, 1);
+    Node* merge = NodeProperties::GetControlInput(node);
+    Node* if_true = NodeProperties::GetControlInput(merge, 0);
+    Node* if_false = NodeProperties::GetControlInput(merge, 1);
+    if (if_true->opcode() != IrOpcode::kIfTrue) {
+      std::swap(if_true, if_false);
+      std::swap(vtrue, vfalse);
+    }
+    if (if_true->opcode() == IrOpcode::kIfTrue &&
+        if_false->opcode() == IrOpcode::kIfFalse &&
+        if_true->InputAt(0) == if_false->InputAt(0)) {
+      Node* branch = if_true->InputAt(0);
+      Node* cond = branch->InputAt(0);
+      if (cond->opcode() == IrOpcode::kFloat64LessThan) {
+        if (cond->InputAt(0) == vtrue && cond->InputAt(1) == vfalse &&
+            machine()->HasFloat64Min()) {
+          node->set_op(machine()->Float64Min());
+          node->ReplaceInput(0, vtrue);
+          node->ReplaceInput(1, vfalse);
+          node->TrimInputCount(2);
+          return Changed(node);
+        } else if (cond->InputAt(0) == vfalse && cond->InputAt(1) == vtrue &&
+                   machine()->HasFloat64Max()) {
+          node->set_op(machine()->Float64Max());
+          node->ReplaceInput(0, vtrue);
+          node->ReplaceInput(1, vfalse);
+          node->TrimInputCount(2);
+          return Changed(node);
+        }
       }
-      break;
     }
-    default:
-      break;
+  }
+  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);
+  }
+  return NoChange();
+}
+
+
+Reduction CommonOperatorReducer::ReduceSelect(Node* node) {
+  DCHECK_EQ(IrOpcode::kSelect, node->opcode());
+  Node* cond = NodeProperties::GetValueInput(node, 0);
+  Node* vtrue = NodeProperties::GetValueInput(node, 1);
+  Node* vfalse = NodeProperties::GetValueInput(node, 2);
+  if (vtrue == vfalse) return Replace(vtrue);
+  if (cond->opcode() == IrOpcode::kFloat64LessThan) {
+    if (cond->InputAt(0) == vtrue && cond->InputAt(1) == vfalse &&
+        machine()->HasFloat64Min()) {
+      node->set_op(machine()->Float64Min());
+      node->ReplaceInput(0, vtrue);
+      node->ReplaceInput(1, vfalse);
+      node->TrimInputCount(2);
+      return Changed(node);
+    } else if (cond->InputAt(0) == vfalse && cond->InputAt(1) == vtrue &&
+               machine()->HasFloat64Max()) {
+      node->set_op(machine()->Float64Max());
+      node->ReplaceInput(0, vtrue);
+      node->ReplaceInput(1, vfalse);
+      node->TrimInputCount(2);
+      return Changed(node);
+    }
   }
   return NoChange();
 }
 
+
+CommonOperatorBuilder* CommonOperatorReducer::common() const {
+  return jsgraph()->common();
+}
+
+
+Graph* CommonOperatorReducer::graph() const { return jsgraph()->graph(); }
+
+
+MachineOperatorBuilder* CommonOperatorReducer::machine() const {
+  return jsgraph()->machine();
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 10543db..dfcbe29 100644 (file)
@@ -11,13 +11,32 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
+// Forward declarations.
+class CommonOperatorBuilder;
+class Graph;
+class JSGraph;
+class MachineOperatorBuilder;
+
+
 // Performs strength reduction on nodes that have common operators.
 class CommonOperatorReducer FINAL : public Reducer {
  public:
-  CommonOperatorReducer() {}
+  explicit CommonOperatorReducer(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
   ~CommonOperatorReducer() FINAL {}
 
   Reduction Reduce(Node* node) FINAL;
+
+ private:
+  Reduction ReduceEffectPhi(Node* node);
+  Reduction ReducePhi(Node* node);
+  Reduction ReduceSelect(Node* node);
+
+  CommonOperatorBuilder* common() const;
+  Graph* graph() const;
+  JSGraph* jsgraph() const { return jsgraph_; }
+  MachineOperatorBuilder* machine() const;
+
+  JSGraph* const jsgraph_;
 };
 
 }  // namespace compiler
index 8aea3df..75f353c 100644 (file)
@@ -115,13 +115,25 @@ size_t ProjectionIndexOf(const Operator* const op) {
   V(End, Operator::kKontrol, 0, 0, 1, 0, 0, 0)             \
   V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1)          \
   V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1)         \
+  V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1)       \
+  V(IfException, Operator::kKontrol, 0, 0, 1, 0, 0, 1)     \
   V(IfDefault, Operator::kKontrol, 0, 0, 1, 0, 0, 1)       \
   V(Throw, Operator::kFoldable, 1, 1, 1, 0, 0, 1)          \
+  V(Deoptimize, Operator::kNoThrow, 1, 1, 1, 0, 0, 1)      \
   V(Return, Operator::kNoThrow, 1, 1, 1, 0, 0, 1)          \
   V(OsrNormalEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \
   V(OsrLoopEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1)
 
 
+#define CACHED_EFFECT_PHI_LIST(V) \
+  V(1)                            \
+  V(2)                            \
+  V(3)                            \
+  V(4)                            \
+  V(5)                            \
+  V(6)
+
+
 #define CACHED_LOOP_LIST(V) \
   V(1)                      \
   V(2)
@@ -148,6 +160,40 @@ size_t ProjectionIndexOf(const Operator* const op) {
   V(6)
 
 
+#define CACHED_PHI_LIST(V) \
+  V(kMachAnyTagged, 1)     \
+  V(kMachAnyTagged, 2)     \
+  V(kMachAnyTagged, 3)     \
+  V(kMachAnyTagged, 4)     \
+  V(kMachAnyTagged, 5)     \
+  V(kMachAnyTagged, 6)     \
+  V(kMachBool, 2)          \
+  V(kMachFloat64, 2)       \
+  V(kMachInt32, 2)
+
+
+#define CACHED_PROJECTION_LIST(V) \
+  V(0)                            \
+  V(1)
+
+
+#define CACHED_STATE_VALUES_LIST(V) \
+  V(0)                              \
+  V(1)                              \
+  V(2)                              \
+  V(3)                              \
+  V(4)                              \
+  V(5)                              \
+  V(6)                              \
+  V(7)                              \
+  V(8)                              \
+  V(10)                             \
+  V(11)                             \
+  V(12)                             \
+  V(13)                             \
+  V(14)
+
+
 struct CommonOperatorGlobalCache FINAL {
 #define CACHED(Name, properties, value_input_count, effect_input_count,      \
                control_input_count, value_output_count, effect_output_count, \
@@ -176,6 +222,19 @@ struct CommonOperatorGlobalCache FINAL {
   BranchOperator<BranchHint::kTrue> kBranchTrueOperator;
   BranchOperator<BranchHint::kFalse> kBranchFalseOperator;
 
+  template <int kEffectInputCount>
+  struct EffectPhiOperator FINAL : public Operator {
+    EffectPhiOperator()
+        : Operator(                                   // --
+              IrOpcode::kEffectPhi, Operator::kPure,  // opcode
+              "EffectPhi",                            // name
+              0, kEffectInputCount, 1, 0, 1, 0) {}    // counts
+  };
+#define CACHED_EFFECT_PHI(input_count) \
+  EffectPhiOperator<input_count> kEffectPhi##input_count##Operator;
+  CACHED_EFFECT_PHI_LIST(CACHED_EFFECT_PHI)
+#undef CACHED_EFFECT_PHI
+
   template <size_t kInputCount>
   struct LoopOperator FINAL : public Operator {
     LoopOperator()
@@ -202,6 +261,20 @@ struct CommonOperatorGlobalCache FINAL {
   CACHED_MERGE_LIST(CACHED_MERGE)
 #undef CACHED_MERGE
 
+  template <MachineType kType, int kInputCount>
+  struct PhiOperator FINAL : public Operator1<MachineType> {
+    PhiOperator()
+        : Operator1<MachineType>(               //--
+              IrOpcode::kPhi, Operator::kPure,  // opcode
+              "Phi",                            // name
+              kInputCount, 0, 1, 1, 0, 0,       // counts
+              kType) {}                         // parameter
+  };
+#define CACHED_PHI(type, input_count) \
+  PhiOperator<type, input_count> kPhi##type##input_count##Operator;
+  CACHED_PHI_LIST(CACHED_PHI)
+#undef CACHED_PHI
+
   template <int kIndex>
   struct ParameterOperator FINAL : public Operator1<int> {
     ParameterOperator()
@@ -215,6 +288,35 @@ struct CommonOperatorGlobalCache FINAL {
   ParameterOperator<index> kParameter##index##Operator;
   CACHED_PARAMETER_LIST(CACHED_PARAMETER)
 #undef CACHED_PARAMETER
+
+  template <size_t kIndex>
+  struct ProjectionOperator FINAL : public Operator1<size_t> {
+    ProjectionOperator()
+        : Operator1<size_t>(          // --
+              IrOpcode::kProjection,  // opcode
+              Operator::kPure,        // flags
+              "Projection",           // name
+              1, 0, 0, 1, 0, 0,       // counts,
+              kIndex) {}              // parameter
+  };
+#define CACHED_PROJECTION(index) \
+  ProjectionOperator<index> kProjection##index##Operator;
+  CACHED_PROJECTION_LIST(CACHED_PROJECTION)
+#undef CACHED_PROJECTION
+
+  template <int kInputCount>
+  struct StateValuesOperator FINAL : public Operator {
+    StateValuesOperator()
+        : Operator(                           // --
+              IrOpcode::kStateValues,         // opcode
+              Operator::kPure,                // flags
+              "StateValues",                  // name
+              kInputCount, 0, 0, 1, 0, 0) {}  // counts
+  };
+#define CACHED_STATE_VALUES(input_count) \
+  StateValuesOperator<input_count> kStateValues##input_count##Operator;
+  CACHED_STATE_VALUES_LIST(CACHED_STATE_VALUES)
+#undef CACHED_STATE_VALUES
 };
 
 
@@ -420,22 +522,40 @@ const Operator* CommonOperatorBuilder::Select(MachineType type,
 }
 
 
-const Operator* CommonOperatorBuilder::Phi(MachineType type, int arguments) {
-  DCHECK(arguments > 0);                       // Disallow empty phis.
+const Operator* CommonOperatorBuilder::Phi(MachineType type,
+                                           int value_input_count) {
+  DCHECK(value_input_count > 0);  // Disallow empty phis.
+#define CACHED_PHI(kType, kValueInputCount)                     \
+  if (kType == type && kValueInputCount == value_input_count) { \
+    return &cache_.kPhi##kType##kValueInputCount##Operator;     \
+  }
+  CACHED_PHI_LIST(CACHED_PHI)
+#undef CACHED_PHI
+  // Uncached.
   return new (zone()) Operator1<MachineType>(  // --
       IrOpcode::kPhi, Operator::kPure,         // opcode
       "Phi",                                   // name
-      arguments, 0, 1, 1, 0, 0,                // counts
+      value_input_count, 0, 1, 1, 0, 0,        // counts
       type);                                   // parameter
 }
 
 
-const Operator* CommonOperatorBuilder::EffectPhi(int arguments) {
-  DCHECK(arguments > 0);                      // Disallow empty phis.
+const Operator* CommonOperatorBuilder::EffectPhi(int effect_input_count) {
+  DCHECK(effect_input_count > 0);  // Disallow empty effect phis.
+  switch (effect_input_count) {
+#define CACHED_EFFECT_PHI(input_count) \
+  case input_count:                    \
+    return &cache_.kEffectPhi##input_count##Operator;
+    CACHED_EFFECT_PHI_LIST(CACHED_EFFECT_PHI)
+#undef CACHED_EFFECT_PHI
+    default:
+      break;
+  }
+  // Uncached.
   return new (zone()) Operator(               // --
       IrOpcode::kEffectPhi, Operator::kPure,  // opcode
       "EffectPhi",                            // name
-      0, arguments, 1, 0, 1, 0);              // counts
+      0, effect_input_count, 1, 0, 1, 0);     // counts
 }
 
 
@@ -467,6 +587,16 @@ const Operator* CommonOperatorBuilder::Finish(int arguments) {
 
 
 const Operator* CommonOperatorBuilder::StateValues(int arguments) {
+  switch (arguments) {
+#define CACHED_STATE_VALUES(arguments) \
+  case arguments:                      \
+    return &cache_.kStateValues##arguments##Operator;
+    CACHED_STATE_VALUES_LIST(CACHED_STATE_VALUES)
+#undef CACHED_STATE_VALUES
+    default:
+      break;
+  }
+  // Uncached.
   return new (zone()) Operator(                 // --
       IrOpcode::kStateValues, Operator::kPure,  // opcode
       "StateValues",                            // name
@@ -474,6 +604,15 @@ const Operator* CommonOperatorBuilder::StateValues(int arguments) {
 }
 
 
+const Operator* CommonOperatorBuilder::TypedStateValues(
+    const ZoneVector<MachineType>* types) {
+  return new (zone()) Operator1<const ZoneVector<MachineType>*>(  // --
+      IrOpcode::kTypedStateValues, Operator::kPure,               // opcode
+      "TypedStateValues",                                         // name
+      static_cast<int>(types->size()), 0, 0, 1, 0, 0, types);     // counts
+}
+
+
 const Operator* CommonOperatorBuilder::FrameState(
     FrameStateType type, BailoutId bailout_id,
     OutputFrameStateCombine state_combine, MaybeHandle<JSFunction> jsfunction) {
@@ -493,9 +632,10 @@ const Operator* CommonOperatorBuilder::Call(const CallDescriptor* descriptor) {
               IrOpcode::kCall, descriptor->properties(), mnemonic,
               descriptor->InputCount() + descriptor->FrameStateCount(),
               Operator::ZeroIfPure(descriptor->properties()),
-              Operator::ZeroIfPure(descriptor->properties()),
+              Operator::ZeroIfEliminatable(descriptor->properties()),
               descriptor->ReturnCount(),
-              Operator::ZeroIfPure(descriptor->properties()), 0, descriptor) {}
+              Operator::ZeroIfPure(descriptor->properties()),
+              Operator::ZeroIfNoThrow(descriptor->properties()), descriptor) {}
 
     void PrintParameter(std::ostream& os) const OVERRIDE {
       os << "[" << *parameter() << "]";
@@ -506,6 +646,16 @@ const Operator* CommonOperatorBuilder::Call(const CallDescriptor* descriptor) {
 
 
 const Operator* CommonOperatorBuilder::Projection(size_t index) {
+  switch (index) {
+#define CACHED_PROJECTION(index) \
+  case index:                    \
+    return &cache_.kProjection##index##Operator;
+    CACHED_PROJECTION_LIST(CACHED_PROJECTION)
+#undef CACHED_PROJECTION
+    default:
+      break;
+  }
+  // Uncached.
   return new (zone()) Operator1<size_t>(         // --
       IrOpcode::kProjection,                     // opcode
       Operator::kFoldable | Operator::kNoThrow,  // flags
index 9f2c575..23d06ea 100644 (file)
@@ -172,10 +172,13 @@ class CommonOperatorBuilder FINAL : public ZoneObject {
   const Operator* Branch(BranchHint = BranchHint::kNone);
   const Operator* IfTrue();
   const Operator* IfFalse();
+  const Operator* IfSuccess();
+  const Operator* IfException();
   const Operator* Switch(size_t control_output_count);
   const Operator* IfValue(int32_t value);
   const Operator* IfDefault();
   const Operator* Throw();
+  const Operator* Deoptimize();
   const Operator* Return();
 
   const Operator* Start(int num_formal_parameters);
@@ -196,12 +199,13 @@ class CommonOperatorBuilder FINAL : public ZoneObject {
   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* Phi(MachineType type, int value_input_count);
+  const Operator* EffectPhi(int effect_input_count);
   const Operator* EffectSet(int arguments);
   const Operator* ValueEffect(int arguments);
   const Operator* Finish(int arguments);
   const Operator* StateValues(int arguments);
+  const Operator* TypedStateValues(const ZoneVector<MachineType>* types);
   const Operator* FrameState(
       FrameStateType type, BailoutId bailout_id,
       OutputFrameStateCombine state_combine,
index 2ace441..0e4f168 100644 (file)
@@ -179,21 +179,25 @@ void TryCatchBuilder::EndCatch() {
 void TryFinallyBuilder::BeginTry() {
   finally_environment_ = environment()->CopyAsUnreachable();
   finally_environment_->Push(the_hole());
+  finally_environment_->Push(the_hole());
 }
 
 
-void TryFinallyBuilder::LeaveTry(Node* token) {
+void TryFinallyBuilder::LeaveTry(Node* token, Node* value) {
+  environment()->Push(value);
   environment()->Push(token);
   finally_environment_->Merge(environment());
-  environment()->Pop();
+  environment()->Drop(2);
 }
 
 
-void TryFinallyBuilder::EndTry(Node* fallthrough_token) {
+void TryFinallyBuilder::EndTry(Node* fallthrough_token, Node* value) {
+  environment()->Push(value);
   environment()->Push(fallthrough_token);
   finally_environment_->Merge(environment());
-  environment()->Pop();
+  environment()->Drop(2);
   token_node_ = finally_environment_->Pop();
+  value_node_ = finally_environment_->Pop();
   set_environment(finally_environment_);
 }
 
index c22ee04..5997056 100644 (file)
@@ -167,20 +167,25 @@ class TryFinallyBuilder FINAL : public ControlBuilder {
   explicit TryFinallyBuilder(AstGraphBuilder* builder)
       : ControlBuilder(builder),
         finally_environment_(NULL),
-        token_node_(NULL) {}
+        token_node_(NULL),
+        value_node_(NULL) {}
 
   // Primitive control commands.
   void BeginTry();
-  void LeaveTry(Node* token);
-  void EndTry(Node* token);
+  void LeaveTry(Node* token, Node* value);
+  void EndTry(Node* token, Node* value);
   void EndFinally();
 
   // Returns the dispatch token value inside the 'finally' body.
   Node* GetDispatchTokenNode() const { return token_node_; }
 
+  // Returns the saved result value inside the 'finally' body.
+  Node* GetResultValueNode() const { return value_node_; }
+
  private:
   Environment* finally_environment_;  // Environment for the 'finally' body.
   Node* token_node_;                  // Node for token in 'finally' body.
+  Node* value_node_;                  // Node for value in 'finally' body.
 };
 
 }  // namespace compiler
index db05e3e..354d6cf 100644 (file)
@@ -14,6 +14,11 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
+#define TRACE(...)                                       \
+  do {                                                   \
+    if (FLAG_trace_turbo_scheduler) PrintF(__VA_ARGS__); \
+  } while (false)
+
 // 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:
@@ -96,16 +101,16 @@ class ControlEquivalence : public ZoneObject {
 
   // Called at pre-visit during DFS walk.
   void VisitPre(Node* node) {
-    Trace("CEQ: Pre-visit of #%d:%s\n", node->id(), node->op()->mnemonic());
+    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));
+    TRACE("  Assigned DFS number is %zu\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());
+    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].
@@ -118,7 +123,7 @@ class ControlEquivalence : public ZoneObject {
     }
 
     // Potentially start a new equivalence class [line:37].
-    BracketListTrace(blist);
+    BracketListTRACE(blist);
     Bracket* recent = &blist.back();
     if (recent->recent_size != blist.size()) {
       recent->recent_size = blist.size();
@@ -127,12 +132,12 @@ class ControlEquivalence : public ZoneObject {
 
     // Assign equivalence class to node.
     SetClass(node, recent->recent_class);
-    Trace("  Assigned class number is %d\n", GetClass(node));
+    TRACE("  Assigned class number is %zu\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());
+    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].
@@ -147,7 +152,7 @@ class ControlEquivalence : public ZoneObject {
 
   // 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(),
+    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].
@@ -316,7 +321,7 @@ class ControlEquivalence : public ZoneObject {
   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());
+        TRACE("  BList erased: {%d->%d}\n", i->from->id(), i->to->id());
         i = blist.erase(i);
       } else {
         ++i;
@@ -324,22 +329,13 @@ class ControlEquivalence : public ZoneObject {
     }
   }
 
-  void BracketListTrace(BracketList& blist) {
+  void BracketListTRACE(BracketList& blist) {
     if (FLAG_trace_turbo_scheduler) {
-      Trace("  BList: ");
+      TRACE("  BList: ");
       for (Bracket bracket : blist) {
-        Trace("{%d->%d} ", bracket.from->id(), bracket.to->id());
+        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);
+      TRACE("\n");
     }
   }
 
@@ -350,6 +346,8 @@ class ControlEquivalence : public ZoneObject {
   Data node_data_;    // Per-node data stored as a side-table.
 };
 
+#undef TRACE
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 1a2b4cd..f074f72 100644 (file)
@@ -46,21 +46,172 @@ void ControlFlowOptimizer::Enqueue(Node* node) {
 
 
 void ControlFlowOptimizer::VisitNode(Node* node) {
-  for (Node* use : node->uses()) {
-    if (NodeProperties::IsControl(use)) Enqueue(use);
+  for (Edge edge : node->use_edges()) {
+    if (NodeProperties::IsControlEdge(edge)) {
+      Enqueue(edge.from());
+    }
   }
 }
 
 
 void ControlFlowOptimizer::VisitBranch(Node* node) {
   DCHECK_EQ(IrOpcode::kBranch, node->opcode());
+  if (TryBuildSwitch(node)) return;
+  if (TryCloneBranch(node)) return;
+  VisitNode(node);
+}
+
+
+bool ControlFlowOptimizer::TryCloneBranch(Node* node) {
+  DCHECK_EQ(IrOpcode::kBranch, node->opcode());
+
+  // This optimization is a special case of (super)block cloning. It takes an
+  // input graph as shown below and clones the Branch node for every predecessor
+  // to the Merge, essentially removing the Merge completely. This avoids
+  // materializing the bit for the Phi and may offer potential for further
+  // branch folding optimizations (i.e. because one or more inputs to the Phi is
+  // a constant). Note that there may be more Phi nodes hanging off the Merge,
+  // but we can only a certain subset of them currently (actually only Phi and
+  // EffectPhi nodes whose uses have either the IfTrue or IfFalse as control
+  // input).
+
+  //   Control1 ... ControlN
+  //      ^            ^
+  //      |            |   Cond1 ... CondN
+  //      +----+  +----+     ^         ^
+  //           |  |          |         |
+  //           |  |     +----+         |
+  //          Merge<--+ | +------------+
+  //            ^      \|/
+  //            |      Phi
+  //            |       |
+  //          Branch----+
+  //            ^
+  //            |
+  //      +-----+-----+
+  //      |           |
+  //    IfTrue     IfFalse
+  //      ^           ^
+  //      |           |
+
+  // The resulting graph (modulo the Phi and EffectPhi nodes) looks like this:
+
+  // Control1 Cond1 ... ControlN CondN
+  //    ^      ^           ^      ^
+  //    \      /           \      /
+  //     Branch     ...     Branch
+  //       ^                  ^
+  //       |                  |
+  //   +---+---+          +---+----+
+  //   |       |          |        |
+  // IfTrue IfFalse ... IfTrue  IfFalse
+  //   ^       ^          ^        ^
+  //   |       |          |        |
+  //   +--+ +-------------+        |
+  //      | |  +--------------+ +--+
+  //      | |                 | |
+  //     Merge               Merge
+  //       ^                   ^
+  //       |                   |
+
+  Node* branch = node;
+  Node* cond = NodeProperties::GetValueInput(branch, 0);
+  if (!cond->OwnedBy(branch) || cond->opcode() != IrOpcode::kPhi) return false;
+  Node* merge = NodeProperties::GetControlInput(branch);
+  if (merge->opcode() != IrOpcode::kMerge ||
+      NodeProperties::GetControlInput(cond) != merge) {
+    return false;
+  }
+  // Grab the IfTrue/IfFalse projections of the Branch.
+  Node* control_projections[2];
+  NodeProperties::CollectControlProjections(branch, control_projections,
+                                            arraysize(control_projections));
+  Node* if_true = control_projections[0];
+  Node* if_false = control_projections[1];
+  DCHECK_EQ(IrOpcode::kIfTrue, if_true->opcode());
+  DCHECK_EQ(IrOpcode::kIfFalse, if_false->opcode());
+  // Check/collect other Phi/EffectPhi nodes hanging off the Merge.
+  NodeVector phis(zone());
+  for (Node* const use : merge->uses()) {
+    if (use == branch || use == cond) continue;
+    // We cannot currently deal with non-Phi/EffectPhi nodes hanging off the
+    // Merge. Ideally, we would just clone the nodes (and everything that
+    // depends on it to some distant join point), but that requires knowledge
+    // about dominance/post-dominance.
+    if (!NodeProperties::IsPhi(use)) return false;
+    for (Edge edge : use->use_edges()) {
+      // Right now we can only handle Phi/EffectPhi nodes whose uses are
+      // directly control-dependend on either the IfTrue or the IfFalse
+      // successor, because we know exactly how to update those uses.
+      // TODO(turbofan): Generalize this to all Phi/EffectPhi nodes using
+      // dominance/post-dominance on the sea of nodes.
+      if (edge.from()->op()->ControlInputCount() != 1) return false;
+      Node* control = NodeProperties::GetControlInput(edge.from());
+      if (NodeProperties::IsPhi(edge.from())) {
+        control = NodeProperties::GetControlInput(control, edge.index());
+      }
+      if (control != if_true && control != if_false) return false;
+    }
+    phis.push_back(use);
+  }
+  BranchHint const hint = BranchHintOf(branch->op());
+  int const input_count = merge->op()->ControlInputCount();
+  DCHECK_LE(1, input_count);
+  Node** const inputs = zone()->NewArray<Node*>(2 * input_count);
+  Node** const merge_true_inputs = &inputs[0];
+  Node** const merge_false_inputs = &inputs[input_count];
+  for (int index = 0; index < input_count; ++index) {
+    Node* cond1 = NodeProperties::GetValueInput(cond, index);
+    Node* control1 = NodeProperties::GetControlInput(merge, index);
+    Node* branch1 = graph()->NewNode(common()->Branch(hint), cond1, control1);
+    merge_true_inputs[index] = graph()->NewNode(common()->IfTrue(), branch1);
+    merge_false_inputs[index] = graph()->NewNode(common()->IfFalse(), branch1);
+    Enqueue(branch1);
+  }
+  Node* const merge_true = graph()->NewNode(common()->Merge(input_count),
+                                            input_count, merge_true_inputs);
+  Node* const merge_false = graph()->NewNode(common()->Merge(input_count),
+                                             input_count, merge_false_inputs);
+  for (Node* const phi : phis) {
+    for (int index = 0; index < input_count; ++index) {
+      inputs[index] = phi->InputAt(index);
+    }
+    inputs[input_count] = merge_true;
+    Node* phi_true = graph()->NewNode(phi->op(), input_count + 1, inputs);
+    inputs[input_count] = merge_false;
+    Node* phi_false = graph()->NewNode(phi->op(), input_count + 1, inputs);
+    for (Edge edge : phi->use_edges()) {
+      Node* control = NodeProperties::GetControlInput(edge.from());
+      if (NodeProperties::IsPhi(edge.from())) {
+        control = NodeProperties::GetControlInput(control, edge.index());
+      }
+      DCHECK(control == if_true || control == if_false);
+      edge.UpdateTo((control == if_true) ? phi_true : phi_false);
+    }
+    phi->Kill();
+  }
+  // Fix up IfTrue and IfFalse and kill all dead nodes.
+  if_false->ReplaceUses(merge_false);
+  if_true->ReplaceUses(merge_true);
+  if_false->Kill();
+  if_true->Kill();
+  branch->Kill();
+  cond->Kill();
+  merge->Kill();
+  return true;
+}
+
+
+bool ControlFlowOptimizer::TryBuildSwitch(Node* node) {
+  DCHECK_EQ(IrOpcode::kBranch, node->opcode());
 
   Node* branch = node;
+  if (BranchHintOf(branch->op()) != BranchHint::kNone) return false;
   Node* cond = NodeProperties::GetValueInput(branch, 0);
-  if (cond->opcode() != IrOpcode::kWord32Equal) return VisitNode(node);
+  if (cond->opcode() != IrOpcode::kWord32Equal) return false;
   Int32BinopMatcher m(cond);
   Node* index = m.left().node();
-  if (!m.right().HasValue()) return VisitNode(node);
+  if (!m.right().HasValue()) return false;
   int32_t value = m.right().Value();
   ZoneSet<int32_t> values(zone());
   values.insert(value);
@@ -79,6 +230,7 @@ void ControlFlowOptimizer::VisitBranch(Node* node) {
     if (it == if_false->uses().end()) break;
     Node* branch1 = *it++;
     if (branch1->opcode() != IrOpcode::kBranch) break;
+    if (BranchHintOf(branch1->op()) != BranchHint::kNone) break;
     if (it != if_false->uses().end()) break;
     Node* cond1 = branch1->InputAt(0);
     if (cond1->opcode() != IrOpcode::kWord32Equal) break;
@@ -90,11 +242,11 @@ void ControlFlowOptimizer::VisitBranch(Node* node) {
     DCHECK_NE(value, value1);
 
     if (branch != node) {
-      branch->RemoveAllInputs();
+      branch->NullAllInputs();
       if_true->ReplaceInput(0, node);
     }
     if_true->set_op(common()->IfValue(value));
-    if_false->RemoveAllInputs();
+    if_false->NullAllInputs();
     Enqueue(if_true);
 
     branch = branch1;
@@ -108,20 +260,19 @@ void ControlFlowOptimizer::VisitBranch(Node* node) {
   DCHECK_EQ(IrOpcode::kIfFalse, if_false->opcode());
   if (branch == node) {
     DCHECK_EQ(1u, values.size());
-    Enqueue(if_true);
-    Enqueue(if_false);
-  } else {
-    DCHECK_LT(1u, values.size());
-    node->set_op(common()->Switch(values.size() + 1));
-    node->ReplaceInput(0, index);
-    if_true->set_op(common()->IfValue(value));
-    if_true->ReplaceInput(0, node);
-    Enqueue(if_true);
-    if_false->set_op(common()->IfDefault());
-    if_false->ReplaceInput(0, node);
-    Enqueue(if_false);
-    branch->RemoveAllInputs();
+    return false;
   }
+  DCHECK_LT(1u, values.size());
+  node->set_op(common()->Switch(values.size() + 1));
+  node->ReplaceInput(0, index);
+  if_true->set_op(common()->IfValue(value));
+  if_true->ReplaceInput(0, node);
+  Enqueue(if_true);
+  if_false->set_op(common()->IfDefault());
+  if_false->ReplaceInput(0, node);
+  Enqueue(if_false);
+  branch->NullAllInputs();
+  return true;
 }
 
 
index fb96e01..d301021 100644 (file)
@@ -31,6 +31,9 @@ class ControlFlowOptimizer FINAL {
   void VisitNode(Node* node);
   void VisitBranch(Node* node);
 
+  bool TryBuildSwitch(Node* node);
+  bool TryCloneBranch(Node* node);
+
   CommonOperatorBuilder* common() const;
   Graph* graph() const;
   JSGraph* jsgraph() const { return jsgraph_; }
index d20c8dd..8b41d19 100644 (file)
@@ -15,6 +15,11 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
+#define TRACE(...)                                       \
+  do {                                                   \
+    if (FLAG_trace_turbo_reduction) PrintF(__VA_ARGS__); \
+  } while (false)
+
 enum VisitState { kUnvisited = 0, kOnStack = 1, kRevisit = 2, kVisited = 3 };
 enum Decision { kFalse, kUnknown, kTrue };
 
@@ -42,9 +47,6 @@ class ReachabilityMarker : public NodeMarker<uint8_t> {
 };
 
 
-#define TRACE(x) \
-  if (FLAG_trace_turbo_reduction) PrintF x
-
 class ControlReducerImpl {
  public:
   ControlReducerImpl(Zone* zone, JSGraph* jsgraph,
@@ -104,41 +106,46 @@ class ControlReducerImpl {
     marked.Push(start);
     marked.SetReachableFromStart(start);
 
-    // We use a stack of (Node, Node::Uses::const_iterator) pairs to avoid
+    // We use a stack of (Node, Node::UseEdges::iterator) pairs to avoid
     // O(n^2) traversal.
-    typedef std::pair<Node*, Node::Uses::const_iterator> FwIter;
+    typedef std::pair<Node*, Node::UseEdges::iterator> FwIter;
     ZoneVector<FwIter> fw_stack(zone_);
-    fw_stack.push_back(FwIter(start, start->uses().begin()));
+    fw_stack.push_back(FwIter(start, start->use_edges().begin()));
 
     while (!fw_stack.empty()) {
       Node* node = fw_stack.back().first;
-      TRACE(("ControlFw: #%d:%s\n", node->id(), node->op()->mnemonic()));
+      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());
+      while (fw_stack.back().second != node->use_edges().end()) {
+        Edge edge = *(fw_stack.back().second);
+        if (NodeProperties::IsControlEdge(edge) &&
+            edge.from()->op()->ControlOutputCount() > 0) {
+          // Only walk control edges to control nodes.
+          Node* succ = edge.from();
+
+          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->use_edges().begin());
+            }
+            pop = false;  // restart traversing successors of this node.
+            break;
+          }
+          if (!marked.IsReachableFromStart(succ)) {
+            // {succ} is not yet reached from start.
+            marked.Push(succ);
+            marked.SetReachableFromStart(succ);
+            fw_stack.push_back(FwIter(succ, succ->use_edges().begin()));
+            pop = false;  // "recurse" into successor control node.
+            break;
           }
-          pop = false;  // restart traversing successors of this node.
-          break;
-        }
-        if (NodeProperties::IsControl(succ) &&
-            !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;
       }
@@ -155,7 +162,7 @@ class ControlReducerImpl {
     // 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 (NodeProperties::IsControl(node) &&
+      if (node->op()->ControlOutputCount() > 0 &&
           !marked.IsReachableFromStart(node)) {
         ReplaceNode(node, dead());  // uses will be added to revisit queue.
       }
@@ -165,7 +172,8 @@ class ControlReducerImpl {
 
   // 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()));
+    TRACE("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic());
+    DCHECK_EQ(IrOpcode::kLoop, loop->opcode());
 
     Node* always = graph()->NewNode(common_->Always());
     // Mark the node as visited so that we can revisit later.
@@ -190,16 +198,14 @@ class ControlReducerImpl {
       DCHECK(NodeProperties::IsControlEdge(edge));
       if (edge.from() == branch) continue;
       switch (edge.from()->opcode()) {
-#define CASE(Opcode) case IrOpcode::k##Opcode:
-        CONTROL_OP_LIST(CASE)
-#undef CASE
-          // Update all control nodes (except {branch}) pointing to the {loop}.
-          edge.UpdateTo(if_true);
+        case IrOpcode::kPhi:
           break;
         case IrOpcode::kEffectPhi:
           effects.push_back(edge.from());
           break;
         default:
+          // Update all control edges (except {branch}) pointing to the {loop}.
+          edge.UpdateTo(if_true);
           break;
       }
     }
@@ -282,9 +288,9 @@ class ControlReducerImpl {
       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()));
+          TRACE("DeadLink: #%d:%s(%d) -> #%d:%s\n", use->id(),
+                use->op()->mnemonic(), edge.index(), node->id(),
+                node->op()->mnemonic());
           edge.UpdateTo(NULL);
         }
       }
@@ -324,7 +330,7 @@ class ControlReducerImpl {
 
     if (node->IsDead()) return Pop();  // Node was killed while on stack.
 
-    TRACE(("ControlReduce: #%d:%s\n", node->id(), node->op()->mnemonic()));
+    TRACE("ControlReduce: #%d:%s\n", node->id(), node->op()->mnemonic());
 
     // Recurse on an input if necessary.
     for (Node* const input : node->inputs()) {
@@ -376,7 +382,7 @@ class ControlReducerImpl {
   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()));
+      TRACE("  Revisit #%d:%s\n", node->id(), node->op()->mnemonic());
       state_[id] = kRevisit;
       revisit_.push_back(node);
     }
@@ -400,7 +406,7 @@ class ControlReducerImpl {
       // 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()));
+        TRACE("ControlDead: #%d:%s\n", node->id(), node->op()->mnemonic());
         return control;
       }
     }
@@ -509,10 +515,8 @@ class ControlReducerImpl {
       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));
+    TRACE("ReduceMerge: #%d:%s (%d of %d live)\n", node->id(),
+          node->op()->mnemonic(), live, index);
 
     if (live == 0) return dead();  // no remaining inputs.
 
@@ -529,15 +533,46 @@ class ControlReducerImpl {
       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);
+    DCHECK_LE(2, live);
+
+    if (live < node->InputCount()) {
+      // 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);
+    }
+
+    DCHECK_EQ(live, node->InputCount());
+
+    // Check if it's an unused diamond.
+    if (live == 2 && phis.empty()) {
+      Node* node0 = node->InputAt(0);
+      Node* node1 = node->InputAt(1);
+      if (((node0->opcode() == IrOpcode::kIfTrue &&
+            node1->opcode() == IrOpcode::kIfFalse) ||
+           (node1->opcode() == IrOpcode::kIfTrue &&
+            node0->opcode() == IrOpcode::kIfFalse)) &&
+          node0->OwnedBy(node) && node1->OwnedBy(node)) {
+        Node* branch0 = NodeProperties::GetControlInput(node0);
+        Node* branch1 = NodeProperties::GetControlInput(node1);
+        if (branch0 == branch1) {
+          // It's a dead diamond, i.e. neither the IfTrue nor the IfFalse nodes
+          // have users except for the Merge and the Merge has no Phi or
+          // EffectPhi uses, so replace the Merge with the control input of the
+          // diamond.
+          TRACE("  DeadDiamond: #%d:%s #%d:%s #%d:%s\n", node0->id(),
+                node0->op()->mnemonic(), node1->id(), node1->op()->mnemonic(),
+                branch0->id(), branch0->op()->mnemonic());
+          return NodeProperties::GetControlInput(branch0);
+        }
+      }
     }
-    // Edit the merge in place, removing dead inputs.
-    RemoveDeadInputs(node, node);
+
     return node;
   }
 
@@ -548,8 +583,8 @@ class ControlReducerImpl {
     Decision result = DecideCondition(branch->InputAt(0));
     if (result == kTrue) {
       // fold a true branch by replacing IfTrue with the branch control.
-      TRACE(("BranchReduce: #%d:%s => #%d:%s\n", branch->id(),
-             branch->op()->mnemonic(), node->id(), node->op()->mnemonic()));
+      TRACE("  BranchReduce: #%d:%s => #%d:%s\n", branch->id(),
+            branch->op()->mnemonic(), node->id(), node->op()->mnemonic());
       return branch->InputAt(1);
     }
     return result == kUnknown ? node : dead();
@@ -562,8 +597,8 @@ class ControlReducerImpl {
     Decision result = DecideCondition(branch->InputAt(0));
     if (result == kFalse) {
       // fold a false branch by replacing IfFalse with the branch control.
-      TRACE(("BranchReduce: #%d:%s => #%d:%s\n", branch->id(),
-             branch->op()->mnemonic(), node->id(), node->op()->mnemonic()));
+      TRACE("  BranchReduce: #%d:%s => #%d:%s\n", branch->id(),
+            branch->op()->mnemonic(), node->id(), node->op()->mnemonic());
       return branch->InputAt(1);
     }
     return result == kUnknown ? node : dead();
@@ -595,9 +630,8 @@ class ControlReducerImpl {
   // 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()));
+    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);
diff --git a/deps/v8/src/compiler/generic-algorithm.h b/deps/v8/src/compiler/generic-algorithm.h
deleted file mode 100644 (file)
index 391757e..0000000
+++ /dev/null
@@ -1,120 +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_H_
-#define V8_COMPILER_GENERIC_ALGORITHM_H_
-
-#include <stack>
-#include <vector>
-
-#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.
-class GenericGraphVisit {
- public:
-  // struct Visitor {
-  //   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>
-  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(graph->NodeCount(), false, zone);
-    Node* current = *root_begin;
-    while (true) {
-      DCHECK(current != NULL);
-      const int id = current->id();
-      DCHECK(id >= 0);
-      DCHECK(id < graph->NodeCount());  // Must be a valid id.
-      bool visit = !GetVisited(&visited, id);
-      if (visit) {
-        visitor->Pre(current);
-        SetVisited(&visited, id);
-      }
-      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) {
-            visitor->Post(post_order_node);
-            SetVisited(&visited, post_order_node->id());
-          }
-          stack.pop();
-          if (stack.empty()) {
-            if (++root_begin == root_end) return;
-            current = *root_begin;
-            break;
-          }
-          post_order_node = (*stack.top().first).from();
-          visit = true;
-        } else {
-          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((*top.first).from(), (*top.first).index(),
-                          (*top.first).to());
-        ++stack.top().first;
-      }
-    }
-  }
-
-  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);
-  }
-
-  struct NullNodeVisitor {
-    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 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) = true;
-  }
-
-  static bool GetVisited(BoolVector* visited, int id) {
-    if (id >= static_cast<int>(visited->size())) return false;
-    return visited->at(id);
-  }
-};
-
-typedef GenericGraphVisit::NullNodeVisitor NullNodeVisitor;
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
-
-#endif  // V8_COMPILER_GENERIC_ALGORITHM_H_
diff --git a/deps/v8/src/compiler/graph-inl.h b/deps/v8/src/compiler/graph-inl.h
deleted file mode 100644 (file)
index 3a21737..0000000
+++ /dev/null
@@ -1,25 +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_GRAPH_INL_H_
-#define V8_COMPILER_GRAPH_INL_H_
-
-#include "src/compiler/generic-algorithm.h"
-#include "src/compiler/graph.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-template <class Visitor>
-void Graph::VisitNodeInputsFromEnd(Visitor* visitor) {
-  Zone tmp_zone;
-  GenericGraphVisit::Visit<Visitor>(this, &tmp_zone, end(), visitor);
-}
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
-
-#endif  // V8_COMPILER_GRAPH_INL_H_
index 42d355f..2d313f3 100644 (file)
@@ -27,9 +27,9 @@ namespace compiler {
 
 FILE* OpenVisualizerLogFile(CompilationInfo* info, const char* phase,
                             const char* suffix, const char* mode) {
-  EmbeddedVector<char, 256> filename;
+  EmbeddedVector<char, 256> filename(0);
   SmartArrayPointer<char> function_name;
-  if (!info->shared_info().is_null()) {
+  if (info->has_shared_info()) {
     function_name = info->shared_info()->DebugName()->ToCString();
     if (strlen(function_name.get()) > 0) {
       SNPrintF(filename, "turbo-%s", function_name.get());
@@ -361,9 +361,17 @@ void GraphVisualizer::Print() {
       << "  concentrate=\"true\"\n"
       << "  \n";
 
+  // Find all nodes that are not reachable from end that use live nodes.
+  std::set<Node*> gray;
+  for (Node* const node : all_.live) {
+    for (Node* const use : node->uses()) {
+      if (!all_.IsLive(use)) gray.insert(use);
+    }
+  }
+
   // Make sure all nodes have been output before writing out the edges.
   for (Node* const node : all_.live) PrintNode(node, false);
-  for (Node* const node : all_.gray) PrintNode(node, true);
+  for (Node* const node : gray) PrintNode(node, true);
 
   // With all the nodes written, add the edges.
   for (Node* const node : all_.live) {
@@ -398,7 +406,7 @@ class GraphC1Visualizer {
   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 PrintBlockProperty(const char* name, int rpo_number);
   void PrintNodeId(Node* n);
   void PrintNode(Node* n);
   void PrintInputs(Node* n);
@@ -461,10 +469,9 @@ void GraphC1Visualizer::PrintLongProperty(const char* name, int64_t value) {
 }
 
 
-void GraphC1Visualizer::PrintBlockProperty(const char* name,
-                                           BasicBlock::Id block_id) {
+void GraphC1Visualizer::PrintBlockProperty(const char* name, int rpo_number) {
   PrintIndent();
-  os_ << name << " \"B" << block_id << "\"\n";
+  os_ << name << " \"B" << rpo_number << "\"\n";
 }
 
 
@@ -550,21 +557,21 @@ void GraphC1Visualizer::PrintSchedule(const char* phase,
   for (size_t i = 0; i < rpo->size(); i++) {
     BasicBlock* current = (*rpo)[i];
     Tag block_tag(this, "block");
-    PrintBlockProperty("name", current->id());
+    PrintBlockProperty("name", current->rpo_number());
     PrintIntProperty("from_bci", -1);
     PrintIntProperty("to_bci", -1);
 
     PrintIndent();
     os_ << "predecessors";
     for (BasicBlock* predecessor : current->predecessors()) {
-      os_ << " \"B" << predecessor->id() << "\"";
+      os_ << " \"B" << predecessor->rpo_number() << "\"";
     }
     os_ << "\n";
 
     PrintIndent();
     os_ << "successors";
     for (BasicBlock* successor : current->successors()) {
-      os_ << " \"B" << successor->id() << "\"";
+      os_ << " \"B" << successor->rpo_number() << "\"";
     }
     os_ << "\n";
 
@@ -575,13 +582,14 @@ void GraphC1Visualizer::PrintSchedule(const char* phase,
     os_ << "flags\n";
 
     if (current->dominator() != NULL) {
-      PrintBlockProperty("dominator", current->dominator()->id());
+      PrintBlockProperty("dominator", current->dominator()->rpo_number());
     }
 
     PrintIntProperty("loop_depth", current->loop_depth());
 
     const InstructionBlock* instruction_block =
-        instructions->InstructionBlockAt(current->GetRpoNumber());
+        instructions->InstructionBlockAt(
+            RpoNumber::FromInt(current->rpo_number()));
     if (instruction_block->code_start() >= 0) {
       int first_index = instruction_block->first_instruction_index();
       int last_index = instruction_block->last_instruction_index();
@@ -646,11 +654,11 @@ void GraphC1Visualizer::PrintSchedule(const char* phase,
         if (current->control_input() != NULL) {
           PrintNode(current->control_input());
         } else {
-          os_ << -1 - current->id().ToInt() << " Goto";
+          os_ << -1 - current->rpo_number() << " Goto";
         }
         os_ << " ->";
         for (BasicBlock* successor : current->successors()) {
-          os_ << " B" << successor->id();
+          os_ << " B" << successor->rpo_number();
         }
         if (FLAG_trace_turbo_types && current->control_input() != NULL) {
           os_ << " ";
index d208489..316333b 100644 (file)
@@ -24,9 +24,11 @@ class IA32OperandConverter : public InstructionOperandConverter {
   IA32OperandConverter(CodeGenerator* gen, Instruction* instr)
       : InstructionOperandConverter(gen, instr) {}
 
-  Operand InputOperand(int index) { return ToOperand(instr_->InputAt(index)); }
+  Operand InputOperand(size_t index, int extra = 0) {
+    return ToOperand(instr_->InputAt(index), extra);
+  }
 
-  Immediate InputImmediate(int index) {
+  Immediate InputImmediate(size_t index) {
     return ToImmediate(instr_->InputAt(index));
   }
 
@@ -75,8 +77,8 @@ class IA32OperandConverter : public InstructionOperandConverter {
     return Immediate(-1);
   }
 
-  static int NextOffset(int* offset) {
-    int i = *offset;
+  static size_t NextOffset(size_t* offset) {
+    size_t i = *offset;
     (*offset)++;
     return i;
   }
@@ -91,7 +93,7 @@ class IA32OperandConverter : public InstructionOperandConverter {
     return static_cast<ScaleFactor>(scale);
   }
 
-  Operand MemoryOperand(int* offset) {
+  Operand MemoryOperand(size_t* offset) {
     AddressingMode mode = AddressingModeField::decode(instr_->opcode());
     switch (mode) {
       case kMode_MR: {
@@ -154,7 +156,7 @@ class IA32OperandConverter : public InstructionOperandConverter {
     return Operand(no_reg, 0);
   }
 
-  Operand MemoryOperand(int first_input = 0) {
+  Operand MemoryOperand(size_t first_input = 0) {
     return MemoryOperand(&first_input);
   }
 };
@@ -162,7 +164,7 @@ class IA32OperandConverter : public InstructionOperandConverter {
 
 namespace {
 
-bool HasImmediateInput(Instruction* instr, int index) {
+bool HasImmediateInput(Instruction* instr, size_t index) {
   return instr->InputAt(index)->IsImmediate();
 }
 
@@ -292,7 +294,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         Register reg = i.InputRegister(0);
         __ call(Operand(reg, Code::kHeaderSize - kHeapObjectTag));
       }
-      AddSafepointAndDeopt(instr);
+      RecordCallPosition(instr);
       break;
     }
     case kArchCallJSFunction: {
@@ -304,7 +306,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         __ Assert(equal, kWrongFunctionContext);
       }
       __ call(FieldOperand(func, JSFunction::kCodeEntryOffset));
-      AddSafepointAndDeopt(instr);
+      RecordCallPosition(instr);
       break;
     }
     case kArchJmp:
@@ -319,6 +321,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArchNop:
       // don't emit code for nops.
       break;
+    case kArchDeoptimize: {
+      int deopt_state_id =
+          BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
+      AssembleDeoptimizerCall(deopt_state_id, Deoptimizer::EAGER);
+      break;
+    }
     case kArchRet:
       AssembleReturn();
       break;
@@ -439,6 +447,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         __ ror_cl(i.OutputOperand());
       }
       break;
+    case kIA32Lzcnt:
+      __ Lzcnt(i.OutputRegister(), i.InputOperand(0));
+      break;
     case kSSEFloat64Cmp:
       __ ucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
       break;
@@ -454,6 +465,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kSSEFloat64Div:
       __ divsd(i.InputDoubleRegister(0), i.InputOperand(1));
       break;
+    case kSSEFloat64Max:
+      __ maxsd(i.InputDoubleRegister(0), i.InputOperand(1));
+      break;
+    case kSSEFloat64Min:
+      __ minsd(i.InputDoubleRegister(0), i.InputOperand(1));
+      break;
     case kSSEFloat64Mod: {
       // TODO(dcarney): alignment is wrong.
       __ sub(esp, Immediate(kDoubleSize));
@@ -482,22 +499,11 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     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: {
+    case kSSEFloat64Round: {
       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);
+      RoundingMode const mode =
+          static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
+      __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
       break;
     }
     case kSSECvtss2sd:
@@ -523,6 +529,29 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kSSEUint32ToFloat64:
       __ LoadUint32(i.OutputDoubleRegister(), i.InputOperand(0));
       break;
+    case kSSEFloat64ExtractLowWord32:
+      if (instr->InputAt(0)->IsDoubleStackSlot()) {
+        __ mov(i.OutputRegister(), i.InputOperand(0));
+      } else {
+        __ movd(i.OutputRegister(), i.InputDoubleRegister(0));
+      }
+      break;
+    case kSSEFloat64ExtractHighWord32:
+      if (instr->InputAt(0)->IsDoubleStackSlot()) {
+        __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
+      } else {
+        __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1);
+      }
+      break;
+    case kSSEFloat64InsertLowWord32:
+      __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0);
+      break;
+    case kSSEFloat64InsertHighWord32:
+      __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1);
+      break;
+    case kSSEFloat64LoadLowWord32:
+      __ movd(i.OutputDoubleRegister(), i.InputOperand(0));
+      break;
     case kAVXFloat64Add: {
       CpuFeatureScope avx_scope(masm(), AVX);
       __ vaddsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
@@ -547,6 +576,18 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
                 i.InputOperand(1));
       break;
     }
+    case kAVXFloat64Max: {
+      CpuFeatureScope avx_scope(masm(), AVX);
+      __ vmaxsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                i.InputOperand(1));
+      break;
+    }
+    case kAVXFloat64Min: {
+      CpuFeatureScope avx_scope(masm(), AVX);
+      __ vminsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                i.InputOperand(1));
+      break;
+    }
     case kIA32Movsxbl:
       __ movsx_b(i.OutputRegister(), i.MemoryOperand());
       break;
@@ -554,7 +595,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ movzx_b(i.OutputRegister(), i.MemoryOperand());
       break;
     case kIA32Movb: {
-      int index = 0;
+      size_t index = 0;
       Operand operand = i.MemoryOperand(&index);
       if (HasImmediateInput(instr, index)) {
         __ mov_b(operand, i.InputInt8(index));
@@ -570,7 +611,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ movzx_w(i.OutputRegister(), i.MemoryOperand());
       break;
     case kIA32Movw: {
-      int index = 0;
+      size_t index = 0;
       Operand operand = i.MemoryOperand(&index);
       if (HasImmediateInput(instr, index)) {
         __ mov_w(operand, i.InputInt16(index));
@@ -583,7 +624,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       if (instr->HasOutput()) {
         __ mov(i.OutputRegister(), i.MemoryOperand());
       } else {
-        int index = 0;
+        size_t index = 0;
         Operand operand = i.MemoryOperand(&index);
         if (HasImmediateInput(instr, index)) {
           __ mov(operand, i.InputImmediate(index));
@@ -596,7 +637,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       if (instr->HasOutput()) {
         __ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
       } else {
-        int index = 0;
+        size_t index = 0;
         Operand operand = i.MemoryOperand(&index);
         __ movsd(operand, i.InputDoubleRegister(index));
       }
@@ -605,7 +646,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       if (instr->HasOutput()) {
         __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
       } else {
-        int index = 0;
+        size_t index = 0;
         Operand operand = i.MemoryOperand(&index);
         __ movss(operand, i.InputDoubleRegister(index));
       }
@@ -699,6 +740,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kCheckedStoreFloat64:
       ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
       break;
+    case kIA32StackCheck: {
+      ExternalReference const stack_limit =
+          ExternalReference::address_of_stack_limit(isolate());
+      __ cmp(esp, Operand::StaticVariable(stack_limit));
+      break;
+    }
   }
 }
 
@@ -759,7 +806,7 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
 }
 
 
-void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+void CodeGenerator::AssembleArchJump(RpoNumber target) {
   if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
 }
 
@@ -868,9 +915,10 @@ void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
 }
 
 
-void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
+void CodeGenerator::AssembleDeoptimizerCall(
+    int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
-      isolate(), deoptimization_id, Deoptimizer::LAZY);
+      isolate(), deoptimization_id, bailout_type);
   __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
 }
 
@@ -1043,6 +1091,8 @@ void CodeGenerator::AssemblePrologue() {
     // remaining stack slots.
     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
     osr_pc_offset_ = __ pc_offset();
+    // TODO(titzer): cannot address target function == local #-1
+    __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
     DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
     stack_slots -= frame()->GetOsrStackSlotCount();
   }
@@ -1117,7 +1167,19 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
     Constant src_constant = g.ToConstant(source);
     if (src_constant.type() == Constant::kHeapObject) {
       Handle<HeapObject> src = src_constant.ToHeapObject();
-      if (destination->IsRegister()) {
+      if (info()->IsOptimizing() && src.is_identical_to(info()->context())) {
+        // Loading the context from the frame is way cheaper than materializing
+        // the actual context heap object address.
+        if (destination->IsRegister()) {
+          Register dst = g.ToRegister(destination);
+          __ mov(dst, Operand(ebp, StandardFrameConstants::kContextOffset));
+        } else {
+          DCHECK(destination->IsStackSlot());
+          Operand dst = g.ToOperand(destination);
+          __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
+          __ pop(dst);
+        }
+      } else if (destination->IsRegister()) {
         Register dst = g.ToRegister(destination);
         __ LoadHeapObject(dst, src);
       } else {
index ec9fd18..b7a9e82 100644 (file)
@@ -30,26 +30,34 @@ namespace compiler {
   V(IA32Shr)                       \
   V(IA32Sar)                       \
   V(IA32Ror)                       \
+  V(IA32Lzcnt)                     \
   V(SSEFloat64Cmp)                 \
   V(SSEFloat64Add)                 \
   V(SSEFloat64Sub)                 \
   V(SSEFloat64Mul)                 \
   V(SSEFloat64Div)                 \
   V(SSEFloat64Mod)                 \
+  V(SSEFloat64Max)                 \
+  V(SSEFloat64Min)                 \
   V(SSEFloat64Sqrt)                \
-  V(SSEFloat64Floor)               \
-  V(SSEFloat64Ceil)                \
-  V(SSEFloat64RoundTruncate)       \
+  V(SSEFloat64Round)               \
   V(SSECvtss2sd)                   \
   V(SSECvtsd2ss)                   \
   V(SSEFloat64ToInt32)             \
   V(SSEFloat64ToUint32)            \
   V(SSEInt32ToFloat64)             \
   V(SSEUint32ToFloat64)            \
+  V(SSEFloat64ExtractLowWord32)    \
+  V(SSEFloat64ExtractHighWord32)   \
+  V(SSEFloat64InsertLowWord32)     \
+  V(SSEFloat64InsertHighWord32)    \
+  V(SSEFloat64LoadLowWord32)       \
   V(AVXFloat64Add)                 \
   V(AVXFloat64Sub)                 \
   V(AVXFloat64Mul)                 \
   V(AVXFloat64Div)                 \
+  V(AVXFloat64Max)                 \
+  V(AVXFloat64Min)                 \
   V(IA32Movsxbl)                   \
   V(IA32Movzxbl)                   \
   V(IA32Movb)                      \
@@ -61,7 +69,8 @@ namespace compiler {
   V(IA32Movsd)                     \
   V(IA32Lea)                       \
   V(IA32Push)                      \
-  V(IA32StoreWriteBarrier)
+  V(IA32StoreWriteBarrier)         \
+  V(IA32StackCheck)
 
 
 // Addressing modes represent the "shape" of inputs to an instruction.
index beec701..5835d13 100644 (file)
@@ -17,10 +17,15 @@ class IA32OperandGenerator FINAL : public OperandGenerator {
       : OperandGenerator(selector) {}
 
   InstructionOperand UseByteRegister(Node* node) {
-    // TODO(dcarney): relax constraint.
+    // TODO(titzer): encode byte register use constraints.
     return UseFixed(node, edx);
   }
 
+  InstructionOperand DefineAsByteRegister(Node* node) {
+    // TODO(titzer): encode byte register def constraints.
+    return DefineAsRegister(node);
+  }
+
   bool CanBeImmediate(Node* node) {
     switch (node->opcode()) {
       case IrOpcode::kInt32Constant:
@@ -119,8 +124,8 @@ class IA32OperandGenerator FINAL : public OperandGenerator {
 };
 
 
-static void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
-                           Node* node) {
+static void VisitRRFloat64(InstructionSelector* selector,
+                           InstructionCode opcode, Node* node) {
   IA32OperandGenerator g(selector);
   selector->Emit(opcode, g.DefineAsRegister(node),
                  g.UseRegister(node->InputAt(0)));
@@ -132,7 +137,6 @@ void InstructionSelector::VisitLoad(Node* node) {
   MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
 
   ArchOpcode opcode;
-  // TODO(titzer): signed/unsigned small loads
   switch (rep) {
     case kRepFloat32:
       opcode = kIA32Movss;
@@ -366,8 +370,7 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
 
   outputs[output_count++] = g.DefineSameAsFirst(node);
   if (cont->IsSet()) {
-    // TODO(turbofan): Use byte register here.
-    outputs[output_count++] = g.DefineAsRegister(cont->result());
+    outputs[output_count++] = g.DefineAsByteRegister(cont->result());
   }
 
   DCHECK_NE(0u, input_count);
@@ -375,9 +378,8 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
   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();
+  selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
+                 inputs);
 }
 
 
@@ -462,7 +464,7 @@ void EmitLea(InstructionSelector* selector, Node* result, Node* index,
   AddressingMode mode = g.GenerateMemoryOperandInputs(
       index, scale, base, displacement, inputs, &input_count);
 
-  DCHECK_NE(0, static_cast<int>(input_count));
+  DCHECK_NE(0u, input_count);
   DCHECK_GE(arraysize(inputs), input_count);
 
   InstructionOperand outputs[1];
@@ -503,6 +505,12 @@ void InstructionSelector::VisitWord32Ror(Node* node) {
 }
 
 
+void InstructionSelector::VisitWord32Clz(Node* node) {
+  IA32OperandGenerator g(this);
+  Emit(kIA32Lzcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitInt32Add(Node* node) {
   IA32OperandGenerator g(this);
 
@@ -515,7 +523,7 @@ void InstructionSelector::VisitInt32Add(Node* node) {
     AddressingMode mode = g.GenerateMemoryOperandInputs(
         m.index(), m.scale(), m.base(), m.displacement(), inputs, &input_count);
 
-    DCHECK_NE(0, static_cast<int>(input_count));
+    DCHECK_NE(0u, input_count);
     DCHECK_GE(arraysize(inputs), input_count);
 
     InstructionOperand outputs[1];
@@ -646,6 +654,19 @@ void InstructionSelector::VisitFloat64Add(Node* node) {
 
 void InstructionSelector::VisitFloat64Sub(Node* node) {
   IA32OperandGenerator g(this);
+  Float64BinopMatcher m(node);
+  if (m.left().IsMinusZero() && m.right().IsFloat64RoundDown() &&
+      CanCover(m.node(), m.right().node())) {
+    if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
+        CanCover(m.right().node(), m.right().InputAt(0))) {
+      Float64BinopMatcher mright0(m.right().InputAt(0));
+      if (mright0.left().IsMinusZero()) {
+        Emit(kSSEFloat64Round | MiscField::encode(kRoundUp),
+             g.DefineAsRegister(node), g.UseRegister(mright0.right().node()));
+        return;
+      }
+    }
+  }
   if (IsSupported(AVX)) {
     Emit(kAVXFloat64Sub, g.DefineAsRegister(node),
          g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
@@ -689,27 +710,44 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
 }
 
 
-void InstructionSelector::VisitFloat64Sqrt(Node* node) {
+void InstructionSelector::VisitFloat64Max(Node* node) {
   IA32OperandGenerator g(this);
-  Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+  if (IsSupported(AVX)) {
+    Emit(kAVXFloat64Max, g.DefineAsRegister(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  } else {
+    Emit(kSSEFloat64Max, g.DefineSameAsFirst(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  }
+}
+
+
+void InstructionSelector::VisitFloat64Min(Node* node) {
+  IA32OperandGenerator g(this);
+  if (IsSupported(AVX)) {
+    Emit(kAVXFloat64Min, g.DefineAsRegister(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  } else {
+    Emit(kSSEFloat64Min, g.DefineSameAsFirst(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  }
 }
 
 
-void InstructionSelector::VisitFloat64Floor(Node* node) {
-  DCHECK(CpuFeatures::IsSupported(SSE4_1));
-  VisitRRFloat64(this, kSSEFloat64Floor, node);
+void InstructionSelector::VisitFloat64Sqrt(Node* node) {
+  IA32OperandGenerator g(this);
+  Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
 }
 
 
-void InstructionSelector::VisitFloat64Ceil(Node* node) {
-  DCHECK(CpuFeatures::IsSupported(SSE4_1));
-  VisitRRFloat64(this, kSSEFloat64Ceil, node);
+void InstructionSelector::VisitFloat64RoundDown(Node* node) {
+  VisitRRFloat64(this, kSSEFloat64Round | MiscField::encode(kRoundDown), node);
 }
 
 
 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
-  DCHECK(CpuFeatures::IsSupported(SSE4_1));
-  VisitRRFloat64(this, kSSEFloat64RoundTruncate, node);
+  VisitRRFloat64(this, kSSEFloat64Round | MiscField::encode(kRoundToZero),
+                 node);
 }
 
 
@@ -718,7 +756,7 @@ void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
 }
 
 
-void InstructionSelector::VisitCall(Node* node) {
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
   IA32OperandGenerator g(this);
   const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
 
@@ -745,6 +783,13 @@ void InstructionSelector::VisitCall(Node* node) {
     Emit(kIA32Push, g.NoOutput(), value);
   }
 
+  // Pass label of exception handler block.
+  CallDescriptor::Flags flags = descriptor->flags();
+  if (handler != nullptr) {
+    flags |= CallDescriptor::kHasExceptionHandler;
+    buffer.instruction_args.push_back(g.Label(handler));
+  }
+
   // Select the appropriate opcode based on the call type.
   InstructionCode opcode;
   switch (descriptor->kind()) {
@@ -759,7 +804,7 @@ void InstructionSelector::VisitCall(Node* node) {
       UNREACHABLE();
       return;
   }
-  opcode |= MiscField::encode(descriptor->flags());
+  opcode |= MiscField::encode(flags);
 
   // Emit the call instruction.
   InstructionOperand* first_output =
@@ -780,12 +825,10 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
   IA32OperandGenerator g(selector);
   if (cont->IsBranch()) {
     selector->Emit(cont->Encode(opcode), g.NoOutput(), left, right,
-                   g.Label(cont->true_block()),
-                   g.Label(cont->false_block()))->MarkAsControl();
+                   g.Label(cont->true_block()), g.Label(cont->false_block()));
   } else {
     DCHECK(cont->IsSet());
-    // TODO(titzer): Needs byte register.
-    selector->Emit(cont->Encode(opcode), g.DefineAsRegister(cont->result()),
+    selector->Emit(cont->Encode(opcode), g.DefineAsByteRegister(cont->result()),
                    left, right);
   }
 }
@@ -834,6 +877,26 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
 
 void VisitWordCompare(InstructionSelector* selector, Node* node,
                       FlagsContinuation* cont) {
+  IA32OperandGenerator g(selector);
+  Int32BinopMatcher m(node);
+  if (m.left().IsLoad() && m.right().IsLoadStackPointer()) {
+    LoadMatcher<ExternalReferenceMatcher> mleft(m.left().node());
+    ExternalReference js_stack_limit =
+        ExternalReference::address_of_stack_limit(selector->isolate());
+    if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) {
+      // Compare(Load(js_stack_limit), LoadStackPointer)
+      if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
+      InstructionCode opcode = cont->Encode(kIA32StackCheck);
+      if (cont->IsBranch()) {
+        selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()),
+                       g.Label(cont->false_block()));
+      } else {
+        DCHECK(cont->IsSet());
+        selector->Emit(opcode, g.DefineAsRegister(cont->result()));
+      }
+      return;
+    }
+  }
   VisitWordCompare(selector, node, kIA32Cmp, cont);
 }
 
@@ -928,64 +991,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
 }
 
 
-void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
-                                      BasicBlock** case_branches,
-                                      int32_t* case_values, size_t case_count,
-                                      int32_t min_value, int32_t max_value) {
+void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
   IA32OperandGenerator g(this);
   InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
-  InstructionOperand default_operand = g.Label(default_branch);
 
-  // Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value}
-  // is 2^31-1, so don't assume that it's non-zero below.
-  size_t value_range =
-      1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
-
-  // Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
-  // instruction.
-  size_t table_space_cost = 4 + value_range;
+  // Emit either ArchTableSwitch or ArchLookupSwitch.
+  size_t table_space_cost = 4 + sw.value_range;
   size_t table_time_cost = 3;
-  size_t lookup_space_cost = 3 + 2 * case_count;
-  size_t lookup_time_cost = case_count;
-  if (case_count > 4 &&
+  size_t lookup_space_cost = 3 + 2 * sw.case_count;
+  size_t lookup_time_cost = sw.case_count;
+  if (sw.case_count > 4 &&
       table_space_cost + 3 * table_time_cost <=
           lookup_space_cost + 3 * lookup_time_cost &&
-      min_value > std::numeric_limits<int32_t>::min()) {
+      sw.min_value > std::numeric_limits<int32_t>::min()) {
     InstructionOperand index_operand = value_operand;
-    if (min_value) {
+    if (sw.min_value) {
       index_operand = g.TempRegister();
       Emit(kIA32Lea | AddressingModeField::encode(kMode_MRI), index_operand,
-           value_operand, g.TempImmediate(-min_value));
-    }
-    size_t input_count = 2 + value_range;
-    auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
-    inputs[0] = index_operand;
-    std::fill(&inputs[1], &inputs[input_count], default_operand);
-    for (size_t index = 0; index < case_count; ++index) {
-      size_t value = case_values[index] - min_value;
-      BasicBlock* branch = case_branches[index];
-      DCHECK_LE(0u, value);
-      DCHECK_LT(value + 2, input_count);
-      inputs[value + 2] = g.Label(branch);
+           value_operand, g.TempImmediate(-sw.min_value));
     }
-    Emit(kArchTableSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
-        ->MarkAsControl();
-    return;
+    // Generate a table lookup.
+    return EmitTableSwitch(sw, index_operand);
   }
 
   // Generate a sequence of conditional jumps.
-  size_t input_count = 2 + case_count * 2;
-  auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
-  inputs[0] = value_operand;
-  inputs[1] = default_operand;
-  for (size_t index = 0; index < case_count; ++index) {
-    int32_t value = case_values[index];
-    BasicBlock* branch = case_branches[index];
-    inputs[index * 2 + 2 + 0] = g.TempImmediate(value);
-    inputs[index * 2 + 2 + 1] = g.Label(branch);
-  }
-  Emit(kArchLookupSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
-      ->MarkAsControl();
+  return EmitLookupSwitch(sw, value_operand);
 }
 
 
@@ -1061,16 +1091,55 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
+  IA32OperandGenerator g(this);
+  Emit(kSSEFloat64ExtractLowWord32, g.DefineAsRegister(node),
+       g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
+  IA32OperandGenerator g(this);
+  Emit(kSSEFloat64ExtractHighWord32, g.DefineAsRegister(node),
+       g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
+  IA32OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Float64Matcher mleft(left);
+  if (mleft.HasValue() && (bit_cast<uint64_t>(mleft.Value()) >> 32) == 0u) {
+    Emit(kSSEFloat64LoadLowWord32, g.DefineAsRegister(node), g.Use(right));
+    return;
+  }
+  Emit(kSSEFloat64InsertLowWord32, g.DefineSameAsFirst(node),
+       g.UseRegister(left), g.Use(right));
+}
+
+
+void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
+  IA32OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Emit(kSSEFloat64InsertHighWord32, g.DefineSameAsFirst(node),
+       g.UseRegister(left), g.Use(right));
+}
+
+
 // static
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
+  MachineOperatorBuilder::Flags flags =
+      MachineOperatorBuilder::kFloat64Max |
+      MachineOperatorBuilder::kFloat64Min |
+      MachineOperatorBuilder::kWord32ShiftIsSafe;
   if (CpuFeatures::IsSupported(SSE4_1)) {
-    return MachineOperatorBuilder::kFloat64Floor |
-           MachineOperatorBuilder::kFloat64Ceil |
-           MachineOperatorBuilder::kFloat64RoundTruncate |
-           MachineOperatorBuilder::kWord32ShiftIsSafe;
+    flags |= MachineOperatorBuilder::kFloat64RoundDown |
+             MachineOperatorBuilder::kFloat64RoundTruncate;
   }
-  return MachineOperatorBuilder::Flag::kNoFlags;
+  return flags;
 }
 
 }  // namespace compiler
index 19dbc43..bfe201b 100644 (file)
@@ -46,9 +46,10 @@ CallDescriptor* Linkage::GetRuntimeCallDescriptor(
 CallDescriptor* Linkage::GetStubCallDescriptor(
     Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
     int stack_parameter_count, CallDescriptor::Flags flags,
-    Operator::Properties properties) {
+    Operator::Properties properties, MachineType return_type) {
   return LH::GetStubCallDescriptor(isolate, zone, descriptor,
-                                   stack_parameter_count, flags, properties);
+                                   stack_parameter_count, flags, properties,
+                                   return_type);
 }
 
 
index ef1e942..50e0434 100644 (file)
@@ -40,6 +40,7 @@ namespace compiler {
   V(ArchLookupSwitch)       \
   V(ArchTableSwitch)        \
   V(ArchNop)                \
+  V(ArchDeoptimize)         \
   V(ArchRet)                \
   V(ArchStackPointer)       \
   V(ArchTruncateDoubleToI)  \
index 90898ba..657167e 100644 (file)
@@ -8,12 +8,24 @@
 #include "src/compiler/instruction.h"
 #include "src/compiler/instruction-selector.h"
 #include "src/compiler/linkage.h"
+#include "src/compiler/schedule.h"
 #include "src/macro-assembler.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
+// Helper struct containing data about a table or lookup switch.
+struct SwitchInfo {
+  int32_t min_value;           // minimum value of {case_values}
+  int32_t max_value;           // maximum value of {case_values}
+  size_t value_range;          // |max_value - min_value| + 1
+  size_t case_count;           // number of cases
+  int32_t* case_values;        // actual case values, unsorted
+  BasicBlock** case_branches;  // basic blocks corresponding to case values
+  BasicBlock* default_branch;  // default branch target
+};
+
 // A helper class for the instruction selector that simplifies construction of
 // Operands. This class implements a base for architecture-specific helpers.
 class OperandGenerator {
@@ -74,6 +86,11 @@ class OperandGenerator {
                                         GetVReg(node)));
   }
 
+  InstructionOperand UseUniqueSlot(Node* node) {
+    return Use(node, UnallocatedOperand(UnallocatedOperand::MUST_HAVE_SLOT,
+                                        GetVReg(node)));
+  }
+
   // 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) {
@@ -142,7 +159,8 @@ class OperandGenerator {
   }
 
   InstructionOperand Label(BasicBlock* block) {
-    int index = sequence()->AddImmediate(Constant(block->GetRpoNumber()));
+    int index = sequence()->AddImmediate(
+        Constant(RpoNumber::FromInt(block->rpo_number())));
     return ImmediateOperand(index);
   }
 
index 41b957a..028b914 100644 (file)
@@ -10,6 +10,8 @@
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties.h"
 #include "src/compiler/pipeline.h"
+#include "src/compiler/schedule.h"
+#include "src/compiler/state-values-utils.h"
 
 namespace v8 {
 namespace internal {
@@ -61,15 +63,15 @@ void InstructionSelector::SelectInstructions() {
   // Schedule the selected instructions.
   for (auto const block : *blocks) {
     InstructionBlock* instruction_block =
-        sequence()->InstructionBlockAt(block->GetRpoNumber());
+        sequence()->InstructionBlockAt(RpoNumber::FromInt(block->rpo_number()));
     size_t end = instruction_block->code_end();
     size_t start = instruction_block->code_start();
     DCHECK_LE(end, start);
-    sequence()->StartBlock(block->GetRpoNumber());
+    sequence()->StartBlock(RpoNumber::FromInt(block->rpo_number()));
     while (start-- > end) {
       sequence()->AddInstruction(instructions_[start]);
     }
-    sequence()->EndBlock(block->GetRpoNumber());
+    sequence()->EndBlock(RpoNumber::FromInt(block->rpo_number()));
   }
 }
 
@@ -398,7 +400,7 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
                         buffer->descriptor->GetInputType(0)));
       break;
   }
-  DCHECK_EQ(1, static_cast<int>(buffer->instruction_args.size()));
+  DCHECK_EQ(1u, 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):
@@ -477,7 +479,7 @@ void InstructionSelector::VisitBlock(BasicBlock* block) {
 
   // We're done with the block.
   InstructionBlock* instruction_block =
-      sequence()->InstructionBlockAt(block->GetRpoNumber());
+      sequence()->InstructionBlockAt(RpoNumber::FromInt(block->rpo_number()));
   instruction_block->set_code_start(static_cast<int>(instructions_.size()));
   instruction_block->set_code_end(current_block_end);
 
@@ -485,34 +487,33 @@ void InstructionSelector::VisitBlock(BasicBlock* block) {
 }
 
 
-namespace {
-
-V8_INLINE void CheckNoPhis(const BasicBlock* block) {
+void InstructionSelector::VisitControl(BasicBlock* block) {
 #ifdef DEBUG
-  // Branch targets should not have phis.
-  for (BasicBlock::const_iterator i = block->begin(); i != block->end(); ++i) {
-    const Node* node = *i;
-    CHECK_NE(IrOpcode::kPhi, node->opcode());
+  // SSA deconstruction requires targets of branches not to have phis.
+  // Edge split form guarantees this property, but is more strict.
+  if (block->SuccessorCount() > 1) {
+    for (BasicBlock* const successor : block->successors()) {
+      for (Node* const node : *successor) {
+        CHECK(!IrOpcode::IsPhiOpcode(node->opcode()));
+      }
+    }
   }
 #endif
-}
-
-}  // namespace
 
-
-void InstructionSelector::VisitControl(BasicBlock* block) {
   Node* input = block->control_input();
   switch (block->control()) {
     case BasicBlock::kGoto:
       return VisitGoto(block->SuccessorAt(0));
+    case BasicBlock::kCall: {
+      DCHECK_EQ(IrOpcode::kCall, input->opcode());
+      BasicBlock* success = block->SuccessorAt(0);
+      BasicBlock* exception = block->SuccessorAt(1);
+      return VisitCall(input, exception), VisitGoto(success);
+    }
     case BasicBlock::kBranch: {
       DCHECK_EQ(IrOpcode::kBranch, input->opcode());
       BasicBlock* tbranch = block->SuccessorAt(0);
       BasicBlock* fbranch = block->SuccessorAt(1);
-      // SSA deconstruction requires targets of branches not to have phis.
-      // Edge split form guarantees this property, but is more strict.
-      CheckNoPhis(tbranch);
-      CheckNoPhis(fbranch);
       if (tbranch == fbranch) return VisitGoto(tbranch);
       // Treat special Branch(Always, IfTrue, IfFalse) as Goto(IfTrue).
       Node* const condition = input->InputAt(0);
@@ -521,41 +522,48 @@ void InstructionSelector::VisitControl(BasicBlock* block) {
     }
     case BasicBlock::kSwitch: {
       DCHECK_EQ(IrOpcode::kSwitch, input->opcode());
+      SwitchInfo sw;
       // Last successor must be Default.
-      BasicBlock* default_branch = block->successors().back();
-      DCHECK_EQ(IrOpcode::kIfDefault, default_branch->front()->opcode());
-      // SSA deconstruction requires targets of branches not to have phis.
-      // Edge split form guarantees this property, but is more strict.
-      CheckNoPhis(default_branch);
+      sw.default_branch = block->successors().back();
+      DCHECK_EQ(IrOpcode::kIfDefault, sw.default_branch->front()->opcode());
       // All other successors must be cases.
-      size_t case_count = block->SuccessorCount() - 1;
-      DCHECK_LE(1u, case_count);
-      BasicBlock** case_branches = &block->successors().front();
+      sw.case_count = block->SuccessorCount() - 1;
+      DCHECK_LE(1u, sw.case_count);
+      sw.case_branches = &block->successors().front();
       // Determine case values and their min/max.
-      int32_t* case_values = zone()->NewArray<int32_t>(case_count);
-      int32_t min_value = std::numeric_limits<int32_t>::max();
-      int32_t max_value = std::numeric_limits<int32_t>::min();
-      for (size_t index = 0; index < case_count; ++index) {
-        BasicBlock* branch = case_branches[index];
+      sw.case_values = zone()->NewArray<int32_t>(sw.case_count);
+      sw.min_value = std::numeric_limits<int32_t>::max();
+      sw.max_value = std::numeric_limits<int32_t>::min();
+      for (size_t index = 0; index < sw.case_count; ++index) {
+        BasicBlock* branch = sw.case_branches[index];
         int32_t value = OpParameter<int32_t>(branch->front()->op());
-        case_values[index] = value;
-        if (min_value > value) min_value = value;
-        if (max_value < value) max_value = value;
-        // SSA deconstruction requires targets of branches not to have phis.
-        // Edge split form guarantees this property, but is more strict.
-        CheckNoPhis(branch);
+        sw.case_values[index] = value;
+        if (sw.min_value > value) sw.min_value = value;
+        if (sw.max_value < value) sw.max_value = value;
       }
-      DCHECK_LE(min_value, max_value);
-      return VisitSwitch(input, default_branch, case_branches, case_values,
-                         case_count, min_value, max_value);
+      DCHECK_LE(sw.min_value, sw.max_value);
+      // Note that {value_range} can be 0 if {min_value} is -2^31 and
+      // {max_value}
+      // is 2^31-1, so don't assume that it's non-zero below.
+      sw.value_range = 1u + bit_cast<uint32_t>(sw.max_value) -
+                       bit_cast<uint32_t>(sw.min_value);
+      return VisitSwitch(input, sw);
     }
     case BasicBlock::kReturn: {
       // If the result itself is a return, return its input.
-      Node* value = (input != NULL && input->opcode() == IrOpcode::kReturn)
+      Node* value = (input != nullptr && input->opcode() == IrOpcode::kReturn)
                         ? input->InputAt(0)
                         : input;
       return VisitReturn(value);
     }
+    case BasicBlock::kDeoptimize: {
+      // If the result itself is a return, return its input.
+      Node* value =
+          (input != nullptr && input->opcode() == IrOpcode::kDeoptimize)
+              ? input->InputAt(0)
+              : input;
+      return VisitDeoptimize(value);
+    }
     case BasicBlock::kThrow:
       DCHECK_EQ(IrOpcode::kThrow, input->opcode());
       return VisitThrow(input->InputAt(0));
@@ -571,140 +579,6 @@ void InstructionSelector::VisitControl(BasicBlock* block) {
 }
 
 
-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::kSwitch:
-    case IrOpcode::kIfValue:
-    case IrOpcode::kIfDefault:
-    case IrOpcode::kEffectPhi:
-    case IrOpcode::kEffectSet:
-    case IrOpcode::kMerge:
-      // 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::kOsrValue:
-      return kMachAnyTagged;
-    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);
@@ -721,6 +595,8 @@ void InstructionSelector::VisitNode(Node* node) {
     case IrOpcode::kBranch:
     case IrOpcode::kIfTrue:
     case IrOpcode::kIfFalse:
+    case IrOpcode::kIfSuccess:
+    case IrOpcode::kIfException:
     case IrOpcode::kSwitch:
     case IrOpcode::kIfValue:
     case IrOpcode::kIfDefault:
@@ -760,7 +636,7 @@ void InstructionSelector::VisitNode(Node* node) {
       return VisitConstant(node);
     }
     case IrOpcode::kCall:
-      return VisitCall(node);
+      return VisitCall(node, nullptr);
     case IrOpcode::kFrameState:
     case IrOpcode::kStateValues:
       return;
@@ -787,6 +663,8 @@ void InstructionSelector::VisitNode(Node* node) {
       return VisitWord32Ror(node);
     case IrOpcode::kWord32Equal:
       return VisitWord32Equal(node);
+    case IrOpcode::kWord32Clz:
+      return VisitWord32Clz(node);
     case IrOpcode::kWord64And:
       return VisitWord64And(node);
     case IrOpcode::kWord64Or:
@@ -883,6 +761,10 @@ void InstructionSelector::VisitNode(Node* node) {
       return MarkAsDouble(node), VisitFloat64Div(node);
     case IrOpcode::kFloat64Mod:
       return MarkAsDouble(node), VisitFloat64Mod(node);
+    case IrOpcode::kFloat64Min:
+      return MarkAsDouble(node), VisitFloat64Min(node);
+    case IrOpcode::kFloat64Max:
+      return MarkAsDouble(node), VisitFloat64Max(node);
     case IrOpcode::kFloat64Sqrt:
       return MarkAsDouble(node), VisitFloat64Sqrt(node);
     case IrOpcode::kFloat64Equal:
@@ -891,14 +773,20 @@ void InstructionSelector::VisitNode(Node* node) {
       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::kFloat64RoundDown:
+      return MarkAsDouble(node), VisitFloat64RoundDown(node);
     case IrOpcode::kFloat64RoundTruncate:
       return MarkAsDouble(node), VisitFloat64RoundTruncate(node);
     case IrOpcode::kFloat64RoundTiesAway:
       return MarkAsDouble(node), VisitFloat64RoundTiesAway(node);
+    case IrOpcode::kFloat64ExtractLowWord32:
+      return VisitFloat64ExtractLowWord32(node);
+    case IrOpcode::kFloat64ExtractHighWord32:
+      return VisitFloat64ExtractHighWord32(node);
+    case IrOpcode::kFloat64InsertLowWord32:
+      return MarkAsDouble(node), VisitFloat64InsertLowWord32(node);
+    case IrOpcode::kFloat64InsertHighWord32:
+      return MarkAsDouble(node), VisitFloat64InsertHighWord32(node);
     case IrOpcode::kLoadStackPointer:
       return VisitLoadStackPointer(node);
     case IrOpcode::kCheckedLoad: {
@@ -930,6 +818,43 @@ void InstructionSelector::VisitLoadStackPointer(Node* node) {
   Emit(kArchStackPointer, g.DefineAsRegister(node));
 }
 
+
+void InstructionSelector::EmitTableSwitch(const SwitchInfo& sw,
+                                          InstructionOperand& index_operand) {
+  OperandGenerator g(this);
+  size_t input_count = 2 + sw.value_range;
+  auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
+  inputs[0] = index_operand;
+  InstructionOperand default_operand = g.Label(sw.default_branch);
+  std::fill(&inputs[1], &inputs[input_count], default_operand);
+  for (size_t index = 0; index < sw.case_count; ++index) {
+    size_t value = sw.case_values[index] - sw.min_value;
+    BasicBlock* branch = sw.case_branches[index];
+    DCHECK_LE(0u, value);
+    DCHECK_LT(value + 2, input_count);
+    inputs[value + 2] = g.Label(branch);
+  }
+  Emit(kArchTableSwitch, 0, nullptr, input_count, inputs, 0, nullptr);
+}
+
+
+void InstructionSelector::EmitLookupSwitch(const SwitchInfo& sw,
+                                           InstructionOperand& value_operand) {
+  OperandGenerator g(this);
+  size_t input_count = 2 + sw.case_count * 2;
+  auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
+  inputs[0] = value_operand;
+  inputs[1] = g.Label(sw.default_branch);
+  for (size_t index = 0; index < sw.case_count; ++index) {
+    int32_t value = sw.case_values[index];
+    BasicBlock* branch = sw.case_branches[index];
+    inputs[index * 2 + 2 + 0] = g.TempImmediate(value);
+    inputs[index * 2 + 2 + 1] = g.Label(branch);
+  }
+  Emit(kArchLookupSwitch, 0, nullptr, input_count, inputs, 0, nullptr);
+}
+
+
 #endif  // V8_TURBOFAN_BACKEND
 
 // 32 bit targets do not implement the following instructions.
@@ -1037,7 +962,9 @@ void InstructionSelector::VisitPhi(Node* node) {
   PhiInstruction* phi = new (instruction_zone())
       PhiInstruction(instruction_zone(), GetVirtualRegister(node),
                      static_cast<size_t>(input_count));
-  sequence()->InstructionBlockAt(current_block_->GetRpoNumber())->AddPhi(phi);
+  sequence()
+      ->InstructionBlockAt(RpoNumber::FromInt(current_block_->rpo_number()))
+      ->AddPhi(phi);
   for (int i = 0; i < input_count; ++i) {
     Node* const input = node->InputAt(i);
     MarkAsUsed(input);
@@ -1076,7 +1003,7 @@ void InstructionSelector::VisitConstant(Node* node) {
 void InstructionSelector::VisitGoto(BasicBlock* target) {
   // jump to the next block.
   OperandGenerator g(this);
-  Emit(kArchJmp, g.NoOutput(), g.Label(target))->MarkAsControl();
+  Emit(kArchJmp, g.NoOutput(), g.Label(target));
 }
 
 
@@ -1092,20 +1019,32 @@ void InstructionSelector::VisitReturn(Node* value) {
 }
 
 
-void InstructionSelector::VisitThrow(Node* value) {
+void InstructionSelector::VisitDeoptimize(Node* value) {
+  DCHECK(FLAG_turbo_deoptimization);
+
   OperandGenerator g(this);
-  Emit(kArchNop, g.NoOutput());  // TODO(titzer)
+
+  FrameStateDescriptor* desc = GetFrameStateDescriptor(value);
+  size_t arg_count = desc->GetTotalSize() + 1;  // Include deopt id.
+
+  InstructionOperandVector args(instruction_zone());
+  args.reserve(arg_count);
+
+  InstructionSequence::StateId state_id =
+      sequence()->AddFrameStateDescriptor(desc);
+  args.push_back(g.TempImmediate(state_id.ToInt()));
+
+  AddFrameStateInputs(value, &args, desc);
+
+  DCHECK_EQ(args.size(), arg_count);
+
+  Emit(kArchDeoptimize, 0, nullptr, arg_count, &args.front(), 0, nullptr);
 }
 
 
-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)));
-  }
+void InstructionSelector::VisitThrow(Node* value) {
+  OperandGenerator g(this);
+  Emit(kArchNop, g.NoOutput());  // TODO(titzer)
 }
 
 
@@ -1113,14 +1052,15 @@ 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());
+  DCHECK_EQ(IrOpcode::kTypedStateValues, state->InputAt(0)->opcode());
+  DCHECK_EQ(IrOpcode::kTypedStateValues, state->InputAt(1)->opcode());
+  DCHECK_EQ(IrOpcode::kTypedStateValues, state->InputAt(2)->opcode());
   FrameStateCallInfo state_info = OpParameter<FrameStateCallInfo>(state);
 
-  int parameters = state->InputAt(0)->InputCount();
-  int locals = state->InputAt(1)->InputCount();
-  int stack = state->InputAt(2)->InputCount();
+  int parameters =
+      static_cast<int>(StateValuesAccess(state->InputAt(0)).size());
+  int locals = static_cast<int>(StateValuesAccess(state->InputAt(1)).size());
+  int stack = static_cast<int>(StateValuesAccess(state->InputAt(2)).size());
 
   FrameStateDescriptor* outer_state = NULL;
   Node* outer_node = state->InputAt(4);
@@ -1133,7 +1073,7 @@ FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
 }
 
 
-static InstructionOperand UseOrImmediate(OperandGenerator* g, Node* input) {
+static InstructionOperand SlotOrImmediate(OperandGenerator* g, Node* input) {
   switch (input->opcode()) {
     case IrOpcode::kInt32Constant:
     case IrOpcode::kNumberConstant:
@@ -1141,7 +1081,7 @@ static InstructionOperand UseOrImmediate(OperandGenerator* g, Node* input) {
     case IrOpcode::kHeapConstant:
       return g->UseImmediate(input);
     default:
-      return g->UseUnique(input);
+      return g->UseUniqueSlot(input);
   }
 }
 
@@ -1160,38 +1100,36 @@ void InstructionSelector::AddFrameStateInputs(
   Node* stack = state->InputAt(2);
   Node* context = state->InputAt(3);
 
-  DCHECK_EQ(IrOpcode::kStateValues, parameters->op()->opcode());
-  DCHECK_EQ(IrOpcode::kStateValues, locals->op()->opcode());
-  DCHECK_EQ(IrOpcode::kStateValues, stack->op()->opcode());
+  DCHECK_EQ(IrOpcode::kTypedStateValues, parameters->op()->opcode());
+  DCHECK_EQ(IrOpcode::kTypedStateValues, locals->op()->opcode());
+  DCHECK_EQ(IrOpcode::kTypedStateValues, stack->op()->opcode());
 
-  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());
+  DCHECK_EQ(descriptor->parameters_count(),
+            StateValuesAccess(parameters).size());
+  DCHECK_EQ(descriptor->locals_count(), StateValuesAccess(locals).size());
+  DCHECK_EQ(descriptor->stack_count(), StateValuesAccess(stack).size());
 
   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++) {
-    Node* input_node = parameters->InputAt(i);
-    inputs->push_back(UseOrImmediate(&g, input_node));
-    descriptor->SetType(value_index++, GetMachineType(input_node));
+  for (StateValuesAccess::TypedNode input_node :
+       StateValuesAccess(parameters)) {
+    inputs->push_back(SlotOrImmediate(&g, input_node.node));
+    descriptor->SetType(value_index++, input_node.type);
   }
   if (descriptor->HasContext()) {
-    inputs->push_back(UseOrImmediate(&g, context));
+    inputs->push_back(SlotOrImmediate(&g, context));
     descriptor->SetType(value_index++, kMachAnyTagged);
   }
-  for (int i = 0; i < static_cast<int>(descriptor->locals_count()); i++) {
-    Node* input_node = locals->InputAt(i);
-    inputs->push_back(UseOrImmediate(&g, input_node));
-    descriptor->SetType(value_index++, GetMachineType(input_node));
+  for (StateValuesAccess::TypedNode input_node : StateValuesAccess(locals)) {
+    inputs->push_back(SlotOrImmediate(&g, input_node.node));
+    descriptor->SetType(value_index++, input_node.type);
   }
-  for (int i = 0; i < static_cast<int>(descriptor->stack_count()); i++) {
-    Node* input_node = stack->InputAt(i);
-    inputs->push_back(UseOrImmediate(&g, input_node));
-    descriptor->SetType(value_index++, GetMachineType(input_node));
+  for (StateValuesAccess::TypedNode input_node : StateValuesAccess(stack)) {
+    inputs->push_back(SlotOrImmediate(&g, input_node.node));
+    descriptor->SetType(value_index++, input_node.type);
   }
   DCHECK(value_index == descriptor->GetSize());
 }
@@ -1205,7 +1143,9 @@ MACHINE_OP_LIST(DECLARE_UNIMPLEMENTED_SELECTOR)
 #undef DECLARE_UNIMPLEMENTED_SELECTOR
 
 
-void InstructionSelector::VisitCall(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
+  UNIMPLEMENTED();
+}
 
 
 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
@@ -1214,10 +1154,7 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
 }
 
 
-void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
-                                      BasicBlock** case_branches,
-                                      int32_t* case_values, size_t case_count,
-                                      int32_t min_value, int32_t max_value) {
+void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
   UNIMPLEMENTED();
 }
 
index 5c31db7..fcf205a 100644 (file)
@@ -18,10 +18,11 @@ namespace internal {
 namespace compiler {
 
 // Forward declarations.
+class BasicBlock;
 struct CallBuffer;  // TODO(bmeurer): Remove this.
 class FlagsContinuation;
 class Linkage;
-
+struct SwitchInfo;
 
 typedef ZoneVector<InstructionOperand> InstructionOperandVector;
 
@@ -129,9 +130,15 @@ class InstructionSelector FINAL {
   int GetVirtualRegister(const Node* node);
   const std::map<NodeId, int> GetVirtualRegistersForTesting() const;
 
+  Isolate* isolate() const { return sequence()->isolate(); }
+
  private:
   friend class OperandGenerator;
 
+  void EmitTableSwitch(const SwitchInfo& sw, InstructionOperand& index_operand);
+  void EmitLookupSwitch(const SwitchInfo& sw,
+                        InstructionOperand& value_operand);
+
   // Inform the instruction selection that {node} was just defined.
   void MarkAsDefined(Node* node);
 
@@ -169,11 +176,8 @@ class InstructionSelector FINAL {
                             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. ===============
@@ -199,15 +203,13 @@ class InstructionSelector FINAL {
   void VisitPhi(Node* node);
   void VisitProjection(Node* node);
   void VisitConstant(Node* node);
-  void VisitCall(Node* call);
+  void VisitCall(Node* call, BasicBlock* handler);
   void VisitGoto(BasicBlock* target);
   void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch);
-  void VisitSwitch(Node* node, BasicBlock* default_branch,
-                   BasicBlock** case_branches, int32_t* case_values,
-                   size_t case_count, int32_t min_value, int32_t max_value);
+  void VisitSwitch(Node* node, const SwitchInfo& sw);
+  void VisitDeoptimize(Node* value);
   void VisitReturn(Node* value);
   void VisitThrow(Node* value);
-  void VisitDeoptimize(Node* deopt);
 
   // ===========================================================================
 
index ebd8125..8446a0d 100644 (file)
@@ -5,6 +5,7 @@
 #include "src/compiler/common-operator.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/instruction.h"
+#include "src/compiler/schedule.h"
 
 namespace v8 {
 namespace internal {
@@ -32,6 +33,8 @@ std::ostream& operator<<(std::ostream& os,
                                    unalloc->fixed_register_index()) << ")";
         case UnallocatedOperand::MUST_HAVE_REGISTER:
           return os << "(R)";
+        case UnallocatedOperand::MUST_HAVE_SLOT:
+          return os << "(S)";
         case UnallocatedOperand::SAME_AS_FIRST_INPUT:
           return os << "(1)";
         case UnallocatedOperand::ANY:
@@ -81,11 +84,32 @@ bool ParallelMove::IsRedundant() const {
 }
 
 
+MoveOperands* ParallelMove::PrepareInsertAfter(MoveOperands* move) const {
+  auto move_ops = 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(!replacement);
+      replacement = curr;
+      if (to_eliminate != nullptr) break;
+    } else if (curr->destination()->Equals(move->destination())) {
+      DCHECK(!to_eliminate);
+      to_eliminate = curr;
+      if (replacement != nullptr) break;
+    }
+  }
+  DCHECK_IMPLIES(replacement == to_eliminate, replacement == nullptr);
+  if (replacement != nullptr) move->set_source(replacement->source());
+  return to_eliminate;
+}
+
+
 Instruction::Instruction(InstructionCode opcode)
     : opcode_(opcode),
       bit_field_(OutputCountField::encode(0) | InputCountField::encode(0) |
-                 TempCountField::encode(0) | IsCallField::encode(false) |
-                 IsControlField::encode(false)),
+                 TempCountField::encode(0) | IsCallField::encode(false)),
       pointer_map_(NULL) {}
 
 
@@ -97,7 +121,7 @@ Instruction::Instruction(InstructionCode opcode, size_t output_count,
       bit_field_(OutputCountField::encode(output_count) |
                  InputCountField::encode(input_count) |
                  TempCountField::encode(temp_count) |
-                 IsCallField::encode(false) | IsControlField::encode(false)),
+                 IsCallField::encode(false)),
       pointer_map_(NULL) {
   size_t offset = 0;
   for (size_t i = 0; i < output_count; ++i) {
@@ -314,6 +338,9 @@ std::ostream& operator<<(std::ostream& os,
 }
 
 
+Constant::Constant(int32_t v) : type_(kInt32), value_(v) {}
+
+
 std::ostream& operator<<(std::ostream& os, const Constant& constant) {
   switch (constant.type()) {
     case Constant::kInt32:
@@ -353,15 +380,12 @@ void PhiInstruction::SetInput(size_t offset, int virtual_register) {
 }
 
 
-InstructionBlock::InstructionBlock(Zone* zone, BasicBlock::Id id,
-                                   BasicBlock::RpoNumber rpo_number,
-                                   BasicBlock::RpoNumber loop_header,
-                                   BasicBlock::RpoNumber loop_end,
+InstructionBlock::InstructionBlock(Zone* zone, RpoNumber rpo_number,
+                                   RpoNumber loop_header, 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),
@@ -371,8 +395,7 @@ InstructionBlock::InstructionBlock(Zone* zone, BasicBlock::Id id,
       deferred_(deferred) {}
 
 
-size_t InstructionBlock::PredecessorIndexOf(
-    BasicBlock::RpoNumber rpo_number) const {
+size_t InstructionBlock::PredecessorIndexOf(RpoNumber rpo_number) const {
   size_t j = 0;
   for (InstructionBlock::Predecessors::const_iterator i = predecessors_.begin();
        i != predecessors_.end(); ++i, ++j) {
@@ -382,31 +405,31 @@ size_t InstructionBlock::PredecessorIndexOf(
 }
 
 
-static BasicBlock::RpoNumber GetRpo(BasicBlock* block) {
-  if (block == NULL) return BasicBlock::RpoNumber::Invalid();
-  return block->GetRpoNumber();
+static RpoNumber GetRpo(const BasicBlock* block) {
+  if (block == NULL) return RpoNumber::Invalid();
+  return RpoNumber::FromInt(block->rpo_number());
 }
 
 
-static BasicBlock::RpoNumber GetLoopEndRpo(const BasicBlock* block) {
-  if (!block->IsLoopHeader()) return BasicBlock::RpoNumber::Invalid();
-  return block->loop_end()->GetRpoNumber();
+static RpoNumber GetLoopEndRpo(const BasicBlock* block) {
+  if (!block->IsLoopHeader()) return RpoNumber::Invalid();
+  return RpoNumber::FromInt(block->loop_end()->rpo_number());
 }
 
 
 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());
+  InstructionBlock* instr_block = new (zone)
+      InstructionBlock(zone, GetRpo(block), GetRpo(block->loop_header()),
+                       GetLoopEndRpo(block), block->deferred());
   // Map successors and precessors
   instr_block->successors().reserve(block->SuccessorCount());
   for (BasicBlock* successor : block->successors()) {
-    instr_block->successors().push_back(successor->GetRpoNumber());
+    instr_block->successors().push_back(GetRpo(successor));
   }
   instr_block->predecessors().reserve(block->PredecessorCount());
   for (BasicBlock* predecessor : block->predecessors()) {
-    instr_block->predecessors().push_back(predecessor->GetRpoNumber());
+    instr_block->predecessors().push_back(GetRpo(predecessor));
   }
   return instr_block;
 }
@@ -421,7 +444,7 @@ InstructionBlocks* InstructionSequence::InstructionBlocksFor(
   for (BasicBlockVector::const_iterator it = schedule->rpo_order()->begin();
        it != schedule->rpo_order()->end(); ++it, ++rpo_number) {
     DCHECK(!(*blocks)[rpo_number]);
-    DCHECK((*it)->GetRpoNumber().ToSize() == rpo_number);
+    DCHECK(GetRpo(*it).ToSize() == rpo_number);
     (*blocks)[rpo_number] = InstructionBlockFor(zone, *it);
   }
   ComputeAssemblyOrder(blocks);
@@ -433,12 +456,12 @@ void InstructionSequence::ComputeAssemblyOrder(InstructionBlocks* blocks) {
   int ao = 0;
   for (auto const block : *blocks) {
     if (!block->IsDeferred()) {
-      block->set_ao_number(BasicBlock::RpoNumber::FromInt(ao++));
+      block->set_ao_number(RpoNumber::FromInt(ao++));
     }
   }
   for (auto const block : *blocks) {
     if (block->IsDeferred()) {
-      block->set_ao_number(BasicBlock::RpoNumber::FromInt(ao++));
+      block->set_ao_number(RpoNumber::FromInt(ao++));
     }
   }
 }
@@ -471,14 +494,13 @@ int InstructionSequence::NextVirtualRegister() {
 }
 
 
-GapInstruction* InstructionSequence::GetBlockStart(
-    BasicBlock::RpoNumber rpo) const {
+GapInstruction* InstructionSequence::GetBlockStart(RpoNumber rpo) const {
   const InstructionBlock* block = InstructionBlockAt(rpo);
   return GapInstruction::cast(InstructionAt(block->code_start()));
 }
 
 
-void InstructionSequence::StartBlock(BasicBlock::RpoNumber rpo) {
+void InstructionSequence::StartBlock(RpoNumber rpo) {
   DCHECK(block_starts_.size() == rpo.ToSize());
   InstructionBlock* block = InstructionBlockAt(rpo);
   int code_start = static_cast<int>(instructions_.size());
@@ -487,7 +509,7 @@ void InstructionSequence::StartBlock(BasicBlock::RpoNumber rpo) {
 }
 
 
-void InstructionSequence::EndBlock(BasicBlock::RpoNumber rpo) {
+void InstructionSequence::EndBlock(RpoNumber rpo) {
   int end = static_cast<int>(instructions_.size());
   InstructionBlock* block = InstructionBlockAt(rpo);
   if (block->code_start() == end) {  // Empty block.  Insert a nop.
@@ -646,6 +668,11 @@ void FrameStateDescriptor::SetType(size_t index, MachineType type) {
 }
 
 
+std::ostream& operator<<(std::ostream& os, const RpoNumber& rpo) {
+  return os << rpo.ToSize();
+}
+
+
 std::ostream& operator<<(std::ostream& os,
                          const PrintableInstructionSequence& printable) {
   const InstructionSequence& code = *printable.sequence_;
@@ -659,13 +686,12 @@ std::ostream& operator<<(std::ostream& os,
     os << "CST#" << i << ": v" << it->first << " = " << it->second << "\n";
   }
   for (int i = 0; i < code.InstructionBlockCount(); i++) {
-    BasicBlock::RpoNumber rpo = BasicBlock::RpoNumber::FromInt(i);
+    RpoNumber rpo = RpoNumber::FromInt(i);
     const InstructionBlock* block = code.InstructionBlockAt(rpo);
     CHECK(block->rpo_number() == rpo);
 
-    os << "RPO#" << block->rpo_number();
+    os << "B" << 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() << ", "
@@ -675,8 +701,7 @@ std::ostream& operator<<(std::ostream& os,
        << block->code_end() << ")\n  predecessors:";
 
     for (auto pred : block->predecessors()) {
-      const InstructionBlock* pred_block = code.InstructionBlockAt(pred);
-      os << " B" << pred_block->id();
+      os << " B" << pred.ToInt();
     }
     os << "\n";
 
@@ -703,8 +728,7 @@ std::ostream& operator<<(std::ostream& os,
     }
 
     for (auto succ : block->successors()) {
-      const InstructionBlock* succ_block = code.InstructionBlockAt(succ);
-      os << " B" << succ_block->id();
+      os << " B" << succ.ToInt();
     }
     os << "\n";
   }
index d04d036..38fc433 100644 (file)
@@ -15,7 +15,6 @@
 #include "src/compiler/instruction-codes.h"
 #include "src/compiler/opcodes.h"
 #include "src/compiler/register-configuration.h"
-#include "src/compiler/schedule.h"
 #include "src/compiler/source-position.h"
 #include "src/zone-allocator.h"
 
@@ -23,6 +22,8 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
+class Schedule;
+
 // A couple of reserved opcodes are used for internal use.
 const InstructionCode kGapInstruction = -1;
 const InstructionCode kSourcePositionInstruction = -2;
@@ -50,14 +51,11 @@ class InstructionOperand {
     DOUBLE_REGISTER
   };
 
-  InstructionOperand() : virtual_register_(kInvalidVirtualRegister) {
-    ConvertTo(INVALID, 0);
-  }
+  InstructionOperand() { ConvertTo(INVALID, 0, kInvalidVirtualRegister); }
 
-  InstructionOperand(Kind kind, int index)
-      : virtual_register_(kInvalidVirtualRegister) {
-    DCHECK(kind != INVALID);
-    ConvertTo(kind, index);
+  InstructionOperand(Kind kind, int index) {
+    DCHECK(kind != UNALLOCATED && kind != INVALID);
+    ConvertTo(kind, index, kInvalidVirtualRegister);
   }
 
   static InstructionOperand* New(Zone* zone, Kind kind, int index) {
@@ -65,7 +63,11 @@ class InstructionOperand {
   }
 
   Kind kind() const { return KindField::decode(value_); }
-  int index() const { return static_cast<int>(value_) >> KindField::kSize; }
+  // TODO(dcarney): move this to subkind operand.
+  int index() const {
+    DCHECK(kind() != UNALLOCATED && kind() != INVALID);
+    return static_cast<int64_t>(value_) >> IndexField::kShift;
+  }
 #define INSTRUCTION_OPERAND_PREDICATE(name, type) \
   bool Is##name() const { return kind() == type; }
   INSTRUCTION_OPERAND_LIST(INSTRUCTION_OPERAND_PREDICATE)
@@ -77,11 +79,13 @@ class InstructionOperand {
   }
 
   void ConvertTo(Kind kind, int index) {
-    if (kind == REGISTER || kind == DOUBLE_REGISTER) DCHECK(index >= 0);
-    value_ = KindField::encode(kind);
-    value_ |= bit_cast<unsigned>(index << KindField::kSize);
-    DCHECK(this->index() == index);
-    if (kind != UNALLOCATED) virtual_register_ = kInvalidVirtualRegister;
+    DCHECK(kind != UNALLOCATED && kind != INVALID);
+    ConvertTo(kind, index, kInvalidVirtualRegister);
+  }
+
+  // Useful for map/set keys.
+  bool operator<(const InstructionOperand& op) const {
+    return value_ < op.value_;
   }
 
  protected:
@@ -91,15 +95,28 @@ class InstructionOperand {
     return new (buffer) SubKindOperand(op);
   }
 
-  InstructionOperand(Kind kind, int index, int virtual_register)
-      : virtual_register_(virtual_register) {
-    ConvertTo(kind, index);
+  InstructionOperand(Kind kind, int index, int virtual_register) {
+    ConvertTo(kind, index, virtual_register);
   }
-  typedef BitField<Kind, 0, 3> KindField;
 
-  uint32_t value_;
-  // TODO(dcarney): this should really be unsigned.
-  int32_t virtual_register_;
+  void ConvertTo(Kind kind, int index, int virtual_register) {
+    if (kind == REGISTER || kind == DOUBLE_REGISTER) DCHECK(index >= 0);
+    if (kind != UNALLOCATED) {
+      DCHECK(virtual_register == kInvalidVirtualRegister);
+    }
+    value_ = KindField::encode(kind);
+    value_ |=
+        VirtualRegisterField::encode(static_cast<uint32_t>(virtual_register));
+    value_ |= static_cast<int64_t>(index) << IndexField::kShift;
+    DCHECK(((kind == UNALLOCATED || kind == INVALID) && index == 0) ||
+           this->index() == index);
+  }
+
+  typedef BitField64<Kind, 0, 3> KindField;
+  typedef BitField64<uint32_t, 3, 32> VirtualRegisterField;
+  typedef BitField64<int32_t, 35, 29> IndexField;
+
+  uint64_t value_;
 };
 
 struct PrintableInstructionOperand {
@@ -120,6 +137,7 @@ class UnallocatedOperand : public InstructionOperand {
     FIXED_REGISTER,
     FIXED_DOUBLE_REGISTER,
     MUST_HAVE_REGISTER,
+    MUST_HAVE_SLOT,
     SAME_AS_FIRST_INPUT
   };
 
@@ -148,7 +166,7 @@ class UnallocatedOperand : public InstructionOperand {
       : InstructionOperand(UNALLOCATED, 0, virtual_register) {
     DCHECK(policy == FIXED_SLOT);
     value_ |= BasicPolicyField::encode(policy);
-    value_ |= static_cast<int32_t>(index) << FixedSlotIndexField::kShift;
+    value_ |= static_cast<int64_t>(index) << FixedSlotIndexField::kShift;
     DCHECK(this->fixed_slot_index() == index);
   }
 
@@ -196,35 +214,33 @@ class UnallocatedOperand : public InstructionOperand {
   // because it accommodates a larger pay-load.
   //
   // For FIXED_SLOT policy:
-  //     +-----------------------------+
-  //     |      slot_index   | 0 | 001 |
-  //     +-----------------------------+
+  //     +------------------------------------------------+
+  //     |      slot_index   | 0 | virtual_register | 001 |
+  //     +------------------------------------------------+
   //
   // For all other (extended) policies:
-  //     +----------------------------------+
-  //     |  reg_index  | L | PPP |  1 | 001 |    L ... Lifetime
-  //     +----------------------------------+    P ... Policy
+  //     +-----------------------------------------------------+
+  //     |  reg_index  | L | PPP |  1 | virtual_register | 001 |
+  //     +-----------------------------------------------------+
+  //     L ... Lifetime
+  //     P ... Policy
   //
   // The slot index is a signed value which requires us to decode it manually
   // instead of using the BitField utility class.
 
-  // The superclass has a KindField.
-  STATIC_ASSERT(KindField::kSize == 3);
+  // All bits fit into the index field.
+  STATIC_ASSERT(IndexField::kShift == 35);
 
   // BitFields for all unallocated operands.
-  class BasicPolicyField : public BitField<BasicPolicy, 3, 1> {};
+  class BasicPolicyField : public BitField64<BasicPolicy, 35, 1> {};
 
   // BitFields specific to BasicPolicy::FIXED_SLOT.
-  class FixedSlotIndexField : public BitField<int, 4, 28> {};
+  class FixedSlotIndexField : public BitField64<int, 36, 28> {};
 
   // BitFields specific to BasicPolicy::EXTENDED_POLICY.
-  class ExtendedPolicyField : public BitField<ExtendedPolicy, 4, 3> {};
-  class LifetimeField : public BitField<Lifetime, 7, 1> {};
-  class FixedRegisterField : public BitField<int, 8, 6> {};
-
-  static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize;
-  static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1;
-  static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1));
+  class ExtendedPolicyField : public BitField64<ExtendedPolicy, 36, 3> {};
+  class LifetimeField : public BitField64<Lifetime, 39, 1> {};
+  class FixedRegisterField : public BitField64<int, 40, 6> {};
 
   // Predicates for the operand policy.
   bool HasAnyPolicy() const {
@@ -239,6 +255,10 @@ class UnallocatedOperand : public InstructionOperand {
     return basic_policy() == EXTENDED_POLICY &&
            extended_policy() == MUST_HAVE_REGISTER;
   }
+  bool HasSlotPolicy() const {
+    return basic_policy() == EXTENDED_POLICY &&
+           extended_policy() == MUST_HAVE_SLOT;
+  }
   bool HasSameAsInputPolicy() const {
     return basic_policy() == EXTENDED_POLICY &&
            extended_policy() == SAME_AS_FIRST_INPUT;
@@ -268,7 +288,7 @@ class UnallocatedOperand : public InstructionOperand {
   // [fixed_slot_index]: Only for FIXED_SLOT.
   int fixed_slot_index() const {
     DCHECK(HasFixedSlotPolicy());
-    return static_cast<int>(bit_cast<int32_t>(value_) >>
+    return static_cast<int>(static_cast<int64_t>(value_) >>
                             FixedSlotIndexField::kShift);
   }
 
@@ -281,13 +301,13 @@ class UnallocatedOperand : public InstructionOperand {
   // [virtual_register]: The virtual register ID for this operand.
   int32_t virtual_register() const {
     DCHECK_EQ(UNALLOCATED, kind());
-    return virtual_register_;
+    return static_cast<int32_t>(VirtualRegisterField::decode(value_));
   }
 
   // TODO(dcarney): remove this.
   void set_virtual_register(int32_t id) {
     DCHECK_EQ(UNALLOCATED, kind());
-    virtual_register_ = id;
+    value_ = VirtualRegisterField::update(value_, static_cast<uint32_t>(id));
   }
 
   // [lifetime]: Only for non-FIXED_SLOT.
@@ -391,6 +411,12 @@ class ParallelMove FINAL : public ZoneObject {
     return &move_operands_;
   }
 
+  // Prepare this ParallelMove to insert move as if it happened in a subsequent
+  // ParallelMove.  move->source() may be changed.  The MoveOperand returned
+  // must be Eliminated and, as it points directly into move_operands_, it must
+  // be Eliminated before any further mutation.
+  MoveOperands* PrepareInsertAfter(MoveOperands* move) const;
+
  private:
   ZoneList<MoveOperands> move_operands_;
 };
@@ -487,7 +513,7 @@ class Instruction {
     return FlagsConditionField::decode(opcode());
   }
 
-  // TODO(titzer): make control and call into flags.
+  // TODO(titzer): make call into a flags.
   static Instruction* New(Zone* zone, InstructionCode opcode) {
     return New(zone, opcode, 0, NULL, 0, NULL, 0, NULL);
   }
@@ -509,17 +535,10 @@ class Instruction {
         opcode, output_count, outputs, input_count, inputs, temp_count, temps);
   }
 
-  // TODO(titzer): another holdover from lithium days; register allocator
-  // should not need to know about control instructions.
-  Instruction* MarkAsControl() {
-    bit_field_ = IsControlField::update(bit_field_, true);
-    return this;
-  }
   Instruction* MarkAsCall() {
     bit_field_ = IsCallField::update(bit_field_, true);
     return this;
   }
-  bool IsControl() const { return IsControlField::decode(bit_field_); }
   bool IsCall() const { return IsCallField::decode(bit_field_); }
   bool NeedsPointerMap() const { return IsCall(); }
   bool HasPointerMap() const { return pointer_map_ != NULL; }
@@ -562,7 +581,6 @@ class Instruction {
   typedef BitField<size_t, 8, 16> InputCountField;
   typedef BitField<size_t, 24, 6> TempCountField;
   typedef BitField<bool, 30, 1> IsCallField;
-  typedef BitField<bool, 31, 1> IsControlField;
 
   InstructionCode opcode_;
   uint32_t bit_field_;
@@ -587,12 +605,10 @@ std::ostream& operator<<(std::ostream& os, const PrintableInstruction& instr);
 class GapInstruction : public Instruction {
  public:
   enum InnerPosition {
-    BEFORE,
     START,
     END,
-    AFTER,
-    FIRST_INNER_POSITION = BEFORE,
-    LAST_INNER_POSITION = AFTER
+    FIRST_INNER_POSITION = START,
+    LAST_INNER_POSITION = END
   };
 
   ParallelMove* GetOrCreateParallelMove(InnerPosition pos, Zone* zone) {
@@ -631,10 +647,8 @@ class GapInstruction : public Instruction {
 
  protected:
   explicit GapInstruction(InstructionCode opcode) : Instruction(opcode) {
-    parallel_moves_[BEFORE] = NULL;
     parallel_moves_[START] = NULL;
     parallel_moves_[END] = NULL;
-    parallel_moves_[AFTER] = NULL;
   }
 
  private:
@@ -675,6 +689,39 @@ class SourcePositionInstruction FINAL : public Instruction {
 };
 
 
+class RpoNumber FINAL {
+ public:
+  static const int kInvalidRpoNumber = -1;
+  int ToInt() const {
+    DCHECK(IsValid());
+    return index_;
+  }
+  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); }
+
+  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_;
+};
+
+
+std::ostream& operator<<(std::ostream&, const RpoNumber&);
+
+
 class Constant FINAL {
  public:
   enum Type {
@@ -687,7 +734,7 @@ class Constant FINAL {
     kRpoNumber
   };
 
-  explicit Constant(int32_t v) : type_(kInt32), value_(v) {}
+  explicit Constant(int32_t 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)) {}
@@ -695,8 +742,7 @@ class Constant FINAL {
       : 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()) {}
+  explicit Constant(RpoNumber rpo) : type_(kRpoNumber), value_(rpo.ToInt()) {}
 
   Type type() const { return type_; }
 
@@ -729,9 +775,9 @@ class Constant FINAL {
     return bit_cast<ExternalReference>(static_cast<intptr_t>(value_));
   }
 
-  BasicBlock::RpoNumber ToRpoNumber() const {
+  RpoNumber ToRpoNumber() const {
     DCHECK_EQ(kRpoNumber, type());
-    return BasicBlock::RpoNumber::FromInt(static_cast<int>(value_));
+    return RpoNumber::FromInt(static_cast<int>(value_));
   }
 
   Handle<HeapObject> ToHeapObject() const {
@@ -815,10 +861,8 @@ class PhiInstruction FINAL : public ZoneObject {
 // 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);
+  InstructionBlock(Zone* zone, RpoNumber rpo_number, RpoNumber loop_header,
+                   RpoNumber loop_end, bool deferred);
 
   // Instruction indexes (used by the register allocator).
   int first_instruction_index() const {
@@ -842,23 +886,22 @@ class InstructionBlock FINAL : public ZoneObject {
 
   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 {
+  RpoNumber ao_number() const { return ao_number_; }
+  RpoNumber rpo_number() const { return rpo_number_; }
+  RpoNumber loop_header() const { return loop_header_; }
+  RpoNumber loop_end() const {
     DCHECK(IsLoopHeader());
     return loop_end_;
   }
   inline bool IsLoopHeader() const { return loop_end_.IsValid(); }
 
-  typedef ZoneVector<BasicBlock::RpoNumber> Predecessors;
+  typedef ZoneVector<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;
+  size_t PredecessorIndexOf(RpoNumber rpo_number) const;
 
-  typedef ZoneVector<BasicBlock::RpoNumber> Successors;
+  typedef ZoneVector<RpoNumber> Successors;
   Successors& successors() { return successors_; }
   const Successors& successors() const { return successors_; }
   size_t SuccessorCount() const { return successors_.size(); }
@@ -867,19 +910,16 @@ class InstructionBlock FINAL : public ZoneObject {
   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;
-  }
+  void set_ao_number(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_;
+  RpoNumber ao_number_;  // Assembly order number.
+  const RpoNumber rpo_number_;
+  const RpoNumber loop_header_;
+  const 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.
@@ -921,7 +961,7 @@ class InstructionSequence FINAL : public ZoneObject {
     return static_cast<int>(instruction_blocks_->size());
   }
 
-  InstructionBlock* InstructionBlockAt(BasicBlock::RpoNumber rpo_number) {
+  InstructionBlock* InstructionBlockAt(RpoNumber rpo_number) {
     return instruction_blocks_->at(rpo_number.ToSize());
   }
 
@@ -930,8 +970,7 @@ class InstructionSequence FINAL : public ZoneObject {
         ->last_instruction_index();
   }
 
-  const InstructionBlock* InstructionBlockAt(
-      BasicBlock::RpoNumber rpo_number) const {
+  const InstructionBlock* InstructionBlockAt(RpoNumber rpo_number) const {
     return instruction_blocks_->at(rpo_number.ToSize());
   }
 
@@ -945,7 +984,7 @@ class InstructionSequence FINAL : public ZoneObject {
 
   void AddGapMove(int index, InstructionOperand* from, InstructionOperand* to);
 
-  GapInstruction* GetBlockStart(BasicBlock::RpoNumber rpo) const;
+  GapInstruction* GetBlockStart(RpoNumber rpo) const;
 
   typedef InstructionDeque::const_iterator const_iterator;
   const_iterator begin() const { return instructions_.begin(); }
@@ -968,8 +1007,8 @@ class InstructionSequence FINAL : public ZoneObject {
 
   // Used by the instruction selector while adding instructions.
   int AddInstruction(Instruction* instr);
-  void StartBlock(BasicBlock::RpoNumber rpo);
-  void EndBlock(BasicBlock::RpoNumber rpo);
+  void StartBlock(RpoNumber rpo);
+  void EndBlock(RpoNumber rpo);
 
   int AddConstant(int virtual_register, Constant constant) {
     // TODO(titzer): allow RPO numbers as constants?
@@ -1014,7 +1053,7 @@ class InstructionSequence FINAL : public ZoneObject {
   FrameStateDescriptor* GetFrameStateDescriptor(StateId deoptimization_id);
   int GetFrameStateDescriptorCount();
 
-  BasicBlock::RpoNumber InputRpo(Instruction* instr, size_t index) {
+  RpoNumber InputRpo(Instruction* instr, size_t index) {
     InstructionOperand* operand = instr->InputAt(index);
     Constant constant = operand->IsImmediate() ? GetImmediate(operand->index())
                                                : GetConstant(operand->index());
index a89f4a3..12b0e2f 100644 (file)
@@ -100,38 +100,6 @@ 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);
-  if (r.InputsMatchOne(Type::Number())) {
-    // Math.sqrt(a:number) -> Float64Sqrt(a)
-    Node* value = graph()->NewNode(machine()->Float64Sqrt(), r.left());
-    return Replace(value);
-  }
-  return NoChange();
-}
-
-
 // ECMA-262, section 15.8.2.11.
 Reduction JSBuiltinReducer::ReduceMathMax(Node* node) {
   JSCallReduction r(node);
@@ -184,52 +152,18 @@ Reduction JSBuiltinReducer::ReduceMathFround(Node* node) {
 }
 
 
-// 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;
   }
index ac6f266..42221e9 100644 (file)
@@ -26,13 +26,9 @@ class JSBuiltinReducer FINAL : public Reducer {
   Reduction Reduce(Node* node) FINAL;
 
  private:
-  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;
index 4720c58..e1dac82 100644 (file)
@@ -6,6 +6,7 @@
 #include "src/code-stubs.h"
 #include "src/compiler/common-operator.h"
 #include "src/compiler/js-generic-lowering.h"
+#include "src/compiler/js-graph.h"
 #include "src/compiler/machine-operator.h"
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties.h"
@@ -20,6 +21,9 @@ JSGenericLowering::JSGenericLowering(bool is_typing_enabled, JSGraph* jsgraph)
     : is_typing_enabled_(is_typing_enabled), jsgraph_(jsgraph) {}
 
 
+JSGenericLowering::~JSGenericLowering() {}
+
+
 Reduction JSGenericLowering::Reduce(Node* node) {
   switch (node->opcode()) {
 #define DECLARE_CASE(x)  \
@@ -101,13 +105,12 @@ REPLACE_RUNTIME_CALL(JSCreateScriptContext, Runtime::kAbort)
 #define REPLACE_UNIMPLEMENTED(op) \
   void JSGenericLowering::Lower##op(Node* node) { UNIMPLEMENTED(); }
 REPLACE_UNIMPLEMENTED(JSYield)
-REPLACE_UNIMPLEMENTED(JSDebugger)
 #undef REPLACE_UNIMPLEMENTED
 
 
 static CallDescriptor::Flags FlagsForNode(Node* node) {
   CallDescriptor::Flags result = CallDescriptor::kNoFlags;
-  if (OperatorProperties::HasFrameStateInput(node->op())) {
+  if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
     result |= CallDescriptor::kNeedsFrameState;
   }
   return result;
@@ -118,7 +121,8 @@ void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token) {
   Callable callable = CodeFactory::CompareIC(isolate(), token);
   CallDescriptor* desc_compare = Linkage::GetStubCallDescriptor(
       isolate(), zone(), callable.descriptor(), 0,
-      CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node));
+      CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node),
+      Operator::kNoProperties, kMachInt32);
 
   // Create a new call node asking a CompareIC for help.
   NodeVector inputs(zone());
@@ -130,14 +134,14 @@ void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token) {
   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(!OperatorProperties::HasFrameStateInput(node->op()));
+    DCHECK(OperatorProperties::GetFrameStateInputCount(node->op()) == 0);
     inputs.push_back(graph()->start());
     inputs.push_back(graph()->start());
   } else {
-    DCHECK(OperatorProperties::HasFrameStateInput(node->op()) ==
+    DCHECK((OperatorProperties::GetFrameStateInputCount(node->op()) == 1) ==
            FLAG_turbo_deoptimization);
     if (FLAG_turbo_deoptimization) {
-      inputs.push_back(NodeProperties::GetFrameStateInput(node));
+      inputs.push_back(NodeProperties::GetFrameStateInput(node, 0));
     }
     inputs.push_back(NodeProperties::GetEffectInput(node));
     inputs.push_back(NodeProperties::GetControlInput(node));
@@ -198,12 +202,26 @@ void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token) {
 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
                                             CallDescriptor::Flags flags) {
   Operator::Properties properties = node->op()->properties();
-  CallDescriptor* desc =
-      Linkage::GetStubCallDescriptor(isolate(), zone(), callable.descriptor(),
-                                     0, flags | FlagsForNode(node), properties);
+  flags |= FlagsForNode(node);
+  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
+      isolate(), zone(), callable.descriptor(), 0, flags, properties);
+  const Operator* new_op = common()->Call(desc);
+
+  // Take care of frame states.
+  int old_frame_state_count =
+      OperatorProperties::GetFrameStateInputCount(node->op());
+  int new_frame_state_count =
+      (flags & CallDescriptor::kNeedsFrameState) ? 1 : 0;
+  DCHECK_GE(old_frame_state_count, new_frame_state_count);
+  // If there are extra frame states, get rid of them.
+  for (int i = new_frame_state_count; i < old_frame_state_count; i++) {
+    node->RemoveInput(NodeProperties::FirstFrameStateIndex(node) +
+                      new_frame_state_count);
+  }
+
   Node* stub_code = jsgraph()->HeapConstant(callable.code());
   node->InsertInput(zone(), 0, stub_code);
-  node->set_op(common()->Call(desc));
+  node->set_op(new_op);
 }
 
 
@@ -291,7 +309,8 @@ void JSGenericLowering::LowerJSToObject(Node* node) {
 
 void JSGenericLowering::LowerJSLoadProperty(Node* node) {
   const LoadPropertyParameters& p = LoadPropertyParametersOf(node->op());
-  Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate());
+  Callable callable =
+      CodeFactory::KeyedLoadICInOptimizedCode(isolate(), UNINITIALIZED);
   if (FLAG_vector_ics) {
     node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
     node->InsertInput(zone(), 3,
@@ -303,8 +322,8 @@ void JSGenericLowering::LowerJSLoadProperty(Node* node) {
 
 void JSGenericLowering::LowerJSLoadNamed(Node* node) {
   const LoadNamedParameters& p = LoadNamedParametersOf(node->op());
-  Callable callable =
-      CodeFactory::LoadICInOptimizedCode(isolate(), p.contextual_mode());
+  Callable callable = CodeFactory::LoadICInOptimizedCode(
+      isolate(), p.contextual_mode(), UNINITIALIZED);
   node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
   if (FLAG_vector_ics) {
     node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
@@ -317,7 +336,8 @@ void JSGenericLowering::LowerJSLoadNamed(Node* node) {
 
 void JSGenericLowering::LowerJSStoreProperty(Node* node) {
   LanguageMode language_mode = OpParameter<LanguageMode>(node);
-  Callable callable = CodeFactory::KeyedStoreIC(isolate(), language_mode);
+  Callable callable = CodeFactory::KeyedStoreICInOptimizedCode(
+      isolate(), language_mode, UNINITIALIZED);
   ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
 }
 
@@ -478,6 +498,59 @@ void JSGenericLowering::LowerJSCallRuntime(Node* node) {
   ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
 }
 
+
+void JSGenericLowering::LowerJSStackCheck(Node* node) {
+  Node* effect = NodeProperties::GetEffectInput(node);
+  Node* control = NodeProperties::GetControlInput(node);
+
+  Node* limit = graph()->NewNode(
+      machine()->Load(kMachPtr),
+      jsgraph()->ExternalConstant(
+          ExternalReference::address_of_stack_limit(isolate())),
+      jsgraph()->IntPtrConstant(0), effect, control);
+  Node* pointer = graph()->NewNode(machine()->LoadStackPointer());
+
+  Node* check = graph()->NewNode(machine()->UintLessThan(), limit, pointer);
+  Node* branch =
+      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
+
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* etrue = effect;
+
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  NodeProperties::ReplaceControlInput(node, if_false);
+  Node* efalse = node;
+
+  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+  Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
+
+  // Relax controls of {node}, i.e. make it free floating.
+  NodeProperties::ReplaceWithValue(node, node, ephi, merge);
+  NodeProperties::ReplaceEffectInput(ephi, efalse, 1);
+
+  // Turn the stack check into a runtime call.
+  ReplaceWithRuntimeCall(node, Runtime::kStackGuard);
+}
+
+
+Zone* JSGenericLowering::zone() const { return graph()->zone(); }
+
+
+Isolate* JSGenericLowering::isolate() const { return jsgraph()->isolate(); }
+
+
+Graph* JSGenericLowering::graph() const { return jsgraph()->graph(); }
+
+
+CommonOperatorBuilder* JSGenericLowering::common() const {
+  return jsgraph()->common();
+}
+
+
+MachineOperatorBuilder* JSGenericLowering::machine() const {
+  return jsgraph()->machine();
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 10057eb..5ca09ef 100644 (file)
@@ -5,11 +5,8 @@
 #ifndef V8_COMPILER_JS_GENERIC_LOWERING_H_
 #define V8_COMPILER_JS_GENERIC_LOWERING_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"
 
@@ -19,6 +16,7 @@ namespace compiler {
 
 // Forward declarations.
 class CommonOperatorBuilder;
+class JSGraph;
 class MachineOperatorBuilder;
 class Linkage;
 
@@ -26,8 +24,8 @@ class Linkage;
 // Lowers JS-level operators to runtime and IC calls in the "generic" case.
 class JSGenericLowering FINAL : public Reducer {
  public:
-  JSGenericLowering(bool is_typing_enabled, JSGraph* graph);
-  ~JSGenericLowering() FINAL {}
+  JSGenericLowering(bool is_typing_enabled, JSGraph* jsgraph);
+  ~JSGenericLowering() FINAL;
 
   Reduction Reduce(Node* node) FINAL;
 
@@ -46,16 +44,16 @@ class JSGenericLowering FINAL : public Reducer {
   // Helper for optimization of JSCallFunction.
   bool TryLowerDirectJSCall(Node* node);
 
-  Zone* zone() const { return graph()->zone(); }
-  Isolate* isolate() const { return jsgraph()->isolate(); }
+  Zone* zone() const;
+  Isolate* isolate() const;
   JSGraph* jsgraph() const { return jsgraph_; }
-  Graph* graph() const { return jsgraph()->graph(); }
-  CommonOperatorBuilder* common() const { return jsgraph()->common(); }
-  MachineOperatorBuilder* machine() const { return jsgraph()->machine(); }
+  Graph* graph() const;
+  CommonOperatorBuilder* common() const;
+  MachineOperatorBuilder* machine() const;
 
  private:
-  bool is_typing_enabled_;
-  JSGraph* jsgraph_;
+  bool const is_typing_enabled_;
+  JSGraph* const jsgraph_;
 };
 
 }  // namespace compiler
index 649b0d6..1f3c25d 100644 (file)
@@ -204,7 +204,7 @@ Node* JSGraph::EmptyFrameState() {
   if (!empty_frame_state_.is_set()) {
     Node* values = graph()->NewNode(common()->StateValues(0));
     Node* state_node = graph()->NewNode(
-        common()->FrameState(JS_FRAME, BailoutId(0),
+        common()->FrameState(JS_FRAME, BailoutId::None(),
                              OutputFrameStateCombine::Ignore()),
         values, values, values, NoContextConstant(), UndefinedConstant());
     empty_frame_state_.set(state_node);
index 91d0823..6c7b666 100644 (file)
@@ -2,29 +2,32 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "src/compiler/js-inlining.h"
+
 #include "src/ast.h"
 #include "src/ast-numbering.h"
-#include "src/compiler/access-builder.h"
+#include "src/compiler/all-nodes.h"
 #include "src/compiler/ast-graph-builder.h"
 #include "src/compiler/common-operator.h"
-#include "src/compiler/graph-inl.h"
-#include "src/compiler/graph-visualizer.h"
-#include "src/compiler/js-inlining.h"
+#include "src/compiler/js-context-specialization.h"
 #include "src/compiler/js-operator.h"
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties.h"
-#include "src/compiler/simplified-operator.h"
-#include "src/compiler/typer.h"
+#include "src/compiler/operator-properties.h"
 #include "src/full-codegen.h"
 #include "src/parser.h"
 #include "src/rewriter.h"
 #include "src/scopes.h"
 
-
 namespace v8 {
 namespace internal {
 namespace compiler {
 
+#define TRACE(...)                                      \
+  do {                                                  \
+    if (FLAG_trace_turbo_inlining) PrintF(__VA_ARGS__); \
+  } while (false)
+
 
 // Provides convenience accessors for calls to JS functions.
 class JSCallFunctionAccessor {
@@ -49,35 +52,14 @@ class JSCallFunctionAccessor {
     return value_inputs - 2;
   }
 
-  Node* frame_state() { return NodeProperties::GetFrameStateInput(call_); }
+  Node* frame_state() { return NodeProperties::GetFrameStateInput(call_, 0); }
 
  private:
   Node* call_;
 };
 
 
-Reduction JSInliner::Reduce(Node* node) {
-  if (node->opcode() != IrOpcode::kJSCallFunction) return NoChange();
-
-  JSCallFunctionAccessor call(node);
-  HeapObjectMatcher<JSFunction> match(call.jsfunction());
-  if (!match.HasValue()) return NoChange();
-
-  Handle<JSFunction> jsfunction = match.Value().handle();
-
-  if (jsfunction->shared()->native()) {
-    if (FLAG_trace_turbo_inlining) {
-      SmartArrayPointer<char> name =
-          jsfunction->shared()->DebugName()->ToCString();
-      PrintF("Not Inlining %s into %s because inlinee is native\n", name.get(),
-             info_->shared_info()->DebugName()->ToCString().get());
-    }
-    return NoChange();
-  }
-
-  return TryInlineJSCall(node, jsfunction);
-}
-
+namespace {
 
 // A facade on a JSFunction's graph to facilitate inlining. It assumes the
 // that the function graph has only one return statement, and provides
@@ -100,6 +82,11 @@ class Inlinee {
   Node* value_output() {
     return NodeProperties::GetValueInput(unique_return(), 0);
   }
+  // Return the control output of the graph,
+  // that is the control input of the return statement of the inlinee.
+  Node* control_output() {
+    return NodeProperties::GetControlInput(unique_return(), 0);
+  }
   // Return the unique return statement of the graph.
   Node* unique_return() {
     Node* unique_return = NodeProperties::GetControlInput(end_);
@@ -155,7 +142,7 @@ void Inlinee::UnifyReturn(JSGraph* jsgraph) {
         values.push_back(NodeProperties::GetValueInput(input, 0));
         effects.push_back(NodeProperties::GetEffectInput(input));
         edge.UpdateTo(NodeProperties::GetControlInput(input));
-        input->RemoveAllInputs();
+        input->NullAllInputs();
         break;
       default:
         UNREACHABLE();
@@ -174,86 +161,69 @@ void Inlinee::UnifyReturn(JSGraph* jsgraph) {
 }
 
 
-class CopyVisitor : public NullNodeVisitor {
+class CopyVisitor {
  public:
   CopyVisitor(Graph* source_graph, Graph* target_graph, Zone* temp_zone)
-      : copies_(source_graph->NodeCount(), NULL, temp_zone),
-        sentinels_(source_graph->NodeCount(), NULL, temp_zone),
+      : sentinel_op_(IrOpcode::kDead, Operator::kNoProperties, "Sentinel", 0, 0,
+                     0, 0, 0, 0),
+        sentinel_(target_graph->NewNode(&sentinel_op_)),
+        copies_(source_graph->NodeCount(), sentinel_, temp_zone),
         source_graph_(source_graph),
         target_graph_(target_graph),
-        temp_zone_(temp_zone),
-        sentinel_op_(IrOpcode::kDead, Operator::kNoProperties, "sentinel", 0, 0,
-                     0, 0, 0, 0) {}
+        temp_zone_(temp_zone) {}
+
+  Node* GetCopy(Node* orig) { return copies_[orig->id()]; }
 
-  void Post(Node* original) {
+  void CopyGraph() {
     NodeVector inputs(temp_zone_);
-    for (Node* const node : original->inputs()) {
-      inputs.push_back(GetCopy(node));
+    // TODO(bmeurer): AllNodes should be turned into something like
+    // Graph::CollectNodesReachableFromEnd() and the gray set stuff should be
+    // removed since it's only needed by the visualizer.
+    AllNodes all(temp_zone_, source_graph_);
+    // Copy all nodes reachable from end.
+    for (Node* orig : all.live) {
+      Node* copy = GetCopy(orig);
+      if (copy != sentinel_) {
+        // Mapping already exists.
+        continue;
+      }
+      // Copy the node.
+      inputs.clear();
+      for (Node* input : orig->inputs()) inputs.push_back(copies_[input->id()]);
+      copy = target_graph_->NewNode(orig->op(), orig->InputCount(),
+                                    inputs.empty() ? nullptr : &inputs[0]);
+      copies_[orig->id()] = copy;
     }
-
-    // Reuse the operator in the copy. This assumes that op lives in a zone
-    // that lives longer than graph()'s zone.
-    Node* copy =
-        target_graph_->NewNode(original->op(), static_cast<int>(inputs.size()),
-                               (inputs.empty() ? NULL : &inputs.front()));
-    copies_[original->id()] = copy;
-  }
-
-  Node* GetCopy(Node* original) {
-    Node* copy = copies_[original->id()];
-    if (copy == NULL) {
-      copy = GetSentinel(original);
+    // For missing inputs.
+    for (Node* orig : all.live) {
+      Node* copy = copies_[orig->id()];
+      for (int i = 0; i < copy->InputCount(); ++i) {
+        Node* input = copy->InputAt(i);
+        if (input == sentinel_) {
+          copy->ReplaceInput(i, GetCopy(orig->InputAt(i)));
+        }
+      }
     }
-    DCHECK(copy);
-    return copy;
-  }
-
-  void CopyGraph() {
-    source_graph_->VisitNodeInputsFromEnd(this);
-    ReplaceSentinels();
   }
 
-  const NodeVector& copies() { return copies_; }
+  const NodeVector& copies() const { return copies_; }
 
  private:
-  void ReplaceSentinels() {
-    for (NodeId id = 0; id < source_graph_->NodeCount(); ++id) {
-      Node* sentinel = sentinels_[id];
-      if (sentinel == NULL) continue;
-      Node* copy = copies_[id];
-      DCHECK(copy);
-      sentinel->ReplaceUses(copy);
-    }
-  }
-
-  Node* GetSentinel(Node* original) {
-    if (sentinels_[original->id()] == NULL) {
-      sentinels_[original->id()] = target_graph_->NewNode(&sentinel_op_);
-    }
-    return sentinels_[original->id()];
-  }
-
+  Operator const sentinel_op_;
+  Node* const sentinel_;
   NodeVector copies_;
-  NodeVector sentinels_;
-  Graph* source_graph_;
-  Graph* target_graph_;
-  Zone* temp_zone_;
-  Operator sentinel_op_;
+  Graph* const source_graph_;
+  Graph* const target_graph_;
+  Zone* const temp_zone_;
 };
 
 
 Reduction Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) {
   // The scheduler is smart enough to place our code; we just ensure {control}
-  // becomes the control input of the start of the inlinee.
+  // becomes the control input of the start of the inlinee, and {effect} becomes
+  // the effect input of the start of the inlinee.
   Node* control = NodeProperties::GetControlInput(call);
-
-  // The inlinee uses the context from the JSFunction object. This will
-  // also be the effect dependency for the inlinee as it produces an effect.
-  SimplifiedOperatorBuilder simplified(jsgraph->zone());
-  Node* context = jsgraph->graph()->NewNode(
-      simplified.LoadField(AccessBuilder::ForJSFunctionContext()),
-      NodeProperties::GetValueInput(call, 0),
-      NodeProperties::GetEffectInput(call), control);
+  Node* effect = NodeProperties::GetEffectInput(call);
 
   // Context is last argument.
   int inlinee_context_index = static_cast<int>(total_parameters()) - 1;
@@ -271,9 +241,9 @@ Reduction Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) {
           // projection but not the context, so rewire the input.
           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(use, context);
+          // TODO(turbofan): We always context specialize inlinees currently, so
+          // we should never get here.
+          UNREACHABLE();
         } else if (index < inlinee_context_index) {
           // Call has fewer arguments than required, fill with undefined.
           NodeProperties::ReplaceWithValue(use, jsgraph->UndefinedConstant());
@@ -285,7 +255,7 @@ Reduction Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) {
       }
       default:
         if (NodeProperties::IsEffectEdge(edge)) {
-          edge.UpdateTo(context);
+          edge.UpdateTo(effect);
         } else if (NodeProperties::IsControlEdge(edge)) {
           edge.UpdateTo(control);
         } else {
@@ -295,10 +265,14 @@ Reduction Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) {
     }
   }
 
-  NodeProperties::ReplaceWithValue(call, value_output(), effect_output());
+  NodeProperties::ReplaceWithValue(call, value_output(), effect_output(),
+                                   control_output());
+
   return Reducer::Replace(value_output());
 }
 
+}  // namespace
+
 
 void JSInliner::AddClosureToFrameState(Node* frame_state,
                                        Handle<JSFunction> jsfunction) {
@@ -333,38 +307,52 @@ Node* JSInliner::CreateArgumentsAdaptorFrameState(JSCallFunctionAccessor* call,
 }
 
 
-Reduction JSInliner::TryInlineJSCall(Node* call_node,
-                                     Handle<JSFunction> function) {
-  JSCallFunctionAccessor call(call_node);
-  CompilationInfoWithZone info(function);
+Reduction JSInliner::Reduce(Node* node) {
+  if (node->opcode() != IrOpcode::kJSCallFunction) return NoChange();
+
+  JSCallFunctionAccessor call(node);
+  HeapObjectMatcher<JSFunction> match(call.jsfunction());
+  if (!match.HasValue()) return NoChange();
 
-  if (!Compiler::ParseAndAnalyze(&info)) return NoChange();
+  Handle<JSFunction> function = match.Value().handle();
+  if (!function->IsJSFunction()) return NoChange();
+  if (mode_ == kBuiltinsInlining && !function->shared()->inline_builtin()) {
+    return NoChange();
+  }
+
+  Zone zone;
+  ParseInfo parse_info(&zone, function);
+  CompilationInfo info(&parse_info);
+
+  if (!Compiler::ParseAndAnalyze(info.parse_info())) return NoChange();
   if (!Compiler::EnsureDeoptimizationSupport(&info)) return NoChange();
 
   if (info.scope()->arguments() != NULL && is_sloppy(info.language_mode())) {
     // For now do not inline functions that use their arguments array.
-    SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString();
-    if (FLAG_trace_turbo_inlining) {
-      PrintF(
-          "Not Inlining %s into %s because inlinee uses arguments "
-          "array\n",
-          name.get(), info_->shared_info()->DebugName()->ToCString().get());
-    }
+    TRACE("Not Inlining %s into %s because inlinee uses arguments array\n",
+          function->shared()->DebugName()->ToCString().get(),
+          info_->shared_info()->DebugName()->ToCString().get());
     return NoChange();
   }
 
-  if (FLAG_trace_turbo_inlining) {
-    SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString();
-    PrintF("Inlining %s into %s\n", name.get(),
-           info_->shared_info()->DebugName()->ToCString().get());
-  }
+  TRACE("Inlining %s into %s\n",
+        function->shared()->DebugName()->ToCString().get(),
+        info_->shared_info()->DebugName()->ToCString().get());
 
   Graph graph(info.zone());
   JSGraph jsgraph(info.isolate(), &graph, jsgraph_->common(),
                   jsgraph_->javascript(), jsgraph_->machine());
 
+  // The inlinee specializes to the context from the JSFunction object.
+  // TODO(turbofan): We might want to load the context from the JSFunction at
+  // runtime in case we only know the SharedFunctionInfo once we have dynamic
+  // type feedback in the compiler.
   AstGraphBuilder graph_builder(local_zone_, &info, &jsgraph);
-  graph_builder.CreateGraph(false);
+  graph_builder.CreateGraph(true, false);
+  JSContextSpecializer context_specializer(&jsgraph);
+  GraphReducer graph_reducer(&graph, local_zone_);
+  graph_reducer.AddReducer(&context_specializer);
+  graph_reducer.ReduceGraph();
   Inlinee::UnifyReturn(&jsgraph);
 
   CopyVisitor visitor(&graph, jsgraph_->graph(), info.zone());
@@ -382,13 +370,14 @@ Reduction JSInliner::TryInlineJSCall(Node* call_node,
 
     for (Node* node : visitor.copies()) {
       if (node && node->opcode() == IrOpcode::kFrameState) {
+        DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
         AddClosureToFrameState(node, function);
-        NodeProperties::ReplaceFrameStateInput(node, outer_frame_state);
+        NodeProperties::ReplaceFrameStateInput(node, 0, outer_frame_state);
       }
     }
   }
 
-  return inlinee.InlineAtCall(jsgraph_, call_node);
+  return inlinee.InlineAtCall(jsgraph_, node);
 }
 
 }  // namespace compiler
index 8a4e0c1..0059b1c 100644 (file)
@@ -16,13 +16,16 @@ class JSCallFunctionAccessor;
 
 class JSInliner FINAL : public Reducer {
  public:
-  JSInliner(Zone* local_zone, CompilationInfo* info, JSGraph* jsgraph)
-      : local_zone_(local_zone), info_(info), jsgraph_(jsgraph) {}
+  enum Mode { kBuiltinsInlining, kGeneralInlining };
 
-  Reduction Reduce(Node* node) OVERRIDE;
+  JSInliner(Mode mode, Zone* local_zone, CompilationInfo* info,
+            JSGraph* jsgraph)
+      : mode_(mode), local_zone_(local_zone), info_(info), jsgraph_(jsgraph) {}
+
+  Reduction Reduce(Node* node) FINAL;
 
  private:
-  friend class InlinerVisitor;
+  Mode const mode_;
   Zone* local_zone_;
   CompilationInfo* info_;
   JSGraph* jsgraph_;
@@ -31,11 +34,10 @@ class JSInliner FINAL : public Reducer {
                                          Handle<JSFunction> jsfunction,
                                          Zone* temp_zone);
   void AddClosureToFrameState(Node* frame_state, Handle<JSFunction> jsfunction);
-  Reduction TryInlineJSCall(Node* node, Handle<JSFunction> jsfunction);
-  static void UnifyReturn(Graph* graph);
 };
-}
-}
-}  // namespace v8::internal::compiler
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_JS_INLINING_H_
index a1e6935..7253aab 100644 (file)
@@ -1,3 +1,4 @@
+
 // 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.
@@ -6,6 +7,7 @@
 
 #include "src/compiler/access-builder.h"
 #include "src/compiler/js-graph.h"
+#include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties.h"
 
 namespace v8 {
@@ -22,18 +24,50 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
       Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id());
   if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) return NoChange();
   switch (f->function_id) {
-    case Runtime::kInlineIsSmi:
-      return ReduceInlineIsSmi(node);
-    case Runtime::kInlineIsNonNegativeSmi:
-      return ReduceInlineIsNonNegativeSmi(node);
+    case Runtime::kInlineConstructDouble:
+      return ReduceConstructDouble(node);
+    case Runtime::kInlineDeoptimizeNow:
+      return ReduceDeoptimizeNow(node);
+    case Runtime::kInlineDoubleHi:
+      return ReduceDoubleHi(node);
+    case Runtime::kInlineDoubleLo:
+      return ReduceDoubleLo(node);
+    case Runtime::kInlineHeapObjectGetMap:
+      return ReduceHeapObjectGetMap(node);
+    case Runtime::kInlineIncrementStatsCounter:
+      return ReduceIncrementStatsCounter(node);
     case Runtime::kInlineIsArray:
-      return ReduceInlineIsInstanceType(node, JS_ARRAY_TYPE);
+      return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
     case Runtime::kInlineIsFunction:
-      return ReduceInlineIsInstanceType(node, JS_FUNCTION_TYPE);
+      return ReduceIsInstanceType(node, JS_FUNCTION_TYPE);
+    case Runtime::kInlineIsNonNegativeSmi:
+      return ReduceIsNonNegativeSmi(node);
     case Runtime::kInlineIsRegExp:
-      return ReduceInlineIsInstanceType(node, JS_REGEXP_TYPE);
+      return ReduceIsInstanceType(node, JS_REGEXP_TYPE);
+    case Runtime::kInlineIsSmi:
+      return ReduceIsSmi(node);
+    case Runtime::kInlineJSValueGetValue:
+      return ReduceJSValueGetValue(node);
+    case Runtime::kInlineMapGetInstanceType:
+      return ReduceMapGetInstanceType(node);
+    case Runtime::kInlineMathClz32:
+      return ReduceMathClz32(node);
+    case Runtime::kInlineMathFloor:
+      return ReduceMathFloor(node);
+    case Runtime::kInlineMathSqrt:
+      return ReduceMathSqrt(node);
+    case Runtime::kInlineOneByteSeqStringGetChar:
+      return ReduceSeqStringGetChar(node, String::ONE_BYTE_ENCODING);
+    case Runtime::kInlineOneByteSeqStringSetChar:
+      return ReduceSeqStringSetChar(node, String::ONE_BYTE_ENCODING);
+    case Runtime::kInlineStringGetLength:
+      return ReduceStringGetLength(node);
+    case Runtime::kInlineTwoByteSeqStringGetChar:
+      return ReduceSeqStringGetChar(node, String::TWO_BYTE_ENCODING);
+    case Runtime::kInlineTwoByteSeqStringSetChar:
+      return ReduceSeqStringSetChar(node, String::TWO_BYTE_ENCODING);
     case Runtime::kInlineValueOf:
-      return ReduceInlineValueOf(node);
+      return ReduceValueOf(node);
     default:
       break;
   }
@@ -41,17 +75,95 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
 }
 
 
-Reduction JSIntrinsicLowering::ReduceInlineIsSmi(Node* node) {
-  return Change(node, simplified()->ObjectIsSmi());
+Reduction JSIntrinsicLowering::ReduceConstructDouble(Node* node) {
+  Node* high = NodeProperties::GetValueInput(node, 0);
+  Node* low = NodeProperties::GetValueInput(node, 1);
+  Node* value =
+      graph()->NewNode(machine()->Float64InsertHighWord32(),
+                       graph()->NewNode(machine()->Float64InsertLowWord32(),
+                                        jsgraph()->Constant(0), low),
+                       high);
+  NodeProperties::ReplaceWithValue(node, value);
+  return Replace(value);
 }
 
 
-Reduction JSIntrinsicLowering::ReduceInlineIsNonNegativeSmi(Node* node) {
-  return Change(node, simplified()->ObjectIsNonNegativeSmi());
+Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
+  if (!FLAG_turbo_deoptimization) return NoChange();
+
+  Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
+  DCHECK_EQ(frame_state->opcode(), IrOpcode::kFrameState);
+
+  Node* effect = NodeProperties::GetEffectInput(node);
+  Node* control = NodeProperties::GetControlInput(node);
+
+  // We are making the continuation after the call dead. To
+  // model this, we generate if (true) statement with deopt
+  // in the true branch and continuation in the false branch.
+  Node* branch =
+      graph()->NewNode(common()->Branch(), jsgraph()->TrueConstant(), control);
+
+  // False branch - the original continuation.
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  NodeProperties::ReplaceWithValue(node, jsgraph()->UndefinedConstant(), effect,
+                                   if_false);
+
+  // True branch: deopt.
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* deopt =
+      graph()->NewNode(common()->Deoptimize(), frame_state, effect, if_true);
+
+  // Connect the deopt to the merge exiting the graph.
+  NodeProperties::MergeControlToEnd(graph(), common(), deopt);
+
+  return Changed(deopt);
 }
 
 
-Reduction JSIntrinsicLowering::ReduceInlineIsInstanceType(
+Reduction JSIntrinsicLowering::ReduceDoubleHi(Node* node) {
+  return Change(node, machine()->Float64ExtractHighWord32());
+}
+
+
+Reduction JSIntrinsicLowering::ReduceDoubleLo(Node* node) {
+  return Change(node, machine()->Float64ExtractLowWord32());
+}
+
+
+Reduction JSIntrinsicLowering::ReduceHeapObjectGetMap(Node* node) {
+  Node* value = NodeProperties::GetValueInput(node, 0);
+  Node* effect = NodeProperties::GetEffectInput(node);
+  Node* control = NodeProperties::GetControlInput(node);
+  return Change(node, simplified()->LoadField(AccessBuilder::ForMap()), value,
+                effect, control);
+}
+
+
+Reduction JSIntrinsicLowering::ReduceIncrementStatsCounter(Node* node) {
+  if (!FLAG_native_code_counters) return ChangeToUndefined(node);
+  HeapObjectMatcher<String> m(NodeProperties::GetValueInput(node, 0));
+  if (!m.HasValue() || !m.Value().handle()->IsString()) {
+    return ChangeToUndefined(node);
+  }
+  SmartArrayPointer<char> name = m.Value().handle()->ToCString();
+  StatsCounter counter(jsgraph()->isolate(), name.get());
+  if (!counter.Enabled()) return ChangeToUndefined(node);
+
+  Node* effect = NodeProperties::GetEffectInput(node);
+  Node* control = NodeProperties::GetControlInput(node);
+  FieldAccess access = AccessBuilder::ForStatsCounter();
+  Node* cnt = jsgraph()->ExternalConstant(ExternalReference(&counter));
+  Node* load =
+      graph()->NewNode(simplified()->LoadField(access), cnt, effect, control);
+  Node* inc =
+      graph()->NewNode(machine()->Int32Add(), load, jsgraph()->OneConstant());
+  Node* store = graph()->NewNode(simplified()->StoreField(access), cnt, inc,
+                                 load, control);
+  return ChangeToUndefined(node, store);
+}
+
+
+Reduction JSIntrinsicLowering::ReduceIsInstanceType(
     Node* node, InstanceType instance_type) {
   // if (%_IsSmi(value)) {
   //   return false;
@@ -91,7 +203,97 @@ Reduction JSIntrinsicLowering::ReduceInlineIsInstanceType(
 }
 
 
-Reduction JSIntrinsicLowering::ReduceInlineValueOf(Node* node) {
+Reduction JSIntrinsicLowering::ReduceIsNonNegativeSmi(Node* node) {
+  return Change(node, simplified()->ObjectIsNonNegativeSmi());
+}
+
+
+Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
+  return Change(node, simplified()->ObjectIsSmi());
+}
+
+
+Reduction JSIntrinsicLowering::ReduceJSValueGetValue(Node* node) {
+  Node* value = NodeProperties::GetValueInput(node, 0);
+  Node* effect = NodeProperties::GetEffectInput(node);
+  Node* control = NodeProperties::GetControlInput(node);
+  return Change(node, simplified()->LoadField(AccessBuilder::ForValue()), value,
+                effect, control);
+}
+
+
+Reduction JSIntrinsicLowering::ReduceMapGetInstanceType(Node* node) {
+  Node* value = NodeProperties::GetValueInput(node, 0);
+  Node* effect = NodeProperties::GetEffectInput(node);
+  Node* control = NodeProperties::GetControlInput(node);
+  return Change(node,
+                simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
+                value, effect, control);
+}
+
+
+Reduction JSIntrinsicLowering::ReduceMathClz32(Node* node) {
+  return Change(node, machine()->Word32Clz());
+}
+
+
+Reduction JSIntrinsicLowering::ReduceMathFloor(Node* node) {
+  if (!machine()->HasFloat64RoundDown()) return NoChange();
+  return Change(node, machine()->Float64RoundDown());
+}
+
+
+Reduction JSIntrinsicLowering::ReduceMathSqrt(Node* node) {
+  return Change(node, machine()->Float64Sqrt());
+}
+
+
+Reduction JSIntrinsicLowering::ReduceSeqStringGetChar(
+    Node* node, String::Encoding encoding) {
+  Node* effect = NodeProperties::GetEffectInput(node);
+  Node* control = NodeProperties::GetControlInput(node);
+  node->set_op(
+      simplified()->LoadElement(AccessBuilder::ForSeqStringChar(encoding)));
+  node->ReplaceInput(2, effect);
+  node->ReplaceInput(3, control);
+  node->TrimInputCount(4);
+  NodeProperties::ReplaceWithValue(node, node, node);
+  return Changed(node);
+}
+
+
+Reduction JSIntrinsicLowering::ReduceSeqStringSetChar(
+    Node* node, String::Encoding encoding) {
+  // Note: The intrinsic has a strange argument order, so we need to reshuffle.
+  Node* index = NodeProperties::GetValueInput(node, 0);
+  Node* chr = NodeProperties::GetValueInput(node, 1);
+  Node* string = NodeProperties::GetValueInput(node, 2);
+  Node* effect = NodeProperties::GetEffectInput(node);
+  Node* control = NodeProperties::GetControlInput(node);
+  node->set_op(
+      simplified()->StoreElement(AccessBuilder::ForSeqStringChar(encoding)));
+  node->ReplaceInput(0, string);
+  node->ReplaceInput(1, index);
+  node->ReplaceInput(2, chr);
+  node->ReplaceInput(3, effect);
+  node->ReplaceInput(4, control);
+  node->TrimInputCount(5);
+  NodeProperties::RemoveBounds(node);
+  NodeProperties::ReplaceWithValue(node, string, node);
+  return Changed(node);
+}
+
+
+Reduction JSIntrinsicLowering::ReduceStringGetLength(Node* node) {
+  Node* value = NodeProperties::GetValueInput(node, 0);
+  Node* effect = NodeProperties::GetEffectInput(node);
+  Node* control = NodeProperties::GetControlInput(node);
+  return Change(node, simplified()->LoadField(AccessBuilder::ForStringLength()),
+                value, effect, control);
+}
+
+
+Reduction JSIntrinsicLowering::ReduceValueOf(Node* node) {
   // if (%_IsSmi(value)) {
   //   return value;
   // } else if (%_GetInstanceType(%_GetMap(value)) == JS_VALUE_TYPE) {
@@ -145,7 +347,6 @@ Reduction JSIntrinsicLowering::ReduceInlineValueOf(Node* node) {
 
   Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
 
-
   // Replace all effect uses of {node} with the {ephi0}.
   Node* ephi0 = graph()->NewNode(ephi_op, etrue0, efalse0, merge0);
   NodeProperties::ReplaceWithValue(node, node, ephi0);
@@ -156,7 +357,7 @@ Reduction JSIntrinsicLowering::ReduceInlineValueOf(Node* node) {
 
 
 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
-  // Remove the effects from the node and update its effect usages.
+  // Replace all effect uses of {node} with the effect dependency.
   NodeProperties::ReplaceWithValue(node, node);
   // Remove the inputs corresponding to context, effect and control.
   NodeProperties::RemoveNonValueInputs(node);
@@ -173,6 +374,14 @@ Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
   node->ReplaceInput(1, b);
   node->ReplaceInput(2, c);
   node->TrimInputCount(3);
+  NodeProperties::ReplaceWithValue(node, node, node);
+  return Changed(node);
+}
+
+
+Reduction JSIntrinsicLowering::ChangeToUndefined(Node* node, Node* effect) {
+  NodeProperties::ReplaceWithValue(node, jsgraph()->UndefinedConstant(),
+                                   effect);
   return Changed(node);
 }
 
index bc188ca..35fb661 100644 (file)
@@ -27,13 +27,28 @@ class JSIntrinsicLowering FINAL : public Reducer {
   Reduction Reduce(Node* node) FINAL;
 
  private:
-  Reduction ReduceInlineIsSmi(Node* node);
-  Reduction ReduceInlineIsNonNegativeSmi(Node* node);
-  Reduction ReduceInlineIsInstanceType(Node* node, InstanceType instance_type);
-  Reduction ReduceInlineValueOf(Node* node);
+  Reduction ReduceConstructDouble(Node* node);
+  Reduction ReduceDeoptimizeNow(Node* node);
+  Reduction ReduceDoubleHi(Node* node);
+  Reduction ReduceDoubleLo(Node* node);
+  Reduction ReduceHeapObjectGetMap(Node* node);
+  Reduction ReduceIncrementStatsCounter(Node* node);
+  Reduction ReduceIsInstanceType(Node* node, InstanceType instance_type);
+  Reduction ReduceIsNonNegativeSmi(Node* node);
+  Reduction ReduceIsSmi(Node* node);
+  Reduction ReduceJSValueGetValue(Node* node);
+  Reduction ReduceMapGetInstanceType(Node* node);
+  Reduction ReduceMathClz32(Node* node);
+  Reduction ReduceMathFloor(Node* node);
+  Reduction ReduceMathSqrt(Node* node);
+  Reduction ReduceSeqStringGetChar(Node* node, String::Encoding encoding);
+  Reduction ReduceSeqStringSetChar(Node* node, String::Encoding encoding);
+  Reduction ReduceStringGetLength(Node* node);
+  Reduction ReduceValueOf(Node* node);
 
   Reduction Change(Node* node, const Operator* op);
   Reduction Change(Node* node, const Operator* op, Node* a, Node* b, Node* c);
+  Reduction ChangeToUndefined(Node* node, Node* effect = nullptr);
 
   Graph* graph() const;
   JSGraph* jsgraph() const { return jsgraph_; }
index 72c3969..327da55 100644 (file)
@@ -239,7 +239,7 @@ const StoreNamedParameters& StoreNamedParametersOf(const Operator* op) {
   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(StackCheck, Operator::kNoProperties, 0, 0)            \
   V(CreateFunctionContext, Operator::kNoProperties, 1, 1) \
   V(CreateWithContext, Operator::kNoProperties, 2, 1)     \
   V(CreateBlockContext, Operator::kNoProperties, 2, 1)    \
@@ -253,8 +253,9 @@ struct JSOperatorGlobalCache FINAL {
     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) {}               \
+                   Operator::ZeroIfEliminatable(properties),             \
+                   value_output_count, Operator::ZeroIfPure(properties), \
+                   Operator::ZeroIfNoThrow(properties)) {}               \
   };                                                                     \
   Name##Operator k##Name##Operator;
   CACHED_OP_LIST(CACHED)
@@ -265,7 +266,7 @@ struct JSOperatorGlobalCache FINAL {
     StorePropertyOperator()
         : Operator1<LanguageMode>(IrOpcode::kJSStoreProperty,
                                   Operator::kNoProperties, "JSStoreProperty", 3,
-                                  1, 1, 0, 1, 0, kLanguageMode) {}
+                                  1, 1, 0, 1, 2, kLanguageMode) {}
   };
   StorePropertyOperator<SLOPPY> kStorePropertySloppyOperator;
   StorePropertyOperator<STRICT> kStorePropertyStrictOperator;
@@ -294,7 +295,7 @@ const Operator* JSOperatorBuilder::CallFunction(size_t arity,
   return new (zone()) Operator1<CallFunctionParameters>(   // --
       IrOpcode::kJSCallFunction, Operator::kNoProperties,  // opcode
       "JSCallFunction",                                    // name
-      parameters.arity(), 1, 1, 1, 1, 0,                   // inputs/outputs
+      parameters.arity(), 1, 1, 1, 1, 2,                   // inputs/outputs
       parameters);                                         // parameter
 }
 
@@ -307,7 +308,7 @@ const Operator* JSOperatorBuilder::CallRuntime(Runtime::FunctionId id,
   return new (zone()) Operator1<CallRuntimeParameters>(   // --
       IrOpcode::kJSCallRuntime, Operator::kNoProperties,  // opcode
       "JSCallRuntime",                                    // name
-      parameters.arity(), 1, 1, f->result_size, 1, 0,     // inputs/outputs
+      parameters.arity(), 1, 1, f->result_size, 1, 2,     // inputs/outputs
       parameters);                                        // parameter
 }
 
@@ -316,7 +317,7 @@ 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, 1, 1, 1, 1, 2,                             // counts
       arguments);                                           // parameter
 }
 
@@ -328,7 +329,7 @@ const Operator* JSOperatorBuilder::LoadNamed(const Unique<Name>& name,
   return new (zone()) Operator1<LoadNamedParameters>(   // --
       IrOpcode::kJSLoadNamed, Operator::kNoProperties,  // opcode
       "JSLoadNamed",                                    // name
-      1, 1, 1, 1, 1, 0,                                 // counts
+      1, 1, 1, 1, 1, 2,                                 // counts
       parameters);                                      // parameter
 }
 
@@ -339,7 +340,7 @@ const Operator* JSOperatorBuilder::LoadProperty(
   return new (zone()) Operator1<LoadPropertyParameters>(   // --
       IrOpcode::kJSLoadProperty, Operator::kNoProperties,  // opcode
       "JSLoadProperty",                                    // name
-      2, 1, 1, 1, 1, 0,                                    // counts
+      2, 1, 1, 1, 1, 2,                                    // counts
       parameters);                                         // parameter
 }
 
@@ -361,7 +362,7 @@ const Operator* JSOperatorBuilder::StoreNamed(LanguageMode language_mode,
   return new (zone()) Operator1<StoreNamedParameters>(   // --
       IrOpcode::kJSStoreNamed, Operator::kNoProperties,  // opcode
       "JSStoreNamed",                                    // name
-      2, 1, 1, 0, 1, 0,                                  // counts
+      2, 1, 1, 0, 1, 2,                                  // counts
       parameters);                                       // parameter
 }
 
@@ -370,7 +371,7 @@ const Operator* JSOperatorBuilder::DeleteProperty(LanguageMode language_mode) {
   return new (zone()) Operator1<LanguageMode>(               // --
       IrOpcode::kJSDeleteProperty, Operator::kNoProperties,  // opcode
       "JSDeleteProperty",                                    // name
-      2, 1, 1, 1, 1, 0,                                      // counts
+      2, 1, 1, 1, 1, 2,                                      // counts
       language_mode);                                        // parameter
 }
 
@@ -378,21 +379,23 @@ const Operator* JSOperatorBuilder::DeleteProperty(LanguageMode language_mode) {
 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
+  return new (zone()) Operator1<ContextAccess>(  // --
+      IrOpcode::kJSLoadContext,                  // opcode
+      Operator::kNoWrite | Operator::kNoThrow,   // flags
+      "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
+  return new (zone()) Operator1<ContextAccess>(  // --
+      IrOpcode::kJSStoreContext,                 // opcode
+      Operator::kNoRead | Operator::kNoThrow,    // flags
+      "JSStoreContext",                          // name
+      2, 1, 1, 0, 1, 0,                          // counts
+      access);                                   // parameter
 }
 
 
@@ -401,7 +404,7 @@ const Operator* JSOperatorBuilder::CreateCatchContext(
   return new (zone()) Operator1<Unique<String>>(                 // --
       IrOpcode::kJSCreateCatchContext, Operator::kNoProperties,  // opcode
       "JSCreateCatchContext",                                    // name
-      2, 1, 1, 1, 1, 0,                                          // counts
+      2, 1, 1, 1, 1, 2,                                          // counts
       name);                                                     // parameter
 }
 
index e7fc04c..32fe356 100644 (file)
@@ -252,7 +252,8 @@ class JSOperatorBuilder FINAL : public ZoneObject {
 
   const Operator* TypeOf();
   const Operator* InstanceOf();
-  const Operator* Debugger();
+
+  const Operator* StackCheck();
 
   // TODO(titzer): nail down the static parts of each of these context flavors.
   const Operator* CreateFunctionContext();
diff --git a/deps/v8/src/compiler/js-type-feedback.cc b/deps/v8/src/compiler/js-type-feedback.cc
new file mode 100644 (file)
index 0000000..bdd61df
--- /dev/null
@@ -0,0 +1,256 @@
+// 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.
+
+#include "src/compiler/js-type-feedback.h"
+
+#include "src/property-details.h"
+
+#include "src/accessors.h"
+#include "src/ast.h"
+#include "src/type-info.h"
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/node-aux-data.h"
+#include "src/compiler/simplified-operator.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+enum LoadOrStore { LOAD, STORE };
+
+JSTypeFeedbackTable::JSTypeFeedbackTable(Zone* zone)
+    : map_(TypeFeedbackIdMap::key_compare(),
+           TypeFeedbackIdMap::allocator_type(zone)) {}
+
+
+void JSTypeFeedbackTable::Record(Node* node, TypeFeedbackId id) {
+  map_.insert(std::make_pair(node->id(), id));
+}
+
+
+Reduction JSTypeFeedbackSpecializer::Reduce(Node* node) {
+  // TODO(turbofan): type feedback currently requires deoptimization.
+  if (!FLAG_turbo_deoptimization) return NoChange();
+  switch (node->opcode()) {
+    case IrOpcode::kJSLoadProperty:
+      return ReduceJSLoadProperty(node);
+    case IrOpcode::kJSLoadNamed:
+      return ReduceJSLoadNamed(node);
+    case IrOpcode::kJSStoreNamed:
+      return ReduceJSStoreNamed(node);
+    case IrOpcode::kJSStoreProperty:
+      return ReduceJSStoreProperty(node);
+    default:
+      break;
+  }
+  return NoChange();
+}
+
+
+static bool GetInObjectFieldAccess(LoadOrStore mode, Handle<Map> map,
+                                   Handle<Name> name, FieldAccess* access) {
+  access->base_is_tagged = kTaggedBase;
+  access->offset = -1;
+  access->name = name;
+  access->type = Type::Any();
+  access->machine_type = kMachAnyTagged;
+
+  // Check for properties that have accessors but are JSObject fields.
+  if (Accessors::IsJSObjectFieldAccessor(map, name, &access->offset)) {
+    // TODO(turbofan): fill in types for special JSObject field accesses.
+    return true;
+  }
+
+  // Check if the map is a dictionary.
+  if (map->is_dictionary_map()) return false;
+
+  // Search the descriptor array.
+  DescriptorArray* descriptors = map->instance_descriptors();
+  int number = descriptors->SearchWithCache(*name, *map);
+  if (number == DescriptorArray::kNotFound) return false;
+  PropertyDetails property_details = descriptors->GetDetails(number);
+
+  bool is_smi = property_details.representation().IsSmi();
+  bool is_double = property_details.representation().IsDouble();
+
+  if (property_details.type() != DATA) {
+    // TODO(turbofan): constant loads and stores.
+    return false;
+  }
+
+  if (mode == STORE) {
+    if (property_details.IsReadOnly()) return false;
+    if (is_smi) {
+      // TODO(turbofan): SMI stores.
+      return false;
+    }
+    if (is_double) {
+      // TODO(turbofan): double stores.
+      return false;
+    }
+  } else {
+    // Check property details for loads.
+    if (is_smi) {
+      access->type = Type::SignedSmall();
+      access->machine_type = static_cast<MachineType>(kTypeInt32 | kRepTagged);
+    }
+    if (is_double) {
+      access->type = Type::Number();
+      access->machine_type = kMachFloat64;
+    }
+  }
+
+  int index = map->instance_descriptors()->GetFieldIndex(number);
+  FieldIndex field_index = FieldIndex::ForPropertyIndex(*map, index, is_double);
+
+  if (field_index.is_inobject()) {
+    access->offset = field_index.offset();
+    return true;
+  }
+
+  // TODO(turbofan): handle out of object properties.
+  return false;
+}
+
+
+Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) {
+  DCHECK(node->opcode() == IrOpcode::kJSLoadNamed);
+  TypeFeedbackId id = js_type_feedback_->find(node);
+  if (id.IsNone() || oracle()->LoadIsUninitialized(id)) return NoChange();
+
+  const LoadNamedParameters& p = LoadNamedParametersOf(node->op());
+  SmallMapList maps;
+  Handle<Name> name = p.name().handle();
+  Node* receiver = node->InputAt(0);
+  Node* effect = NodeProperties::GetEffectInput(node);
+  GatherReceiverTypes(receiver, effect, id, name, &maps);
+
+  if (maps.length() != 1) return NoChange();  // TODO(turbofan): polymorphism
+
+  Handle<Map> map = maps.first();
+  FieldAccess field_access;
+  if (!GetInObjectFieldAccess(LOAD, map, name, &field_access)) {
+    return NoChange();
+  }
+
+  Node* control = NodeProperties::GetControlInput(node);
+  Node* check_success;
+  Node* check_failed;
+  BuildMapCheck(receiver, map, true, effect, control, &check_success,
+                &check_failed);
+
+  // Build the actual load.
+  Node* load = graph()->NewNode(simplified()->LoadField(field_access), receiver,
+                                effect, check_success);
+
+  // TODO(turbofan): handle slow case instead of deoptimizing.
+  // TODO(titzer): frame state should be from before the load.
+  Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
+  Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect,
+                                 check_failed);
+  NodeProperties::MergeControlToEnd(graph(), common(), deopt);
+  NodeProperties::ReplaceWithValue(node, load, load, check_success);
+  return Replace(load);
+}
+
+
+Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) {
+  return NoChange();
+}
+
+
+Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) {
+  DCHECK(node->opcode() == IrOpcode::kJSStoreNamed);
+  TypeFeedbackId id = js_type_feedback_->find(node);
+  if (id.IsNone() || oracle()->StoreIsUninitialized(id)) return NoChange();
+
+  const StoreNamedParameters& p = StoreNamedParametersOf(node->op());
+  SmallMapList maps;
+  Handle<Name> name = p.name().handle();
+  Node* receiver = node->InputAt(0);
+  Node* effect = NodeProperties::GetEffectInput(node);
+  GatherReceiverTypes(receiver, effect, id, name, &maps);
+
+  if (maps.length() != 1) return NoChange();  // TODO(turbofan): polymorphism
+
+  Handle<Map> map = maps.first();
+  FieldAccess field_access;
+  if (!GetInObjectFieldAccess(STORE, map, name, &field_access)) {
+    return NoChange();
+  }
+
+  Node* control = NodeProperties::GetControlInput(node);
+  Node* check_success;
+  Node* check_failed;
+  BuildMapCheck(receiver, map, true, effect, control, &check_success,
+                &check_failed);
+
+  // Build the actual load.
+  Node* value = node->InputAt(1);
+  Node* store = graph()->NewNode(simplified()->StoreField(field_access),
+                                 receiver, value, effect, check_success);
+
+  // TODO(turbofan): handle slow case instead of deoptimizing.
+  // TODO(titzer): frame state should be from before the store.
+  Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
+  Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect,
+                                 check_failed);
+  NodeProperties::MergeControlToEnd(graph(), common(), deopt);
+  NodeProperties::ReplaceWithValue(node, store, store, check_success);
+  return Replace(store);
+}
+
+
+Reduction JSTypeFeedbackSpecializer::ReduceJSStoreProperty(Node* node) {
+  return NoChange();
+}
+
+
+void JSTypeFeedbackSpecializer::BuildMapCheck(Node* receiver, Handle<Map> map,
+                                              bool smi_check, Node* effect,
+                                              Node* control, Node** success,
+                                              Node** fail) {
+  Node* if_smi = nullptr;
+  if (smi_check) {
+    Node* branch_smi = graph()->NewNode(
+        common()->Branch(BranchHint::kFalse),
+        graph()->NewNode(simplified()->ObjectIsSmi(), receiver), control);
+    if_smi = graph()->NewNode(common()->IfTrue(), branch_smi);
+    control = graph()->NewNode(common()->IfFalse(), branch_smi);
+  }
+
+  FieldAccess map_access = AccessBuilder::ForMap();
+  Node* receiver_map = graph()->NewNode(simplified()->LoadField(map_access),
+                                        receiver, effect, control);
+  Node* map_const = jsgraph_->Constant(map);
+  Node* cmp = graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
+                               receiver_map, map_const);
+  Node* branch =
+      graph()->NewNode(common()->Branch(BranchHint::kTrue), cmp, control);
+  *success = graph()->NewNode(common()->IfTrue(), branch);
+  *fail = graph()->NewNode(common()->IfFalse(), branch);
+
+  if (if_smi) {
+    *fail = graph()->NewNode(common()->Merge(2), *fail, if_smi);
+  }
+}
+
+
+void JSTypeFeedbackSpecializer::GatherReceiverTypes(Node* receiver,
+                                                    Node* effect,
+                                                    TypeFeedbackId id,
+                                                    Handle<Name> name,
+                                                    SmallMapList* maps) {
+  // TODO(turbofan): filter maps by initial receiver map if known
+  // TODO(turbofan): filter maps by native context (if specializing)
+  // TODO(turbofan): filter maps by effect chain
+  oracle()->PropertyReceiverTypes(id, name, maps);
+}
+
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/deps/v8/src/compiler/js-type-feedback.h b/deps/v8/src/compiler/js-type-feedback.h
new file mode 100644 (file)
index 0000000..033da65
--- /dev/null
@@ -0,0 +1,91 @@
+// 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.
+
+#ifndef V8_COMPILER_JS_TYPE_FEEDBACK_H_
+#define V8_COMPILER_JS_TYPE_FEEDBACK_H_
+
+#include "src/utils.h"
+
+#include "src/compiler/graph-reducer.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/node-aux-data.h"
+#include "src/compiler/simplified-operator.h"
+
+namespace v8 {
+namespace internal {
+
+class TypeFeedbackOracle;
+class SmallMapList;
+
+namespace compiler {
+
+// Stores type feedback information for nodes in the graph in a separate
+// data structure.
+class JSTypeFeedbackTable : public ZoneObject {
+ public:
+  explicit JSTypeFeedbackTable(Zone* zone);
+
+  // TODO(titzer): support recording the feedback vector slot.
+
+  void Record(Node* node, TypeFeedbackId id);
+
+ private:
+  friend class JSTypeFeedbackSpecializer;
+  typedef std::map<NodeId, TypeFeedbackId, std::less<NodeId>,
+                   zone_allocator<TypeFeedbackId> > TypeFeedbackIdMap;
+
+  TypeFeedbackIdMap map_;
+
+  TypeFeedbackId find(Node* node) {
+    TypeFeedbackIdMap::const_iterator it = map_.find(node->id());
+    return it == map_.end() ? TypeFeedbackId::None() : it->second;
+  }
+};
+
+
+// Specializes a graph to the type feedback recorded in the
+// {js_type_feedback} provided to the constructor.
+class JSTypeFeedbackSpecializer : public Reducer {
+ public:
+  JSTypeFeedbackSpecializer(JSGraph* jsgraph,
+                            JSTypeFeedbackTable* js_type_feedback,
+                            TypeFeedbackOracle* oracle)
+      : jsgraph_(jsgraph),
+        simplified_(jsgraph->graph()->zone()),
+        js_type_feedback_(js_type_feedback),
+        oracle_(oracle) {
+    CHECK(js_type_feedback);
+  }
+
+  Reduction Reduce(Node* node) OVERRIDE;
+
+  // Visible for unit testing.
+  Reduction ReduceJSLoadNamed(Node* node);
+  Reduction ReduceJSLoadProperty(Node* node);
+  Reduction ReduceJSStoreNamed(Node* node);
+  Reduction ReduceJSStoreProperty(Node* node);
+
+ private:
+  JSGraph* jsgraph_;
+  SimplifiedOperatorBuilder simplified_;
+  JSTypeFeedbackTable* js_type_feedback_;
+  TypeFeedbackOracle* oracle_;
+
+  TypeFeedbackOracle* oracle() { return oracle_; }
+  Graph* graph() { return jsgraph_->graph(); }
+  CommonOperatorBuilder* common() { return jsgraph_->common(); }
+  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
+
+  void BuildMapCheck(Node* receiver, Handle<Map> map, bool smi_check,
+                     Node* effect, Node* control, Node** success, Node** fail);
+
+  void GatherReceiverTypes(Node* receiver, Node* effect, TypeFeedbackId id,
+                           Handle<Name> property, SmallMapList* maps);
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif
index bbe46fb..244cfe2 100644 (file)
@@ -19,36 +19,32 @@ namespace compiler {
 // - relax effects from generic but not-side-effecting operations
 
 
-// Relax the effects of {node} by immediately replacing effect uses of {node}
-// with the effect input to {node}.
+// Relax the effects of {node} by immediately replacing effect and control uses
+// of {node} with the effect and control input to {node}.
 // TODO(turbofan): replace the effect input to {node} with {graph->start()}.
 // TODO(titzer): move into a GraphEditor?
-static void RelaxEffects(Node* node) {
+static void RelaxEffectsAndControls(Node* node) {
   NodeProperties::ReplaceWithValue(node, node, NULL);
 }
 
 
+// Relax the control uses of {node} by immediately replacing them with the
+// control input to {node}.
+// TODO(titzer): move into a GraphEditor?
+static void RelaxControls(Node* node) {
+  NodeProperties::ReplaceWithValue(node, node, node);
+}
+
+
 JSTypedLowering::JSTypedLowering(JSGraph* jsgraph, Zone* zone)
     : jsgraph_(jsgraph), simplified_(graph()->zone()), conversions_(zone) {
-  zero_range_ = Type::Range(0.0, 1.0, graph()->zone());
+  zero_range_ = Type::Range(0.0, 0.0, graph()->zone());
   one_range_ = Type::Range(1.0, 1.0, graph()->zone());
   zero_thirtyone_range_ = Type::Range(0.0, 31.0, 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) {
-      double min = kMinInt / (1 << k);
-      double max = 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) {
-      double min = kMinInt / (1 << k);
-      double max = kMaxInt / (1 << k);
-      shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
-    }
+  for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) {
+    double min = kMinInt / (1 << k);
+    double max = kMaxInt / (1 << k);
+    shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
   }
 }
 
@@ -66,14 +62,36 @@ Reduction JSTypedLowering::ReplaceEagerly(Node* old, Node* node) {
 class JSBinopReduction FINAL {
  public:
   JSBinopReduction(JSTypedLowering* lowering, Node* node)
-      : lowering_(lowering),
-        node_(node),
-        left_type_(NodeProperties::GetBounds(node->InputAt(0)).upper),
-        right_type_(NodeProperties::GetBounds(node->InputAt(1)).upper) {}
+      : lowering_(lowering), node_(node) {}
 
-  void ConvertInputsToNumber() {
-    node_->ReplaceInput(0, ConvertToNumber(left()));
-    node_->ReplaceInput(1, ConvertToNumber(right()));
+  void ConvertPrimitiveInputsToNumber() {
+    node_->ReplaceInput(0, ConvertPrimitiveToNumber(left()));
+    node_->ReplaceInput(1, ConvertPrimitiveToNumber(right()));
+  }
+
+  void ConvertInputsToNumber(Node* frame_state) {
+    // To convert the inputs to numbers, we have to provide frame states
+    // for lazy bailouts in the ToNumber conversions.
+    // We use a little hack here: we take the frame state before the binary
+    // operation and use it to construct the frame states for the conversion
+    // so that after the deoptimization, the binary operation IC gets
+    // already converted values from full code. This way we are sure that we
+    // will not re-do any of the side effects.
+
+    Node* left_input =
+        left_type()->Is(Type::PlainPrimitive())
+            ? ConvertPrimitiveToNumber(left())
+            : ConvertToNumber(left(),
+                              CreateFrameStateForLeftInput(frame_state));
+
+    Node* right_input =
+        right_type()->Is(Type::PlainPrimitive())
+            ? ConvertPrimitiveToNumber(right())
+            : ConvertToNumber(right(), CreateFrameStateForRightInput(
+                                           frame_state, left_input));
+
+    node_->ReplaceInput(0, left_input);
+    node_->ReplaceInput(1, right_input);
   }
 
   void ConvertInputsToUI32(Signedness left_signedness,
@@ -89,8 +107,9 @@ class JSBinopReduction FINAL {
 
   // Convert inputs for bitwise shift operation (ES5 spec 11.7).
   void ConvertInputsForShift(Signedness left_signedness) {
-    node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
-    Node* rnum = ConvertToUI32(right(), kUnsigned);
+    node_->ReplaceInput(
+        0, ConvertToUI32(ConvertPrimitiveToNumber(left()), left_signedness));
+    Node* rnum = ConvertToUI32(ConvertPrimitiveToNumber(right()), kUnsigned);
     Type* rnum_type = NodeProperties::GetBounds(rnum).upper;
     if (!rnum_type->Is(lowering_->zero_thirtyone_range_)) {
       rnum = graph()->NewNode(machine()->Word32And(), rnum,
@@ -104,7 +123,6 @@ class JSBinopReduction FINAL {
     Node* r = right();
     node_->ReplaceInput(0, r);
     node_->ReplaceInput(1, l);
-    std::swap(left_type_, right_type_);
   }
 
   // Remove all effect and control inputs and outputs to this node and change
@@ -116,9 +134,9 @@ class JSBinopReduction FINAL {
     DCHECK_EQ(0, op->ControlInputCount());
     DCHECK_EQ(2, op->ValueInputCount());
 
-    // Remove the effects from the node, if any, and update its effect usages.
+    // Remove the effects from the node, and update its effect/control usages.
     if (node_->op()->EffectInputCount() > 0) {
-      RelaxEffects(node_);
+      RelaxEffectsAndControls(node_);
     }
     // Remove the inputs corresponding to context, effect, and control.
     NodeProperties::RemoveNonValueInputs(node_);
@@ -145,18 +163,18 @@ class JSBinopReduction FINAL {
     return ChangeToPureOperator(op, false, type);
   }
 
-  bool OneInputIs(Type* t) { return left_type_->Is(t) || right_type_->Is(t); }
+  bool OneInputIs(Type* t) { return left_type()->Is(t) || right_type()->Is(t); }
 
   bool BothInputsAre(Type* t) {
-    return left_type_->Is(t) && right_type_->Is(t);
+    return left_type()->Is(t) && right_type()->Is(t);
   }
 
   bool OneInputCannotBe(Type* t) {
-    return !left_type_->Maybe(t) || !right_type_->Maybe(t);
+    return !left_type()->Maybe(t) || !right_type()->Maybe(t);
   }
 
   bool NeitherInputCanBe(Type* t) {
-    return !left_type_->Maybe(t) && !right_type_->Maybe(t);
+    return !left_type()->Maybe(t) && !right_type()->Maybe(t);
   }
 
   Node* effect() { return NodeProperties::GetEffectInput(node_); }
@@ -164,8 +182,12 @@ class JSBinopReduction FINAL {
   Node* context() { return NodeProperties::GetContextInput(node_); }
   Node* left() { return NodeProperties::GetValueInput(node_, 0); }
   Node* right() { return NodeProperties::GetValueInput(node_, 1); }
-  Type* left_type() { return left_type_; }
-  Type* right_type() { return right_type_; }
+  Type* left_type() {
+    return NodeProperties::GetBounds(node_->InputAt(0)).upper;
+  }
+  Type* right_type() {
+    return NodeProperties::GetBounds(node_->InputAt(1)).upper;
+  }
 
   SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
   Graph* graph() const { return lowering_->graph(); }
@@ -177,8 +199,6 @@ class JSBinopReduction FINAL {
  private:
   JSTypedLowering* lowering_;  // The containing lowering instance.
   Node* node_;                 // The original node.
-  Type* left_type_;            // Cache of the left input's type.
-  Type* right_type_;           // Cache of the right input's type.
 
   Node* ConvertToString(Node* node) {
     // Avoid introducing too many eager ToString() operations.
@@ -190,27 +210,93 @@ class JSBinopReduction FINAL {
     return n;
   }
 
-  Node* ConvertToNumber(Node* node) {
+  Node* CreateFrameStateForLeftInput(Node* frame_state) {
+    if (!FLAG_turbo_deoptimization) return nullptr;
+
+    FrameStateCallInfo state_info =
+        OpParameter<FrameStateCallInfo>(frame_state);
+    // If the frame state is already the right one, just return it.
+    if (state_info.state_combine().kind() == OutputFrameStateCombine::kPokeAt &&
+        state_info.state_combine().GetOffsetToPokeAt() == 1) {
+      return frame_state;
+    }
+
+    // Here, we smash the result of the conversion into the slot just below
+    // the stack top. This is the slot that full code uses to store the
+    // left operand.
+    const Operator* op = jsgraph()->common()->FrameState(
+        state_info.type(), state_info.bailout_id(),
+        OutputFrameStateCombine::PokeAt(1));
+
+    return graph()->NewNode(op, frame_state->InputAt(0),
+                            frame_state->InputAt(1), frame_state->InputAt(2),
+                            frame_state->InputAt(3), frame_state->InputAt(4));
+  }
+
+  Node* CreateFrameStateForRightInput(Node* frame_state, Node* converted_left) {
+    if (!FLAG_turbo_deoptimization) return nullptr;
+
+    FrameStateCallInfo state_info =
+        OpParameter<FrameStateCallInfo>(frame_state);
+
+    if (state_info.bailout_id() == BailoutId::None()) {
+      // Dummy frame state => just leave it as is.
+      return frame_state;
+    }
+
+    // Create a frame state that stores the result of the operation to the
+    // top of the stack (i.e., the slot used for the right operand).
+    const Operator* op = jsgraph()->common()->FrameState(
+        state_info.type(), state_info.bailout_id(),
+        OutputFrameStateCombine::PokeAt(0));
+
+    // Change the left operand {converted_left} on the expression stack.
+    Node* stack = frame_state->InputAt(2);
+    DCHECK_EQ(stack->opcode(), IrOpcode::kStateValues);
+    DCHECK_GE(stack->InputCount(), 2);
+
+    // TODO(jarin) Allocate in a local zone or a reusable buffer.
+    NodeVector new_values(stack->InputCount(), zone());
+    for (int i = 0; i < stack->InputCount(); i++) {
+      if (i == stack->InputCount() - 2) {
+        new_values[i] = converted_left;
+      } else {
+        new_values[i] = stack->InputAt(i);
+      }
+    }
+    Node* new_stack =
+        graph()->NewNode(stack->op(), stack->InputCount(), &new_values.front());
+
+    return graph()->NewNode(op, frame_state->InputAt(0),
+                            frame_state->InputAt(1), new_stack,
+                            frame_state->InputAt(3), frame_state->InputAt(4));
+  }
+
+  Node* ConvertPrimitiveToNumber(Node* node) {
+    return lowering_->ConvertPrimitiveToNumber(node);
+  }
+
+  Node* ConvertToNumber(Node* node, Node* frame_state) {
     if (NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())) {
-      return lowering_->ConvertToNumber(node);
+      return ConvertPrimitiveToNumber(node);
+    } else if (!FLAG_turbo_deoptimization) {
+      // We cannot use ConvertToPrimitiveNumber here because we need context
+      // for converting general values.
+      Node* const n = graph()->NewNode(javascript()->ToNumber(), node,
+                                       context(), effect(), control());
+      update_effect(n);
+      return n;
+    } else {
+      Node* const n =
+          graph()->NewNode(javascript()->ToNumber(), node, context(),
+                           frame_state, effect(), control());
+      update_effect(n);
+      return n;
     }
-    // TODO(jarin) This ToNumber conversion can deoptimize, but we do not really
-    // have a frame state to deoptimize to. Either we provide such a frame state
-    // or we exclude the values that could lead to deoptimization (e.g., by
-    // triggering eager deopt if the value is not plain).
-    Node* const n = FLAG_turbo_deoptimization
-                        ? graph()->NewNode(
-                              javascript()->ToNumber(), node, context(),
-                              jsgraph()->EmptyFrameState(), effect(), control())
-                        : graph()->NewNode(javascript()->ToNumber(), node,
-                                           context(), effect(), control());
-    update_effect(n);
-    return n;
   }
 
   Node* ConvertToUI32(Node* node, Signedness signedness) {
     // Avoid introducing too many eager NumberToXXnt32() operations.
-    node = ConvertToNumber(node);
     Type* type = NodeProperties::GetBounds(node).upper;
     if (signedness == kSigned) {
       if (!type->Is(Type::Signed32())) {
@@ -237,22 +323,15 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
     // JSAdd(x:number, y:number) => NumberAdd(x, y)
     return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
   }
-  if (r.BothInputsAre(Type::Primitive()) &&
-      r.NeitherInputCanBe(Type::StringOrReceiver())) {
+  if (r.NeitherInputCanBe(Type::StringOrReceiver())) {
     // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
-    r.ConvertInputsToNumber();
+    Node* frame_state = FLAG_turbo_deoptimization
+                            ? NodeProperties::GetFrameStateInput(node, 1)
+                            : nullptr;
+    r.ConvertInputsToNumber(frame_state);
     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.
@@ -269,79 +348,25 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
 }
 
 
-Reduction JSTypedLowering::ReduceJSBitwiseOr(Node* node) {
-  JSBinopReduction r(this, node);
-
-  // We can only reduce to Word32Or if we are sure the to-number conversions
-  // cannot lazily deoptimize.
-  bool shortcut_or_zero =
-      !FLAG_turbo_deoptimization && r.OneInputIs(zero_range_);
-  if (r.BothInputsAre(Type::Primitive()) || shortcut_or_zero) {
-    // 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);
-
-  // We can only reduce to NumberMultiply if we are sure the to-number
-  // conversions cannot lazily deoptimize.
-  bool shortcut_multiply_one =
-      !FLAG_turbo_deoptimization && r.OneInputIs(one_range_);
-
-  if (r.BothInputsAre(Type::Primitive()) || shortcut_multiply_one) {
-    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.
-    // TODO(turbofan): make this heuristic configurable for code size.
-    r.ConvertInputsToNumber();
-    return r.ChangeToPureOperator(numberOp);
-  }
-#endif
-  // TODO(turbofan): relax/remove the effects of this operator in other cases.
-  return NoChange();
+  Node* frame_state = FLAG_turbo_deoptimization
+                          ? NodeProperties::GetFrameStateInput(node, 1)
+                          : nullptr;
+  r.ConvertInputsToNumber(frame_state);
+  return r.ChangeToPureOperator(numberOp, Type::Number());
 }
 
 
 Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
   JSBinopReduction r(this, node);
-  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();
+  Node* frame_state = FLAG_turbo_deoptimization
+                          ? NodeProperties::GetFrameStateInput(node, 1)
+                          : nullptr;
+  r.ConvertInputsToNumber(frame_state);
+  r.ConvertInputsToUI32(kSigned, kSigned);
+  return r.ChangeToPureOperator(intOp, Type::Integral32());
 }
 
 
@@ -392,7 +417,7 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
     ...
   }
 #endif
-  if (r.BothInputsAre(Type::Primitive()) &&
+  if (r.BothInputsAre(Type::PlainPrimitive()) &&
       r.OneInputCannotBe(Type::StringOrReceiver())) {
     const Operator* less_than;
     const Operator* less_than_or_equal;
@@ -404,7 +429,7 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
       less_than_or_equal = machine()->Int32LessThanOrEqual();
     } else {
       // TODO(turbofan): mixed signed/unsigned int32 comparisons.
-      r.ConvertInputsToNumber();
+      r.ConvertPrimitiveInputsToNumber();
       less_than = simplified()->NumberLessThan();
       less_than_or_equal = simplified()->NumberLessThanOrEqual();
     }
@@ -501,33 +526,64 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
 
 
 Reduction JSTypedLowering::ReduceJSUnaryNot(Node* node) {
-  Node* input = node->InputAt(0);
-  Type* input_type = NodeProperties::GetBounds(input).upper;
+  Node* const input = node->InputAt(0);
+  Type* const input_type = NodeProperties::GetBounds(input).upper;
   if (input_type->Is(Type::Boolean())) {
-    // JSUnaryNot(x:boolean,context) => BooleanNot(x)
+    // JSUnaryNot(x:boolean) => BooleanNot(x)
     node->set_op(simplified()->BooleanNot());
     node->TrimInputCount(1);
     return Changed(node);
+  } else if (input_type->Is(Type::OrderedNumber())) {
+    // JSUnaryNot(x:number) => NumberEqual(x,#0)
+    node->set_op(simplified()->NumberEqual());
+    node->ReplaceInput(1, jsgraph()->ZeroConstant());
+    node->TrimInputCount(2);
+    return Changed(node);
+  } else if (input_type->Is(Type::String())) {
+    // JSUnaryNot(x:string) => NumberEqual(x.length,#0)
+    FieldAccess const access = AccessBuilder::ForStringLength();
+    // It is safe for the load to be effect-free (i.e. not linked into effect
+    // chain) because we assume String::length to be immutable.
+    Node* length = graph()->NewNode(simplified()->LoadField(access), input,
+                                    graph()->start(), graph()->start());
+    node->set_op(simplified()->NumberEqual());
+    node->ReplaceInput(0, length);
+    node->ReplaceInput(1, jsgraph()->ZeroConstant());
+    node->TrimInputCount(2);
+    NodeProperties::ReplaceWithValue(node, node, length);
+    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);
+  return NoChange();
 }
 
 
 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
-  Node* input = node->InputAt(0);
-  Type* input_type = NodeProperties::GetBounds(input).upper;
+  Node* const input = node->InputAt(0);
+  Type* const input_type = NodeProperties::GetBounds(input).upper;
   if (input_type->Is(Type::Boolean())) {
-    // JSToBoolean(x:boolean,context) => x
+    // JSToBoolean(x:boolean) => x
     return Replace(input);
+  } else if (input_type->Is(Type::OrderedNumber())) {
+    // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0))
+    node->set_op(simplified()->BooleanNot());
+    node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input,
+                                           jsgraph()->ZeroConstant()));
+    node->TrimInputCount(1);
+    return Changed(node);
+  } else if (input_type->Is(Type::String())) {
+    // JSToBoolean(x:string) => NumberLessThan(#0,x.length)
+    FieldAccess const access = AccessBuilder::ForStringLength();
+    // It is safe for the load to be effect-free (i.e. not linked into effect
+    // chain) because we assume String::length to be immutable.
+    Node* length = graph()->NewNode(simplified()->LoadField(access), input,
+                                    graph()->start(), graph()->start());
+    node->set_op(simplified()->NumberLessThan());
+    node->ReplaceInput(0, jsgraph()->ZeroConstant());
+    node->ReplaceInput(1, length);
+    node->TrimInputCount(2);
+    return Changed(node);
   }
-  // JSToBoolean(x,context) => AnyToBoolean(x)
-  node->set_op(simplified()->AnyToBoolean());
-  node->TrimInputCount(1);
-  return Changed(node);
+  return NoChange();
 }
 
 
@@ -584,7 +640,7 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
       DCHECK(NodeProperties::IsControl(control));
       DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number()));
       DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number()));
-      RelaxEffects(node);
+      RelaxEffectsAndControls(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
@@ -593,7 +649,7 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
         // 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* const value = ConvertPrimitiveToNumber(input->InputAt(i));
         if (i < node->InputCount()) {
           node->ReplaceInput(i, value);
         } else {
@@ -616,7 +672,7 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
       DCHECK_EQ(3, input_count);
       DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number()));
       DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number()));
-      RelaxEffects(node);
+      RelaxEffectsAndControls(node);
       node->set_op(common()->Select(kMachAnyTagged, input_hint));
       node->ReplaceInput(0, input->InputAt(0));
       for (int i = 1; i < input_count; ++i) {
@@ -626,7 +682,7 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
         // 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* const value = ConvertPrimitiveToNumber(input->InputAt(i));
         node->ReplaceInput(i, value);
       }
       node->TrimInputCount(input_count);
@@ -640,12 +696,13 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
         NodeProperties::GetControlInput(node) != graph()->start()) {
       // JSToNumber(x:plain-primitive,context,effect,control)
       //   => JSToNumber(x,no-context,start,start)
-      RelaxEffects(node);
+      RelaxEffectsAndControls(node);
       NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
       NodeProperties::ReplaceControlInput(node, graph()->start());
       NodeProperties::ReplaceEffectInput(node, graph()->start());
-      if (OperatorProperties::HasFrameStateInput(node->op())) {
-        NodeProperties::ReplaceFrameStateInput(node,
+      if (FLAG_turbo_deoptimization) {
+        DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
+        NodeProperties::ReplaceFrameStateInput(node, 0,
                                                jsgraph()->EmptyFrameState());
       }
       return Changed(node);
@@ -767,11 +824,15 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
         if (number_reduction.Changed()) {
           value = number_reduction.replacement();
         } else {
-          if (OperatorProperties::HasFrameStateInput(
-                  javascript()->ToNumber())) {
+          DCHECK(FLAG_turbo_deoptimization ==
+                 (OperatorProperties::GetFrameStateInputCount(
+                      javascript()->ToNumber()) == 1));
+          if (FLAG_turbo_deoptimization) {
+            Node* frame_state_for_to_number =
+                NodeProperties::GetFrameStateInput(node, 1);
             value = effect =
                 graph()->NewNode(javascript()->ToNumber(), value, context,
-                                 jsgraph()->EmptyFrameState(), effect, control);
+                                 frame_state_for_to_number, effect, control);
           } else {
             value = effect = graph()->NewNode(javascript()->ToNumber(), value,
                                               context, effect, control);
@@ -796,6 +857,7 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
         node->ReplaceInput(3, effect);
         node->ReplaceInput(4, control);
         node->TrimInputCount(5);
+        RelaxControls(node);
         return Changed(node);
       }
       // Compute byte offset.
@@ -809,6 +871,7 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
       node->ReplaceInput(4, effect);
       node->ReplaceInput(5, control);
       node->TrimInputCount(6);
+      RelaxControls(node);
       return Changed(node);
     }
   }
@@ -904,7 +967,7 @@ Reduction JSTypedLowering::Reduce(Node* node) {
     case IrOpcode::kJSGreaterThanOrEqual:
       return ReduceJSComparison(node);
     case IrOpcode::kJSBitwiseOr:
-      return ReduceJSBitwiseOr(node);
+      return ReduceInt32Binop(node, machine()->Word32Or());
     case IrOpcode::kJSBitwiseXor:
       return ReduceInt32Binop(node, machine()->Word32Xor());
     case IrOpcode::kJSBitwiseAnd:
@@ -920,7 +983,7 @@ Reduction JSTypedLowering::Reduce(Node* node) {
     case IrOpcode::kJSSubtract:
       return ReduceNumberBinop(node, simplified()->NumberSubtract());
     case IrOpcode::kJSMultiply:
-      return ReduceJSMultiply(node);
+      return ReduceNumberBinop(node, simplified()->NumberMultiply());
     case IrOpcode::kJSDivide:
       return ReduceNumberBinop(node, simplified()->NumberDivide());
     case IrOpcode::kJSModulus:
@@ -948,7 +1011,7 @@ Reduction JSTypedLowering::Reduce(Node* node) {
 }
 
 
-Node* JSTypedLowering::ConvertToNumber(Node* input) {
+Node* JSTypedLowering::ConvertPrimitiveToNumber(Node* input) {
   DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive()));
   // Avoid inserting too many eager ToNumber() operations.
   Reduction const reduction = ReduceJSToNumberInput(input);
index 838085e..d7e5b42 100644 (file)
@@ -52,7 +52,7 @@ class JSTypedLowering FINAL : public Reducer {
   Reduction ReduceUI32Shift(Node* node, Signedness left_signedness,
                             const Operator* shift_op);
 
-  Node* ConvertToNumber(Node* input);
+  Node* ConvertPrimitiveToNumber(Node* input);
   template <IrOpcode::Value>
   Node* FindConversion(Node* input);
   void InsertConversion(Node* conversion);
index 4242c95..e5b4595 100644 (file)
@@ -9,10 +9,10 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
-typedef BasicBlock::RpoNumber RpoNumber;
-
-#define TRACE(x) \
-  if (FLAG_trace_turbo_jt) PrintF x
+#define TRACE(...)                                \
+  do {                                            \
+    if (FLAG_trace_turbo_jt) PrintF(__VA_ARGS__); \
+  } while (false)
 
 struct JumpThreadingState {
   bool forwarded;
@@ -31,19 +31,19 @@ struct JumpThreadingState {
     RpoNumber to_to = result[to.ToInt()];
     bool pop = true;
     if (to == from) {
-      TRACE(("  xx %d\n", from.ToInt()));
+      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()));
+      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()));
+      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()));
+      TRACE("  fw %d -> %d (forward)\n", from.ToInt(), to.ToInt());
       result[from.ToInt()] = to_to;  // forward the block.
       forwarded = true;
     }
@@ -70,36 +70,36 @@ bool JumpThreading::ComputeForwarding(Zone* local_zone,
     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()));
+      TRACE("jt [%d] B%d\n", static_cast<int>(stack.size()),
+            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"));
+          TRACE("  nop gap\n");
           continue;
         } else if (instr->IsSourcePosition()) {
           // skip source positions.
-          TRACE(("  src pos\n"));
+          TRACE("  src pos\n");
           continue;
         } else if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
           // can't skip instructions with flags continuations.
-          TRACE(("  flags\n"));
+          TRACE("  flags\n");
           fallthru = false;
         } else if (instr->IsNop()) {
           // skip nops.
-          TRACE(("  nop\n"));
+          TRACE("  nop\n");
           continue;
         } else if (instr->arch_opcode() == kArchJmp) {
           // try to forward the jump instruction.
-          TRACE(("  jmp\n"));
+          TRACE("  jmp\n");
           fw = code->InputRpo(instr, 0);
           fallthru = false;
         } else {
           // can't skip other instructions.
-          TRACE(("  other\n"));
+          TRACE("  other\n");
           fallthru = false;
         }
         break;
@@ -120,14 +120,12 @@ bool JumpThreading::ComputeForwarding(Zone* local_zone,
 
   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()));
+      TRACE("B%d ", i);
       int to = result[i].ToInt();
       if (i != to) {
-        TRACE(("-> B%d\n",
-               code->InstructionBlockAt(RpoNumber::FromInt(to))->id().ToInt()));
+        TRACE("-> B%d\n", to);
       } else {
-        TRACE(("\n"));
+        TRACE("\n");
       }
     }
   }
@@ -157,7 +155,7 @@ void JumpThreading::ApplyForwarding(ZoneVector<RpoNumber>& result,
       } else if (instr->arch_opcode() == kArchJmp) {
         if (skip[block_num]) {
           // Overwrite a redundant jump with a nop.
-          TRACE(("jt-fw nop @%d\n", i));
+          TRACE("jt-fw nop @%d\n", i);
           instr->OverwriteWithNop();
         }
         fallthru = false;  // jumps don't fall through to the next block.
index b801fec..fa74ee9 100644 (file)
@@ -17,13 +17,12 @@ 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,
+  static bool ComputeForwarding(Zone* local_zone, ZoneVector<RpoNumber>& result,
                                 InstructionSequence* code);
 
   // Rewrite the instructions to forward jumps and branches.
   // May also negate some branches.
-  static void ApplyForwarding(ZoneVector<BasicBlock::RpoNumber>& forwarding,
+  static void ApplyForwarding(ZoneVector<RpoNumber>& forwarding,
                               InstructionSequence* code);
 };
 
index abd0696..98f8f1c 100644 (file)
@@ -57,12 +57,10 @@ class LinkageHelper {
 
     // The target for JS function calls is the JSFunction object.
     MachineType target_type = kMachAnyTagged;
-    // Unoptimized code doesn't preserve the JSCallFunctionReg, so expect the
-    // closure on the stack.
-    LinkageLocation target_loc =
-        is_osr ? stackloc(Linkage::kJSFunctionCallClosureParamIndex -
-                          js_parameter_count)
-               : regloc(LinkageTraits::JSCallFunctionReg());
+    // TODO(titzer): When entering into an OSR function from unoptimized code,
+    // the JSFunction is not in a register, but it is on the stack in an
+    // unaddressable spill slot. We hack this in the OSR prologue. Fix.
+    LinkageLocation target_loc = regloc(LinkageTraits::JSCallFunctionReg());
     return new (zone) CallDescriptor(     // --
         CallDescriptor::kCallJSFunction,  // kind
         target_type,                      // target MachineType
@@ -138,11 +136,13 @@ class LinkageHelper {
   }
 
 
+  // TODO(all): Add support for return representations/locations to
+  // CallInterfaceDescriptor.
   // TODO(turbofan): cache call descriptors for code stub calls.
   static CallDescriptor* GetStubCallDescriptor(
       Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
       int stack_parameter_count, CallDescriptor::Flags flags,
-      Operator::Properties properties) {
+      Operator::Properties properties, MachineType return_type) {
     const int register_parameter_count =
         descriptor.GetEnvironmentParameterCount();
     const int js_parameter_count =
@@ -157,20 +157,23 @@ class LinkageHelper {
 
     // Add return location.
     AddReturnLocations(&locations);
-    types.AddReturn(kMachAnyTagged);
+    types.AddReturn(return_type);
 
     // Add parameters in registers and on the stack.
     for (int i = 0; i < js_parameter_count; i++) {
       if (i < register_parameter_count) {
         // The first parameters go in registers.
         Register reg = descriptor.GetEnvironmentParameterRegister(i);
+        Representation rep =
+            descriptor.GetEnvironmentParameterRepresentation(i);
         locations.AddParam(regloc(reg));
+        types.AddParam(reptyp(rep));
       } else {
         // The rest of the parameters go on the stack.
         int stack_slot = i - register_parameter_count - stack_parameter_count;
         locations.AddParam(stackloc(stack_slot));
+        types.AddParam(kMachAnyTagged);
       }
-      types.AddParam(kMachAnyTagged);
     }
     // Add context.
     locations.AddParam(regloc(LinkageTraits::ContextReg()));
@@ -232,6 +235,34 @@ class LinkageHelper {
     DCHECK_LT(i, 0);
     return LinkageLocation(i);
   }
+
+  static MachineType reptyp(Representation representation) {
+    switch (representation.kind()) {
+      case Representation::kInteger8:
+        return kMachInt8;
+      case Representation::kUInteger8:
+        return kMachUint8;
+      case Representation::kInteger16:
+        return kMachInt16;
+      case Representation::kUInteger16:
+        return kMachUint16;
+      case Representation::kInteger32:
+        return kMachInt32;
+      case Representation::kSmi:
+      case Representation::kTagged:
+      case Representation::kHeapObject:
+        return kMachAnyTagged;
+      case Representation::kDouble:
+        return kMachFloat64;
+      case Representation::kExternal:
+        return kMachPtr;
+      case Representation::kNone:
+      case Representation::kNumRepresentations:
+        break;
+    }
+    UNREACHABLE();
+    return kMachNone;
+  }
 };
 
 
@@ -254,7 +285,6 @@ LinkageLocation Linkage::GetOsrValueLocation(int index) const {
   }
 }
 
-
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index eedf9ed..72b7daf 100644 (file)
@@ -39,6 +39,14 @@ std::ostream& operator<<(std::ostream& os, const CallDescriptor& d) {
 
 
 CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
+  if (info->code_stub() != NULL) {
+    // Use the code stub interface descriptor.
+    CallInterfaceDescriptor descriptor =
+        info->code_stub()->GetCallInterfaceDescriptor();
+    return GetStubCallDescriptor(info->isolate(), zone, descriptor, 0,
+                                 CallDescriptor::kNoFlags,
+                                 Operator::kNoProperties);
+  }
   if (info->function() != NULL) {
     // If we already have the function literal, use the number of parameters
     // plus the receiver.
@@ -54,14 +62,6 @@ CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
                                1 + shared->internal_formal_parameter_count(),
                                CallDescriptor::kNoFlags);
   }
-  if (info->code_stub() != NULL) {
-    // Use the code stub interface descriptor.
-    CallInterfaceDescriptor descriptor =
-        info->code_stub()->GetCallInterfaceDescriptor();
-    return GetStubCallDescriptor(info->isolate(), zone, descriptor, 0,
-                                 CallDescriptor::kNoFlags,
-                                 Operator::kNoProperties);
-  }
   return NULL;  // TODO(titzer): ?
 }
 
@@ -114,22 +114,23 @@ bool Linkage::NeedsFrameState(Runtime::FunctionId function) {
     case Runtime::kNewArguments:
     case Runtime::kNewClosure:
     case Runtime::kNewFunctionContext:
+    case Runtime::kNewRestParamSlow:
     case Runtime::kPushBlockContext:
     case Runtime::kPushCatchContext:
     case Runtime::kReThrow:
     case Runtime::kSetProperty:  // TODO(jarin): Is it safe?
-    case Runtime::kStringCompare:
+    case Runtime::kStringCompareRT:
     case Runtime::kStringEquals:
     case Runtime::kToFastProperties:  // TODO(jarin): Is it safe?
     case Runtime::kTraceEnter:
     case Runtime::kTraceExit:
     case Runtime::kTypeof:
-    case Runtime::kNewRestParamSlow:
       return false;
     case Runtime::kInlineArguments:
     case Runtime::kInlineCallFunction:
     case Runtime::kInlineDateField:
-    case Runtime::kInlineOptimizedGetPrototype:
+    case Runtime::kInlineDeoptimizeNow:
+    case Runtime::kInlineGetPrototype:
     case Runtime::kInlineRegExpExec:
       return true;
     default:
@@ -174,7 +175,7 @@ CallDescriptor* Linkage::GetRuntimeCallDescriptor(
 CallDescriptor* Linkage::GetStubCallDescriptor(
     Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
     int stack_parameter_count, CallDescriptor::Flags flags,
-    Operator::Properties properties) {
+    Operator::Properties properties, MachineType return_type) {
   UNIMPLEMENTED();
   return NULL;
 }
index a3bdbf9..c1f3762 100644 (file)
@@ -56,11 +56,11 @@ class CallDescriptor FINAL : public ZoneObject {
   };
 
   enum Flag {
-    // TODO(jarin) kLazyDeoptimization and kNeedsFrameState should be unified.
     kNoFlags = 0u,
     kNeedsFrameState = 1u << 0,
     kPatchableCallSite = 1u << 1,
     kNeedsNopAfterCall = 1u << 2,
+    kHasExceptionHandler = 1u << 3,
     kPatchableCallSiteWithNop = kPatchableCallSite | kNeedsNopAfterCall
   };
   typedef base::Flags<Flag> Flags;
@@ -191,7 +191,8 @@ class Linkage : public ZoneObject {
   static CallDescriptor* GetStubCallDescriptor(
       Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
       int stack_parameter_count, CallDescriptor::Flags flags,
-      Operator::Properties properties = Operator::kNoProperties);
+      Operator::Properties properties = Operator::kNoProperties,
+      MachineType return_type = kMachAnyTagged);
 
   // Creates a call descriptor for simplified C calls that is appropriate
   // for the host platform. This simplified calling convention only supports
diff --git a/deps/v8/src/compiler/liveness-analyzer.cc b/deps/v8/src/compiler/liveness-analyzer.cc
new file mode 100644 (file)
index 0000000..301106d
--- /dev/null
@@ -0,0 +1,200 @@
+// Copyright 2014 the V8 project 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/liveness-analyzer.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/node.h"
+#include "src/compiler/node-matchers.h"
+#include "src/compiler/state-values-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+
+LivenessAnalyzer::LivenessAnalyzer(size_t local_count, Zone* zone)
+    : zone_(zone), blocks_(zone), local_count_(local_count), queue_(zone) {}
+
+
+void LivenessAnalyzer::Print(std::ostream& os) {
+  for (auto block : blocks_) {
+    block->Print(os);
+    os << std::endl;
+  }
+}
+
+
+LivenessAnalyzerBlock* LivenessAnalyzer::NewBlock() {
+  LivenessAnalyzerBlock* result =
+      new (zone()->New(sizeof(LivenessAnalyzerBlock)))
+          LivenessAnalyzerBlock(blocks_.size(), local_count_, zone());
+  blocks_.push_back(result);
+  return result;
+}
+
+
+LivenessAnalyzerBlock* LivenessAnalyzer::NewBlock(
+    LivenessAnalyzerBlock* predecessor) {
+  LivenessAnalyzerBlock* result = NewBlock();
+  result->AddPredecessor(predecessor);
+  return result;
+}
+
+
+void LivenessAnalyzer::Queue(LivenessAnalyzerBlock* block) {
+  if (!block->IsQueued()) {
+    block->SetQueued();
+    queue_.push(block);
+  }
+}
+
+
+void LivenessAnalyzer::Run(NonLiveFrameStateSlotReplacer* replacer) {
+  if (local_count_ == 0) {
+    // No local variables => nothing to do.
+    return;
+  }
+
+  // Put all blocks into the queue.
+  DCHECK(queue_.empty());
+  for (auto block : blocks_) {
+    Queue(block);
+  }
+
+  // Compute the fix-point.
+  BitVector working_area(static_cast<int>(local_count_), zone_);
+  while (!queue_.empty()) {
+    LivenessAnalyzerBlock* block = queue_.front();
+    queue_.pop();
+    block->Process(&working_area, nullptr);
+
+    for (auto i = block->pred_begin(); i != block->pred_end(); i++) {
+      if ((*i)->UpdateLive(&working_area)) {
+        Queue(*i);
+      }
+    }
+  }
+
+  // Update the frame states according to the liveness.
+  for (auto block : blocks_) {
+    block->Process(&working_area, replacer);
+  }
+}
+
+LivenessAnalyzerBlock::LivenessAnalyzerBlock(size_t id, size_t local_count,
+                                             Zone* zone)
+    : entries_(zone),
+      predecessors_(zone),
+      live_(local_count == 0 ? 1 : static_cast<int>(local_count), zone),
+      queued_(false),
+      id_(id) {}
+
+void LivenessAnalyzerBlock::Process(BitVector* result,
+                                    NonLiveFrameStateSlotReplacer* replacer) {
+  queued_ = false;
+
+  // Copy the bitvector to the target bit vector.
+  result->CopyFrom(live_);
+
+  for (auto i = entries_.rbegin(); i != entries_.rend(); i++) {
+    auto entry = *i;
+    switch (entry.kind()) {
+      case Entry::kLookup:
+        result->Add(entry.var());
+        break;
+      case Entry::kBind:
+        result->Remove(entry.var());
+        break;
+      case Entry::kCheckpoint:
+        if (replacer != nullptr) {
+          replacer->ClearNonLiveFrameStateSlots(entry.node(), result);
+        }
+        break;
+    }
+  }
+}
+
+
+bool LivenessAnalyzerBlock::UpdateLive(BitVector* working_area) {
+  return live_.UnionIsChanged(*working_area);
+}
+
+
+void NonLiveFrameStateSlotReplacer::ClearNonLiveFrameStateSlots(
+    Node* frame_state, BitVector* liveness) {
+  DCHECK_EQ(frame_state->opcode(), IrOpcode::kFrameState);
+  Node* locals_state = frame_state->InputAt(1);
+  DCHECK_EQ(locals_state->opcode(), IrOpcode::kStateValues);
+  int count = static_cast<int>(StateValuesAccess(locals_state).size());
+  DCHECK_EQ(count == 0 ? 1 : count, liveness->length());
+  for (int i = 0; i < count; i++) {
+    bool live = liveness->Contains(i) || permanently_live_.Contains(i);
+    if (!live || locals_state->InputAt(i) != replacement_node_) {
+      Node* new_values = ClearNonLiveStateValues(locals_state, liveness);
+      frame_state->ReplaceInput(1, new_values);
+      break;
+    }
+  }
+}
+
+
+Node* NonLiveFrameStateSlotReplacer::ClearNonLiveStateValues(
+    Node* values, BitVector* liveness) {
+  DCHECK(inputs_buffer_.empty());
+  for (StateValuesAccess::TypedNode node : StateValuesAccess(values)) {
+    // Index of the next variable is its furure index in the inputs buffer,
+    // i.e., the buffer's size.
+    int var = static_cast<int>(inputs_buffer_.size());
+    bool live = liveness->Contains(var) || permanently_live_.Contains(var);
+    inputs_buffer_.push_back(live ? node.node : replacement_node_);
+  }
+  Node* result = state_values_cache()->GetNodeForValues(
+      inputs_buffer_.empty() ? nullptr : &(inputs_buffer_.front()),
+      inputs_buffer_.size());
+  inputs_buffer_.clear();
+  return result;
+}
+
+
+void LivenessAnalyzerBlock::Print(std::ostream& os) {
+  os << "Block " << id();
+  bool first = true;
+  for (LivenessAnalyzerBlock* pred : predecessors_) {
+    if (!first) {
+      os << ", ";
+    } else {
+      os << "; predecessors: ";
+      first = false;
+    }
+    os << pred->id();
+  }
+  os << std::endl;
+
+  for (auto entry : entries_) {
+    os << "    ";
+    switch (entry.kind()) {
+      case Entry::kLookup:
+        os << "- Lookup " << entry.var() << std::endl;
+        break;
+      case Entry::kBind:
+        os << "- Bind " << entry.var() << std::endl;
+        break;
+      case Entry::kCheckpoint:
+        os << "- Checkpoint " << entry.node()->id() << std::endl;
+        break;
+    }
+  }
+
+  if (live_.length() > 0) {
+    os << "    Live set: ";
+    for (int i = 0; i < live_.length(); i++) {
+      os << (live_.Contains(i) ? "L" : ".");
+    }
+    os << std::endl;
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/deps/v8/src/compiler/liveness-analyzer.h b/deps/v8/src/compiler/liveness-analyzer.h
new file mode 100644 (file)
index 0000000..1e2f85b
--- /dev/null
@@ -0,0 +1,146 @@
+// 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.
+
+#ifndef V8_COMPILER_LIVENESS_ANAYZER_H_
+#define V8_COMPILER_LIVENESS_ANAYZER_H_
+
+#include "src/bit-vector.h"
+#include "src/compiler/node.h"
+#include "src/zone-containers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class LivenessAnalyzerBlock;
+class Node;
+class StateValuesCache;
+
+
+class NonLiveFrameStateSlotReplacer {
+ public:
+  void ClearNonLiveFrameStateSlots(Node* frame_state, BitVector* liveness);
+  NonLiveFrameStateSlotReplacer(StateValuesCache* state_values_cache,
+                                Node* replacement, size_t local_count,
+                                Zone* local_zone)
+      : replacement_node_(replacement),
+        state_values_cache_(state_values_cache),
+        local_zone_(local_zone),
+        permanently_live_(local_count == 0 ? 1 : static_cast<int>(local_count),
+                          local_zone),
+        inputs_buffer_(local_zone) {}
+
+  void MarkPermanentlyLive(int var) { permanently_live_.Add(var); }
+
+ private:
+  Node* ClearNonLiveStateValues(Node* frame_state, BitVector* liveness);
+
+  StateValuesCache* state_values_cache() { return state_values_cache_; }
+  Zone* local_zone() { return local_zone_; }
+
+  // Node that replaces dead values.
+  Node* replacement_node_;
+  // Reference to state values cache so that we can create state values
+  // nodes.
+  StateValuesCache* state_values_cache_;
+
+  Zone* local_zone_;
+  BitVector permanently_live_;
+  NodeVector inputs_buffer_;
+};
+
+
+class LivenessAnalyzer {
+ public:
+  LivenessAnalyzer(size_t local_count, Zone* zone);
+
+  LivenessAnalyzerBlock* NewBlock();
+  LivenessAnalyzerBlock* NewBlock(LivenessAnalyzerBlock* predecessor);
+
+  void Run(NonLiveFrameStateSlotReplacer* relaxer);
+
+  Zone* zone() { return zone_; }
+
+  void Print(std::ostream& os);
+
+  size_t local_count() { return local_count_; }
+
+ private:
+  void Queue(LivenessAnalyzerBlock* block);
+
+  Zone* zone_;
+  ZoneDeque<LivenessAnalyzerBlock*> blocks_;
+  size_t local_count_;
+
+  ZoneQueue<LivenessAnalyzerBlock*> queue_;
+};
+
+
+class LivenessAnalyzerBlock {
+ public:
+  friend class LivenessAnalyzer;
+
+  void Lookup(int var) { entries_.push_back(Entry(Entry::kLookup, var)); }
+  void Bind(int var) { entries_.push_back(Entry(Entry::kBind, var)); }
+  void Checkpoint(Node* node) { entries_.push_back(Entry(node)); }
+  void AddPredecessor(LivenessAnalyzerBlock* b) { predecessors_.push_back(b); }
+
+ private:
+  class Entry {
+   public:
+    enum Kind { kBind, kLookup, kCheckpoint };
+
+    Kind kind() const { return kind_; }
+    Node* node() const {
+      DCHECK(kind() == kCheckpoint);
+      return node_;
+    }
+    int var() const {
+      DCHECK(kind() != kCheckpoint);
+      return var_;
+    }
+
+    explicit Entry(Node* node) : kind_(kCheckpoint), var_(-1), node_(node) {}
+    Entry(Kind kind, int var) : kind_(kind), var_(var), node_(nullptr) {
+      DCHECK(kind != kCheckpoint);
+    }
+
+   private:
+    Kind kind_;
+    int var_;
+    Node* node_;
+  };
+
+  LivenessAnalyzerBlock(size_t id, size_t local_count, Zone* zone);
+  void Process(BitVector* result, NonLiveFrameStateSlotReplacer* relaxer);
+  bool UpdateLive(BitVector* working_area);
+
+  void SetQueued() { queued_ = true; }
+  bool IsQueued() { return queued_; }
+
+  ZoneDeque<LivenessAnalyzerBlock*>::const_iterator pred_begin() {
+    return predecessors_.begin();
+  }
+  ZoneDeque<LivenessAnalyzerBlock*>::const_iterator pred_end() {
+    return predecessors_.end();
+  }
+
+  size_t id() { return id_; }
+  void Print(std::ostream& os);
+
+  ZoneDeque<Entry> entries_;
+  ZoneDeque<LivenessAnalyzerBlock*> predecessors_;
+
+  BitVector live_;
+  bool queued_;
+
+  size_t id_;
+};
+
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_AST_GRAPH_BUILDER_H_
index 8f91d49..ba0b7a1 100644 (file)
@@ -160,29 +160,8 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
       }
       return ReduceWord32Shifts(node);
     }
-    case IrOpcode::kWord32Sar: {
-      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().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::kWord32Sar:
+      return ReduceWord32Sar(node);
     case IrOpcode::kWord32Ror: {
       Int32BinopMatcher m(node);
       if (m.right().Is(0)) return Replace(m.left().node());  // x ror 0 => x
@@ -454,6 +433,10 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
       if (m.IsChangeFloat32ToFloat64()) return Replace(m.node()->InputAt(0));
       break;
     }
+    case IrOpcode::kFloat64InsertLowWord32:
+      return ReduceFloat64InsertLowWord32(node);
+    case IrOpcode::kFloat64InsertHighWord32:
+      return ReduceFloat64InsertHighWord32(node);
     case IrOpcode::kStore:
       return ReduceStore(node);
     default:
@@ -471,6 +454,25 @@ Reduction MachineOperatorReducer::ReduceInt32Add(Node* node) {
     return ReplaceUint32(bit_cast<uint32_t>(m.left().Value()) +
                          bit_cast<uint32_t>(m.right().Value()));
   }
+  if (m.left().IsInt32Sub()) {
+    Int32BinopMatcher mleft(m.left().node());
+    if (mleft.left().Is(0)) {  // (0 - x) + y => y - x
+      node->set_op(machine()->Int32Sub());
+      node->ReplaceInput(0, m.right().node());
+      node->ReplaceInput(1, mleft.right().node());
+      Reduction const reduction = ReduceInt32Sub(node);
+      return reduction.Changed() ? reduction : Changed(node);
+    }
+  }
+  if (m.right().IsInt32Sub()) {
+    Int32BinopMatcher mright(m.right().node());
+    if (mright.left().Is(0)) {  // y + (0 - x) => y - x
+      node->set_op(machine()->Int32Sub());
+      node->ReplaceInput(1, mright.right().node());
+      Reduction const reduction = ReduceInt32Sub(node);
+      return reduction.Changed() ? reduction : Changed(node);
+    }
+  }
   return NoChange();
 }
 
@@ -784,11 +786,48 @@ Reduction MachineOperatorReducer::ReduceWord32Shl(Node* node) {
 }
 
 
+Reduction MachineOperatorReducer::ReduceWord32Sar(Node* node) {
+  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().IsWord32Shl()) {
+    Int32BinopMatcher mleft(m.left().node());
+    if (mleft.left().IsComparison()) {
+      if (m.right().Is(31) && mleft.right().Is(31)) {
+        // Comparison << 31 >> 31 => 0 - Comparison
+        node->set_op(machine()->Int32Sub());
+        node->ReplaceInput(0, Int32Constant(0));
+        node->ReplaceInput(1, mleft.left().node());
+        Reduction const reduction = ReduceInt32Sub(node);
+        return reduction.Changed() ? reduction : Changed(node);
+      }
+    } else 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);
+}
+
+
 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.left().IsComparison() && m.right().Is(1)) {       // CMP & 1 => CMP
+    return Replace(m.left().node());
+  }
   if (m.IsFoldable()) {                                   // K & K  => K
     return ReplaceInt32(m.left().Value() & m.right().Value());
   }
@@ -871,6 +910,12 @@ Reduction MachineOperatorReducer::ReduceWord32And(Node* node) {
           return reduction.Changed() ? reduction : Changed(node);
         }
       }
+    } else if (m.left().IsInt32Mul()) {
+      Int32BinopMatcher mleft(m.left().node());
+      if (mleft.right().IsMultipleOf(-mask)) {
+        // (x * (K << L)) & (-1 << L) => x * (K << L)
+        return Replace(mleft.node());
+      }
     }
   }
   return NoChange();
@@ -934,6 +979,32 @@ Reduction MachineOperatorReducer::ReduceWord32Or(Node* node) {
 }
 
 
+Reduction MachineOperatorReducer::ReduceFloat64InsertLowWord32(Node* node) {
+  DCHECK_EQ(IrOpcode::kFloat64InsertLowWord32, node->opcode());
+  Float64Matcher mlhs(node->InputAt(0));
+  Uint32Matcher mrhs(node->InputAt(1));
+  if (mlhs.HasValue() && mrhs.HasValue()) {
+    return ReplaceFloat64(bit_cast<double>(
+        (bit_cast<uint64_t>(mlhs.Value()) & V8_UINT64_C(0xFFFFFFFF00000000)) |
+        mrhs.Value()));
+  }
+  return NoChange();
+}
+
+
+Reduction MachineOperatorReducer::ReduceFloat64InsertHighWord32(Node* node) {
+  DCHECK_EQ(IrOpcode::kFloat64InsertHighWord32, node->opcode());
+  Float64Matcher mlhs(node->InputAt(0));
+  Uint32Matcher mrhs(node->InputAt(1));
+  if (mlhs.HasValue() && mrhs.HasValue()) {
+    return ReplaceFloat64(bit_cast<double>(
+        (bit_cast<uint64_t>(mlhs.Value()) & V8_UINT64_C(0xFFFFFFFF)) |
+        (static_cast<uint64_t>(mrhs.Value()) << 32)));
+  }
+  return NoChange();
+}
+
+
 CommonOperatorBuilder* MachineOperatorReducer::common() const {
   return jsgraph()->common();
 }
index 9e02ffd..7c41f14 100644 (file)
@@ -75,8 +75,11 @@ class MachineOperatorReducer FINAL : public Reducer {
   Reduction ReduceProjection(size_t index, Node* node);
   Reduction ReduceWord32Shifts(Node* node);
   Reduction ReduceWord32Shl(Node* node);
+  Reduction ReduceWord32Sar(Node* node);
   Reduction ReduceWord32And(Node* node);
   Reduction ReduceWord32Or(Node* node);
+  Reduction ReduceFloat64InsertLowWord32(Node* node);
+  Reduction ReduceFloat64InsertHighWord32(Node* node);
 
   Graph* graph() const;
   JSGraph* jsgraph() const { return jsgraph_; }
index 2522a8e..fa8979c 100644 (file)
@@ -73,6 +73,7 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
   V(Word32Sar, Operator::kNoProperties, 2, 0, 1)                              \
   V(Word32Ror, Operator::kNoProperties, 2, 0, 1)                              \
   V(Word32Equal, Operator::kCommutative, 2, 0, 1)                             \
+  V(Word32Clz, Operator::kNoProperties, 1, 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)      \
@@ -123,13 +124,18 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
   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(Float64RoundDown, 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(Float64ExtractLowWord32, Operator::kNoProperties, 1, 0, 1)                \
+  V(Float64ExtractHighWord32, Operator::kNoProperties, 1, 0, 1)               \
+  V(Float64InsertLowWord32, Operator::kNoProperties, 2, 0, 1)                 \
+  V(Float64InsertHighWord32, Operator::kNoProperties, 2, 0, 1)                \
+  V(Float64Max, Operator::kNoProperties, 2, 0, 1)                             \
+  V(Float64Min, Operator::kNoProperties, 2, 0, 1)                             \
   V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1)
 
 
index 42f3130..d428562 100644 (file)
@@ -74,13 +74,14 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
   // 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
+    kFloat64Max = 1u << 0,
+    kFloat64Min = 1u << 1,
+    kFloat64RoundDown = 1u << 2,
+    kFloat64RoundTruncate = 1u << 3,
+    kFloat64RoundTiesAway = 1u << 4,
+    kInt32DivIsSafe = 1u << 5,
+    kUint32DivIsSafe = 1u << 6,
+    kWord32ShiftIsSafe = 1u << 7
   };
   typedef base::Flags<Flag, unsigned> Flags;
 
@@ -95,6 +96,7 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
   const Operator* Word32Sar();
   const Operator* Word32Ror();
   const Operator* Word32Equal();
+  const Operator* Word32Clz();
   bool Word32ShiftIsSafe() const { return flags_ & kWord32ShiftIsSafe; }
 
   const Operator* Word64And();
@@ -167,16 +169,26 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
   const Operator* Float64LessThan();
   const Operator* Float64LessThanOrEqual();
 
+  // Floating point min/max complying to IEEE 754.
+  const Operator* Float64Max();
+  const Operator* Float64Min();
+  bool HasFloat64Max() { return flags_ & kFloat64Max; }
+  bool HasFloat64Min() { return flags_ & kFloat64Min; }
+
   // Floating point rounding.
-  const Operator* Float64Floor();
-  const Operator* Float64Ceil();
+  const Operator* Float64RoundDown();
   const Operator* Float64RoundTruncate();
   const Operator* Float64RoundTiesAway();
-  bool HasFloat64Floor() { return flags_ & kFloat64Floor; }
-  bool HasFloat64Ceil() { return flags_ & kFloat64Ceil; }
+  bool HasFloat64RoundDown() { return flags_ & kFloat64RoundDown; }
   bool HasFloat64RoundTruncate() { return flags_ & kFloat64RoundTruncate; }
   bool HasFloat64RoundTiesAway() { return flags_ & kFloat64RoundTiesAway; }
 
+  // Floating point bit representation.
+  const Operator* Float64ExtractLowWord32();
+  const Operator* Float64ExtractHighWord32();
+  const Operator* Float64InsertLowWord32();
+  const Operator* Float64InsertHighWord32();
+
   // load [base + index]
   const Operator* Load(LoadRepresentation rep);
 
@@ -226,10 +238,10 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
 #undef PSEUDO_OP_LIST
 
  private:
-  Zone* zone_;
-  const MachineOperatorGlobalCache& cache_;
-  const MachineType word_;
-  const Flags flags_;
+  Zone* const zone_;
+  MachineOperatorGlobalCache const& cache_;
+  MachineType const word_;
+  Flags const flags_;
 
   DISALLOW_COPY_AND_ASSIGN(MachineOperatorBuilder);
 };
index 58c4581..48ef033 100644 (file)
@@ -39,11 +39,11 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
   MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
       : InstructionOperandConverter(gen, instr) {}
 
-  FloatRegister OutputSingleRegister(int index = 0) {
+  FloatRegister OutputSingleRegister(size_t index = 0) {
     return ToSingleRegister(instr_->OutputAt(index));
   }
 
-  FloatRegister InputSingleRegister(int index) {
+  FloatRegister InputSingleRegister(size_t index) {
     return ToSingleRegister(instr_->InputAt(index));
   }
 
@@ -53,7 +53,7 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
     return ToDoubleRegister(op);
   }
 
-  Operand InputImmediate(int index) {
+  Operand InputImmediate(size_t index) {
     Constant constant = ToConstant(instr_->InputAt(index));
     switch (constant.type()) {
       case Constant::kInt32:
@@ -78,7 +78,7 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
     return Operand(zero_reg);
   }
 
-  Operand InputOperand(int index) {
+  Operand InputOperand(size_t index) {
     InstructionOperand* op = instr_->InputAt(index);
     if (op->IsRegister()) {
       return Operand(ToRegister(op));
@@ -86,8 +86,8 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
     return InputImmediate(index);
   }
 
-  MemOperand MemoryOperand(int* first_index) {
-    const int index = *first_index;
+  MemOperand MemoryOperand(size_t* first_index) {
+    const size_t index = *first_index;
     switch (AddressingModeField::decode(instr_->opcode())) {
       case kMode_None:
         break;
@@ -102,7 +102,7 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
     return MemOperand(no_reg);
   }
 
-  MemOperand MemoryOperand(int index = 0) { return MemoryOperand(&index); }
+  MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); }
 
   MemOperand ToMemOperand(InstructionOperand* op) const {
     DCHECK(op != NULL);
@@ -116,7 +116,7 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
 };
 
 
-static inline bool HasRegisterInput(Instruction* instr, int index) {
+static inline bool HasRegisterInput(Instruction* instr, size_t index) {
   return instr->InputAt(index)->IsRegister();
 }
 
@@ -408,7 +408,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         __ addiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
         __ Call(at);
       }
-      AddSafepointAndDeopt(instr);
+      RecordCallPosition(instr);
       break;
     }
     case kArchCallJSFunction: {
@@ -422,7 +422,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
 
       __ lw(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
       __ Call(at);
-      AddSafepointAndDeopt(instr);
+      RecordCallPosition(instr);
       break;
     }
     case kArchJmp:
@@ -437,6 +437,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArchNop:
       // don't emit code for nops.
       break;
+    case kArchDeoptimize: {
+      int deopt_state_id =
+          BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
+      AssembleDeoptimizerCall(deopt_state_id, Deoptimizer::EAGER);
+      break;
+    }
     case kArchRet:
       AssembleReturn();
       break;
@@ -490,6 +496,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kMipsXor:
       __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
       break;
+    case kMipsClz:
+      __ Clz(i.OutputRegister(), i.InputRegister(0));
+      break;
     case kMipsShl:
       if (instr->InputAt(1)->IsRegister()) {
         __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
@@ -567,18 +576,18 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ MovFromFloatResult(i.OutputDoubleRegister());
       break;
     }
-    case kMipsFloat64Floor: {
+    case kMipsFloat64RoundDown: {
       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 kMipsFloat64RoundUp: {
+      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil_l_d, Ceil);
+      break;
+    }
     case kMipsSqrtD: {
       __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       break;
@@ -615,6 +624,18 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
       break;
     }
+    case kMipsFloat64ExtractLowWord32:
+      __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0));
+      break;
+    case kMipsFloat64ExtractHighWord32:
+      __ FmoveHigh(i.OutputRegister(), i.InputDoubleRegister(0));
+      break;
+    case kMipsFloat64InsertLowWord32:
+      __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1));
+      break;
+    case kMipsFloat64InsertHighWord32:
+      __ FmoveHigh(i.OutputDoubleRegister(), i.InputRegister(1));
+      break;
     // ... more basic instructions ...
 
     case kMipsLbu:
@@ -646,7 +667,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       break;
     }
     case kMipsSwc1: {
-      int index = 0;
+      size_t index = 0;
       MemOperand operand = i.MemoryOperand(&index);
       __ swc1(i.InputSingleRegister(index), operand);
       break;
@@ -803,7 +824,7 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
 }
 
 
-void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+void CodeGenerator::AssembleArchJump(RpoNumber target) {
   if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
 }
 
@@ -917,9 +938,10 @@ void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
 }
 
 
-void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
+void CodeGenerator::AssembleDeoptimizerCall(
+    int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
-      isolate(), deoptimization_id, Deoptimizer::LAZY);
+      isolate(), deoptimization_id, bailout_type);
   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
 }
 
@@ -962,6 +984,8 @@ void CodeGenerator::AssemblePrologue() {
     // remaining stack slots.
     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
     osr_pc_offset_ = __ pc_offset();
+    // TODO(titzer): cannot address target function == local #-1
+    __ lw(a1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
     DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
     stack_slots -= frame()->GetOsrStackSlotCount();
   }
@@ -1150,9 +1174,9 @@ void CodeGenerator::AssembleSwap(InstructionOperand* source,
     Register temp_0 = kScratchReg;
     FPURegister temp_1 = kScratchDoubleReg;
     MemOperand src0 = g.ToMemOperand(source);
-    MemOperand src1(src0.rm(), src0.offset() + kPointerSize);
+    MemOperand src1(src0.rm(), src0.offset() + kIntSize);
     MemOperand dst0 = g.ToMemOperand(destination);
-    MemOperand dst1(dst0.rm(), dst0.offset() + kPointerSize);
+    MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize);
     __ 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);
index 3aa508f..82639ba 100644 (file)
@@ -26,6 +26,7 @@ namespace compiler {
   V(MipsAnd)                       \
   V(MipsOr)                        \
   V(MipsXor)                       \
+  V(MipsClz)                       \
   V(MipsShl)                       \
   V(MipsShr)                       \
   V(MipsSar)                       \
@@ -40,9 +41,9 @@ namespace compiler {
   V(MipsDivD)                      \
   V(MipsModD)                      \
   V(MipsSqrtD)                     \
-  V(MipsFloat64Floor)              \
-  V(MipsFloat64Ceil)               \
+  V(MipsFloat64RoundDown)          \
   V(MipsFloat64RoundTruncate)      \
+  V(MipsFloat64RoundUp)            \
   V(MipsCvtSD)                     \
   V(MipsCvtDS)                     \
   V(MipsTruncWD)                   \
@@ -61,6 +62,10 @@ namespace compiler {
   V(MipsSwc1)                      \
   V(MipsLdc1)                      \
   V(MipsSdc1)                      \
+  V(MipsFloat64ExtractLowWord32)   \
+  V(MipsFloat64ExtractHighWord32)  \
+  V(MipsFloat64InsertLowWord32)    \
+  V(MipsFloat64InsertHighWord32)   \
   V(MipsPush)                      \
   V(MipsStoreToStackSlot)          \
   V(MipsStackClaim)                \
index d723453..0e8df3e 100644 (file)
@@ -114,9 +114,8 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
   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();
+  selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
+                 inputs);
 }
 
 
@@ -265,6 +264,12 @@ void InstructionSelector::VisitWord32Ror(Node* node) {
 }
 
 
+void InstructionSelector::VisitWord32Clz(Node* node) {
+  MipsOperandGenerator g(this);
+  Emit(kMipsClz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitInt32Add(Node* node) {
   MipsOperandGenerator g(this);
 
@@ -402,6 +407,20 @@ void InstructionSelector::VisitFloat64Add(Node* node) {
 
 
 void InstructionSelector::VisitFloat64Sub(Node* node) {
+  MipsOperandGenerator g(this);
+  Float64BinopMatcher m(node);
+  if (m.left().IsMinusZero() && m.right().IsFloat64RoundDown() &&
+      CanCover(m.node(), m.right().node())) {
+    if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
+        CanCover(m.right().node(), m.right().InputAt(0))) {
+      Float64BinopMatcher mright0(m.right().InputAt(0));
+      if (mright0.left().IsMinusZero()) {
+        Emit(kMipsFloat64RoundUp, g.DefineAsRegister(node),
+             g.UseRegister(mright0.right().node()));
+        return;
+      }
+    }
+  }
   VisitRRR(this, kMipsSubD, node);
 }
 
@@ -423,19 +442,20 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64Max(Node* node) { UNREACHABLE(); }
+
+
+void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); }
+
+
 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::VisitFloat64RoundDown(Node* node) {
+  VisitRR(this, kMipsFloat64RoundDown, node);
 }
 
 
@@ -449,7 +469,7 @@ void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
 }
 
 
-void InstructionSelector::VisitCall(Node* node) {
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
   MipsOperandGenerator g(this);
   const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
 
@@ -476,6 +496,13 @@ void InstructionSelector::VisitCall(Node* node) {
     slot--;
   }
 
+  // Pass label of exception handler block.
+  CallDescriptor::Flags flags = descriptor->flags();
+  if (handler != nullptr) {
+    flags |= CallDescriptor::kHasExceptionHandler;
+    buffer.instruction_args.push_back(g.Label(handler));
+  }
+
   // Select the appropriate opcode based on the call type.
   InstructionCode opcode;
   switch (descriptor->kind()) {
@@ -490,7 +517,7 @@ void InstructionSelector::VisitCall(Node* node) {
       UNREACHABLE();
       return;
   }
-  opcode |= MiscField::encode(descriptor->flags());
+  opcode |= MiscField::encode(flags);
 
   // Emit the call instruction.
   InstructionOperand* first_output =
@@ -600,8 +627,7 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
   opcode = cont->Encode(opcode);
   if (cont->IsBranch()) {
     selector->Emit(opcode, g.NoOutput(), left, right,
-                   g.Label(cont->true_block()),
-                   g.Label(cont->false_block()))->MarkAsControl();
+                   g.Label(cont->true_block()), g.Label(cont->false_block()));
   } else {
     DCHECK(cont->IsSet());
     // TODO(plind): Revisit and test this path.
@@ -730,8 +756,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
   InstructionOperand const value_operand = g.UseRegister(value);
   if (cont->IsBranch()) {
     selector->Emit(opcode, g.NoOutput(), value_operand, g.TempImmediate(0),
-                   g.Label(cont->true_block()),
-                   g.Label(cont->false_block()))->MarkAsControl();
+                   g.Label(cont->true_block()), g.Label(cont->false_block()));
   } else {
     selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
                    g.TempImmediate(0));
@@ -746,63 +771,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
 }
 
 
-void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
-                                      BasicBlock** case_branches,
-                                      int32_t* case_values, size_t case_count,
-                                      int32_t min_value, int32_t max_value) {
+void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
   MipsOperandGenerator g(this);
   InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
-  InstructionOperand default_operand = g.Label(default_branch);
-
-  // Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value}
-  // is 2^31-1, so don't assume that it's non-zero below.
-  size_t value_range =
-      1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
-
-  // Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
-  // instruction.
-  size_t table_space_cost = 9 + value_range;
-  size_t table_time_cost = 9;
-  size_t lookup_space_cost = 2 + 2 * case_count;
-  size_t lookup_time_cost = case_count;
-  if (case_count > 0 &&
+
+  // Emit either ArchTableSwitch or ArchLookupSwitch.
+  size_t table_space_cost = 9 + sw.value_range;
+  size_t table_time_cost = 3;
+  size_t lookup_space_cost = 2 + 2 * sw.case_count;
+  size_t lookup_time_cost = sw.case_count;
+  if (sw.case_count > 0 &&
       table_space_cost + 3 * table_time_cost <=
           lookup_space_cost + 3 * lookup_time_cost &&
-      min_value > std::numeric_limits<int32_t>::min()) {
+      sw.min_value > std::numeric_limits<int32_t>::min()) {
     InstructionOperand index_operand = value_operand;
-    if (min_value) {
+    if (sw.min_value) {
       index_operand = g.TempRegister();
-      Emit(kMipsSub, index_operand, value_operand, g.TempImmediate(min_value));
-    }
-    size_t input_count = 2 + value_range;
-    auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
-    inputs[0] = index_operand;
-    std::fill(&inputs[1], &inputs[input_count], default_operand);
-    for (size_t index = 0; index < case_count; ++index) {
-      size_t value = case_values[index] - min_value;
-      BasicBlock* branch = case_branches[index];
-      DCHECK_LE(0u, value);
-      DCHECK_LT(value + 2, input_count);
-      inputs[value + 2] = g.Label(branch);
+      Emit(kMipsSub, index_operand, value_operand,
+           g.TempImmediate(sw.min_value));
     }
-    Emit(kArchTableSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
-        ->MarkAsControl();
-    return;
+    // Generate a table lookup.
+    return EmitTableSwitch(sw, index_operand);
   }
 
   // Generate a sequence of conditional jumps.
-  size_t input_count = 2 + case_count * 2;
-  auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
-  inputs[0] = value_operand;
-  inputs[1] = default_operand;
-  for (size_t index = 0; index < case_count; ++index) {
-    int32_t value = case_values[index];
-    BasicBlock* branch = case_branches[index];
-    inputs[index * 2 + 2 + 0] = g.TempImmediate(value);
-    inputs[index * 2 + 2 + 1] = g.Label(branch);
-  }
-  Emit(kArchLookupSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
-      ->MarkAsControl();
+  return EmitLookupSwitch(sw, value_operand);
 }
 
 
@@ -878,12 +871,43 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
+  MipsOperandGenerator g(this);
+  Emit(kMipsFloat64ExtractLowWord32, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
+  MipsOperandGenerator g(this);
+  Emit(kMipsFloat64ExtractHighWord32, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
+  MipsOperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Emit(kMipsFloat64InsertLowWord32, g.DefineSameAsFirst(node),
+       g.UseRegister(left), g.UseRegister(right));
+}
+
+
+void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
+  MipsOperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Emit(kMipsFloat64InsertHighWord32, g.DefineSameAsFirst(node),
+       g.UseRegister(left), g.UseRegister(right));
+}
+
+
 // static
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
   if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
-    return MachineOperatorBuilder::kFloat64Floor |
-           MachineOperatorBuilder::kFloat64Ceil |
+    return MachineOperatorBuilder::kFloat64RoundDown |
            MachineOperatorBuilder::kFloat64RoundTruncate;
   }
   return MachineOperatorBuilder::kNoFlags;
index cbb59d3..9480b73 100644 (file)
@@ -51,9 +51,10 @@ CallDescriptor* Linkage::GetRuntimeCallDescriptor(
 CallDescriptor* Linkage::GetStubCallDescriptor(
     Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
     int stack_parameter_count, CallDescriptor::Flags flags,
-    Operator::Properties properties) {
+    Operator::Properties properties, MachineType return_type) {
   return LH::GetStubCallDescriptor(isolate, zone, descriptor,
-                                   stack_parameter_count, flags, properties);
+                                   stack_parameter_count, flags, properties,
+                                   return_type);
 }
 
 
index 60e016f..f620487 100644 (file)
@@ -38,11 +38,11 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
   MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
       : InstructionOperandConverter(gen, instr) {}
 
-  FloatRegister OutputSingleRegister(int index = 0) {
+  FloatRegister OutputSingleRegister(size_t index = 0) {
     return ToSingleRegister(instr_->OutputAt(index));
   }
 
-  FloatRegister InputSingleRegister(int index) {
+  FloatRegister InputSingleRegister(size_t index) {
     return ToSingleRegister(instr_->InputAt(index));
   }
 
@@ -52,7 +52,7 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
     return ToDoubleRegister(op);
   }
 
-  Operand InputImmediate(int index) {
+  Operand InputImmediate(size_t index) {
     Constant constant = ToConstant(instr_->InputAt(index));
     switch (constant.type()) {
       case Constant::kInt32:
@@ -78,7 +78,7 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
     return Operand(zero_reg);
   }
 
-  Operand InputOperand(int index) {
+  Operand InputOperand(size_t index) {
     InstructionOperand* op = instr_->InputAt(index);
     if (op->IsRegister()) {
       return Operand(ToRegister(op));
@@ -86,8 +86,8 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
     return InputImmediate(index);
   }
 
-  MemOperand MemoryOperand(int* first_index) {
-    const int index = *first_index;
+  MemOperand MemoryOperand(size_t* first_index) {
+    const size_t index = *first_index;
     switch (AddressingModeField::decode(instr_->opcode())) {
       case kMode_None:
         break;
@@ -102,7 +102,7 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
     return MemOperand(no_reg);
   }
 
-  MemOperand MemoryOperand(int index = 0) { return MemoryOperand(&index); }
+  MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); }
 
   MemOperand ToMemOperand(InstructionOperand* op) const {
     DCHECK(op != NULL);
@@ -116,7 +116,7 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
 };
 
 
-static inline bool HasRegisterInput(Instruction* instr, int index) {
+static inline bool HasRegisterInput(Instruction* instr, size_t index) {
   return instr->InputAt(index)->IsRegister();
 }
 
@@ -408,7 +408,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         __ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
         __ Call(at);
       }
-      AddSafepointAndDeopt(instr);
+      RecordCallPosition(instr);
       break;
     }
     case kArchCallJSFunction: {
@@ -422,7 +422,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
 
       __ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
       __ Call(at);
-      AddSafepointAndDeopt(instr);
+      RecordCallPosition(instr);
       break;
     }
     case kArchJmp:
@@ -437,6 +437,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArchNop:
       // don't emit code for nops.
       break;
+    case kArchDeoptimize: {
+      int deopt_state_id =
+          BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
+      AssembleDeoptimizerCall(deopt_state_id, Deoptimizer::EAGER);
+      break;
+    }
     case kArchRet:
       AssembleReturn();
       break;
@@ -505,6 +511,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kMips64Xor:
       __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
       break;
+    case kMips64Clz:
+      __ Clz(i.OutputRegister(), i.InputRegister(0));
+      break;
     case kMips64Shl:
       if (instr->InputAt(1)->IsRegister()) {
         __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
@@ -580,11 +589,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ 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:
@@ -631,18 +638,18 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ MovFromFloatResult(i.OutputDoubleRegister());
       break;
     }
-    case kMips64Float64Floor: {
+    case kMips64Float64RoundDown: {
       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 kMips64Float64RoundUp: {
+      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil_l_d, Ceil);
+      break;
+    }
     case kMips64SqrtD: {
       __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       break;
@@ -679,6 +686,18 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
       break;
     }
+    case kMips64Float64ExtractLowWord32:
+      __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0));
+      break;
+    case kMips64Float64ExtractHighWord32:
+      __ FmoveHigh(i.OutputRegister(), i.InputDoubleRegister(0));
+      break;
+    case kMips64Float64InsertLowWord32:
+      __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1));
+      break;
+    case kMips64Float64InsertHighWord32:
+      __ FmoveHigh(i.OutputDoubleRegister(), i.InputRegister(1));
+      break;
     // ... more basic instructions ...
 
     case kMips64Lbu:
@@ -716,7 +735,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       break;
     }
     case kMips64Swc1: {
-      int index = 0;
+      size_t index = 0;
       MemOperand operand = i.MemoryOperand(&index);
       __ swc1(i.InputSingleRegister(index), operand);
       break;
@@ -808,25 +827,13 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
   // 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
+  // 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() == kMips64Tst) {
     cc = FlagsConditionToConditionTst(branch->condition);
     __ And(at, i.InputRegister(0), i.InputOperand(1));
     __ Branch(tlabel, cc, at, Operand(zero_reg));
-  } else if (instr->arch_opcode() == kMips64Tst32) {
-    cc = FlagsConditionToConditionTst(branch->condition);
-    // 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) {
     cc = FlagsConditionToConditionOvf(branch->condition);
@@ -839,42 +846,6 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
     __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
 
     if (!branch->fallthru) __ Branch(flabel);  // no fallthru to flabel.
-
-  } else if (instr->arch_opcode() == kMips64Cmp32) {
-    cc = FlagsConditionToConditionCmp(branch->condition);
-
-    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.
@@ -917,7 +888,7 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
 }
 
 
-void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+void CodeGenerator::AssembleArchJump(RpoNumber target) {
   if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
 }
 
@@ -948,14 +919,6 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
     __ 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) {
-    cc = FlagsConditionToConditionTst(condition);
-    // 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) {
     cc = FlagsConditionToConditionOvf(condition);
@@ -969,42 +932,6 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
     cc = FlagsConditionToConditionCmp(condition);
     __ 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);
-    cc = FlagsConditionToConditionCmp(condition);
-
-    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);
@@ -1077,9 +1004,10 @@ void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
 }
 
 
-void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
+void CodeGenerator::AssembleDeoptimizerCall(
+    int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
-      isolate(), deoptimization_id, Deoptimizer::LAZY);
+      isolate(), deoptimization_id, bailout_type);
   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
 }
 
@@ -1122,6 +1050,8 @@ void CodeGenerator::AssemblePrologue() {
     // remaining stack slots.
     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
     osr_pc_offset_ = __ pc_offset();
+    // TODO(titzer): cannot address target function == local #-1
+    __ ld(a1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
     DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
     stack_slots -= frame()->GetOsrStackSlotCount();
   }
@@ -1310,9 +1240,9 @@ void CodeGenerator::AssembleSwap(InstructionOperand* source,
     Register temp_0 = kScratchReg;
     FPURegister temp_1 = kScratchDoubleReg;
     MemOperand src0 = g.ToMemOperand(source);
-    MemOperand src1(src0.rm(), src0.offset() + kPointerSize);
+    MemOperand src1(src0.rm(), src0.offset() + kIntSize);
     MemOperand dst0 = g.ToMemOperand(destination);
-    MemOperand dst1(dst0.rm(), dst0.offset() + kPointerSize);
+    MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize);
     __ 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);
index dd019f9..b184018 100644 (file)
@@ -11,74 +11,77 @@ 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)              \
+#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(Mips64Clz)                      \
+  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(Mips64Cmp)                      \
+  V(Mips64CmpD)                     \
+  V(Mips64AddD)                     \
+  V(Mips64SubD)                     \
+  V(Mips64MulD)                     \
+  V(Mips64DivD)                     \
+  V(Mips64ModD)                     \
+  V(Mips64SqrtD)                    \
+  V(Mips64Float64RoundDown)         \
+  V(Mips64Float64RoundTruncate)     \
+  V(Mips64Float64RoundUp)           \
+  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(Mips64Float64ExtractLowWord32)  \
+  V(Mips64Float64ExtractHighWord32) \
+  V(Mips64Float64InsertLowWord32)   \
+  V(Mips64Float64InsertHighWord32)  \
+  V(Mips64Push)                     \
+  V(Mips64StoreToStackSlot)         \
+  V(Mips64StackClaim)               \
   V(Mips64StoreWriteBarrier)
 
 
index 779f786..a0a6e22 100644 (file)
@@ -57,35 +57,6 @@ class Mips64OperandGenerator FINAL : public OperandGenerator {
     }
   }
 
-
-  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();
@@ -147,9 +118,8 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
   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();
+  selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
+                 inputs);
 }
 
 
@@ -334,6 +304,12 @@ void InstructionSelector::VisitWord32Ror(Node* node) {
 }
 
 
+void InstructionSelector::VisitWord32Clz(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64Clz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitWord64Ror(Node* node) {
   VisitRRO(this, kMips64Dror, node);
 }
@@ -581,6 +557,20 @@ void InstructionSelector::VisitFloat64Add(Node* node) {
 
 
 void InstructionSelector::VisitFloat64Sub(Node* node) {
+  Mips64OperandGenerator g(this);
+  Float64BinopMatcher m(node);
+  if (m.left().IsMinusZero() && m.right().IsFloat64RoundDown() &&
+      CanCover(m.node(), m.right().node())) {
+    if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
+        CanCover(m.right().node(), m.right().InputAt(0))) {
+      Float64BinopMatcher mright0(m.right().InputAt(0));
+      if (mright0.left().IsMinusZero()) {
+        Emit(kMips64Float64RoundUp, g.DefineAsRegister(node),
+             g.UseRegister(mright0.right().node()));
+        return;
+      }
+    }
+  }
   VisitRRR(this, kMips64SubD, node);
 }
 
@@ -603,19 +593,20 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64Max(Node* node) { UNREACHABLE(); }
+
+
+void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); }
+
+
 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::VisitFloat64RoundDown(Node* node) {
+  VisitRR(this, kMips64Float64RoundDown, node);
 }
 
 
@@ -629,7 +620,7 @@ void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
 }
 
 
-void InstructionSelector::VisitCall(Node* node) {
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
   Mips64OperandGenerator g(this);
   const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
 
@@ -656,6 +647,13 @@ void InstructionSelector::VisitCall(Node* node) {
     slot--;
   }
 
+  // Pass label of exception handler block.
+  CallDescriptor::Flags flags = descriptor->flags();
+  if (handler != nullptr) {
+    flags |= CallDescriptor::kHasExceptionHandler;
+    buffer.instruction_args.push_back(g.Label(handler));
+  }
+
   // Select the appropriate opcode based on the call type.
   InstructionCode opcode;
   switch (descriptor->kind()) {
@@ -670,7 +668,7 @@ void InstructionSelector::VisitCall(Node* node) {
       UNREACHABLE();
       return;
   }
-  opcode |= MiscField::encode(descriptor->flags());
+  opcode |= MiscField::encode(flags);
 
   // Emit the call instruction.
   Instruction* call_instr =
@@ -779,8 +777,7 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
   opcode = cont->Encode(opcode);
   if (cont->IsBranch()) {
     selector->Emit(opcode, g.NoOutput(), left, right,
-                   g.Label(cont->true_block()),
-                   g.Label(cont->false_block()))->MarkAsControl();
+                   g.Label(cont->true_block()), g.Label(cont->false_block()));
   } else {
     DCHECK(cont->IsSet());
     selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
@@ -808,10 +805,10 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
   Node* right = node->InputAt(1);
 
   // Match immediates on left or right side of comparison.
-  if (g.CanBeImmediate(right, opcode, cont)) {
+  if (g.CanBeImmediate(right, opcode)) {
     VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
                  cont);
-  } else if (g.CanBeImmediate(left, opcode, cont)) {
+  } else if (g.CanBeImmediate(left, opcode)) {
     if (!commutative) cont->Commute();
     VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
                  cont);
@@ -824,7 +821,7 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
 
 void VisitWord32Compare(InstructionSelector* selector, Node* node,
                         FlagsContinuation* cont) {
-  VisitWordCompare(selector, node, kMips64Cmp32, cont, false);
+  VisitWordCompare(selector, node, kMips64Cmp, cont, false);
 }
 
 
@@ -836,15 +833,14 @@ void VisitWord64Compare(InstructionSelector* selector, Node* node,
 }  // namespace
 
 
-void EmitWordCompareZero(InstructionSelector* selector, InstructionCode opcode,
-                         Node* value, FlagsContinuation* cont) {
+void EmitWordCompareZero(InstructionSelector* selector, Node* value,
+                         FlagsContinuation* cont) {
   Mips64OperandGenerator g(selector);
-  opcode = cont->Encode(opcode);
+  InstructionCode opcode = cont->Encode(kMips64Cmp);
   InstructionOperand const value_operand = g.UseRegister(value);
   if (cont->IsBranch()) {
     selector->Emit(opcode, g.NoOutput(), value_operand, g.TempImmediate(0),
-                   g.Label(cont->true_block()),
-                   g.Label(cont->false_block()))->MarkAsControl();
+                   g.Label(cont->true_block()), g.Label(cont->false_block()));
   } else {
     selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
                    g.TempImmediate(0));
@@ -855,13 +851,7 @@ void EmitWordCompareZero(InstructionSelector* selector, InstructionCode opcode,
 // 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
@@ -871,7 +861,6 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
           user = value;
           value = m.left().node();
           cont->Negate();
-          opcode = kMips64Cmp32;
           continue;
         }
         cont->OverwriteAndNegateIfEqual(kEqual);
@@ -946,7 +935,6 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
         }
         break;
       case IrOpcode::kWord32And:
-        return VisitWordCompare(selector, value, kMips64Tst32, cont, true);
       case IrOpcode::kWord64And:
         return VisitWordCompare(selector, value, kMips64Tst, cont, true);
       default:
@@ -956,7 +944,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
   }
 
   // Continuation could not be combined with a compare, emit compare against 0.
-  EmitWordCompareZero(selector, opcode, value, cont);
+  EmitWordCompareZero(selector, value, cont);
 }
 
 
@@ -967,64 +955,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
 }
 
 
-void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
-                                      BasicBlock** case_branches,
-                                      int32_t* case_values, size_t case_count,
-                                      int32_t min_value, int32_t max_value) {
+void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
   Mips64OperandGenerator g(this);
   InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
-  InstructionOperand default_operand = g.Label(default_branch);
-
-  // Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value}
-  // is 2^31-1, so don't assume that it's non-zero below.
-  size_t value_range =
-      1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
-
-  // Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
-  // instruction.
-  size_t table_space_cost = 10 + 2 * value_range;
-  size_t table_time_cost = 10;
-  size_t lookup_space_cost = 2 + 2 * case_count;
-  size_t lookup_time_cost = case_count;
-  if (case_count > 0 &&
+
+  // Emit either ArchTableSwitch or ArchLookupSwitch.
+  size_t table_space_cost = 10 + 2 * sw.value_range;
+  size_t table_time_cost = 3;
+  size_t lookup_space_cost = 2 + 2 * sw.case_count;
+  size_t lookup_time_cost = sw.case_count;
+  if (sw.case_count > 0 &&
       table_space_cost + 3 * table_time_cost <=
           lookup_space_cost + 3 * lookup_time_cost &&
-      min_value > std::numeric_limits<int32_t>::min()) {
+      sw.min_value > std::numeric_limits<int32_t>::min()) {
     InstructionOperand index_operand = value_operand;
-    if (min_value) {
+    if (sw.min_value) {
       index_operand = g.TempRegister();
       Emit(kMips64Sub, index_operand, value_operand,
-           g.TempImmediate(min_value));
+           g.TempImmediate(sw.min_value));
     }
-    size_t input_count = 2 + value_range;
-    auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
-    inputs[0] = index_operand;
-    std::fill(&inputs[1], &inputs[input_count], default_operand);
-    for (size_t index = 0; index < case_count; ++index) {
-      size_t value = case_values[index] - min_value;
-      BasicBlock* branch = case_branches[index];
-      DCHECK_LE(0u, value);
-      DCHECK_LT(value + 2, input_count);
-      inputs[value + 2] = g.Label(branch);
-    }
-    Emit(kArchTableSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
-        ->MarkAsControl();
-    return;
+    // Generate a table lookup.
+    return EmitTableSwitch(sw, index_operand);
   }
 
   // Generate a sequence of conditional jumps.
-  size_t input_count = 2 + case_count * 2;
-  auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
-  inputs[0] = value_operand;
-  inputs[1] = default_operand;
-  for (size_t index = 0; index < case_count; ++index) {
-    int32_t value = case_values[index];
-    BasicBlock* branch = case_branches[index];
-    inputs[index * 2 + 2 + 0] = g.TempImmediate(value);
-    inputs[index * 2 + 2 + 1] = g.Label(branch);
-  }
-  Emit(kArchLookupSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
-      ->MarkAsControl();
+  return EmitLookupSwitch(sw, value_operand);
 }
 
 
@@ -1130,11 +1085,42 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64Float64ExtractLowWord32, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64Float64ExtractHighWord32, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
+  Mips64OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Emit(kMips64Float64InsertLowWord32, g.DefineSameAsFirst(node),
+       g.UseRegister(left), g.UseRegister(right));
+}
+
+
+void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
+  Mips64OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Emit(kMips64Float64InsertHighWord32, g.DefineSameAsFirst(node),
+       g.UseRegister(left), g.UseRegister(right));
+}
+
+
 // static
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
-  return MachineOperatorBuilder::kFloat64Floor |
-         MachineOperatorBuilder::kFloat64Ceil |
+  return MachineOperatorBuilder::kFloat64RoundDown |
          MachineOperatorBuilder::kFloat64RoundTruncate;
 }
 
index 273054e..6fed061 100644 (file)
@@ -51,9 +51,10 @@ CallDescriptor* Linkage::GetRuntimeCallDescriptor(
 CallDescriptor* Linkage::GetStubCallDescriptor(
     Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
     int stack_parameter_count, CallDescriptor::Flags flags,
-    Operator::Properties properties) {
+    Operator::Properties properties, MachineType return_type) {
   return LH::GetStubCallDescriptor(isolate, zone, descriptor,
-                                   stack_parameter_count, flags, properties);
+                                   stack_parameter_count, flags, properties,
+                                   return_type);
 }
 
 
index f4e0513..2c4c720 100644 (file)
@@ -10,31 +10,9 @@ namespace compiler {
 
 namespace {
 
-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(!replacement);
-      replacement = curr;
-      if (to_eliminate != nullptr) break;
-    } else if (curr->destination()->Equals(move->destination())) {
-      DCHECK(!to_eliminate);
-      to_eliminate = curr;
-      if (replacement != nullptr) break;
-    }
-  }
-  DCHECK(!(replacement == to_eliminate && replacement != nullptr));
-  if (replacement != nullptr) {
-    auto new_source = InstructionOperand::New(
-        zone, replacement->source()->kind(), replacement->source()->index());
-    move->set_source(new_source);
-  }
-  return to_eliminate;
-}
+typedef std::pair<InstructionOperand, InstructionOperand> MoveKey;
+typedef ZoneMap<MoveKey, unsigned> MoveMap;
+typedef ZoneSet<InstructionOperand> OperandSet;
 
 
 bool GapsCanMoveOver(Instruction* instr) {
@@ -75,6 +53,10 @@ void MoveOptimizer::Run() {
   for (auto* block : code()->instruction_blocks()) {
     CompressBlock(block);
   }
+  for (auto block : code()->instruction_blocks()) {
+    if (block->PredecessorCount() <= 1) continue;
+    OptimizeMerge(block);
+  }
   for (auto gap : to_finalize_) {
     FinalizeMoves(gap);
   }
@@ -90,7 +72,7 @@ void MoveOptimizer::CompressMoves(MoveOpVector* eliminated, ParallelMove* left,
     // 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());
+      auto to_eliminate = left->PrepareInsertAfter(op);
       if (to_eliminate != nullptr) eliminated->push_back(to_eliminate);
     }
     // Eliminate dead moves.  Must happen before insertion of new moves as the
@@ -157,6 +139,107 @@ void MoveOptimizer::CompressBlock(InstructionBlock* block) {
 }
 
 
+GapInstruction* MoveOptimizer::LastGap(InstructionBlock* block) {
+  int gap_index = block->last_instruction_index() - 1;
+  auto instr = code()->instructions()[gap_index];
+  return GapInstruction::cast(instr);
+}
+
+
+void MoveOptimizer::OptimizeMerge(InstructionBlock* block) {
+  DCHECK(block->PredecessorCount() > 1);
+  // Ensure that the last instruction in all incoming blocks don't contain
+  // things that would prevent moving gap moves across them.
+  for (auto pred_index : block->predecessors()) {
+    auto pred = code()->InstructionBlockAt(pred_index);
+    auto last_instr = code()->instructions()[pred->last_instruction_index()];
+    DCHECK(!last_instr->IsGapMoves());
+    if (last_instr->IsSourcePosition()) continue;
+    if (last_instr->IsCall()) return;
+    if (last_instr->TempCount() != 0) return;
+    if (last_instr->OutputCount() != 0) return;
+    for (size_t i = 0; i < last_instr->InputCount(); ++i) {
+      auto op = last_instr->InputAt(i);
+      if (!op->IsConstant() && !op->IsImmediate()) return;
+    }
+  }
+  // TODO(dcarney): pass a ZonePool down for this?
+  MoveMap move_map(local_zone());
+  size_t correct_counts = 0;
+  // Accumulate set of shared moves.
+  for (auto pred_index : block->predecessors()) {
+    auto pred = code()->InstructionBlockAt(pred_index);
+    auto gap = LastGap(pred);
+    if (gap->parallel_moves()[0] == nullptr ||
+        gap->parallel_moves()[0]->move_operands()->is_empty()) {
+      return;
+    }
+    auto move_ops = gap->parallel_moves()[0]->move_operands();
+    for (auto op = move_ops->begin(); op != move_ops->end(); ++op) {
+      if (op->IsRedundant()) continue;
+      auto src = *op->source();
+      auto dst = *op->destination();
+      MoveKey key = {src, dst};
+      auto res = move_map.insert(std::make_pair(key, 1));
+      if (!res.second) {
+        res.first->second++;
+        if (res.first->second == block->PredecessorCount()) {
+          correct_counts++;
+        }
+      }
+    }
+  }
+  if (move_map.empty() || correct_counts != move_map.size()) return;
+  // Find insertion point.
+  GapInstruction* gap = nullptr;
+  for (int i = block->first_instruction_index();
+       i <= block->last_instruction_index(); ++i) {
+    auto instr = code()->instructions()[i];
+    if (instr->IsGapMoves()) {
+      gap = GapInstruction::cast(instr);
+      continue;
+    }
+    if (!GapsCanMoveOver(instr)) break;
+  }
+  DCHECK(gap != nullptr);
+  bool gap_initialized = true;
+  if (gap->parallel_moves()[0] == nullptr ||
+      gap->parallel_moves()[0]->move_operands()->is_empty()) {
+    to_finalize_.push_back(gap);
+  } else {
+    // Will compress after insertion.
+    gap_initialized = false;
+    std::swap(gap->parallel_moves()[0], gap->parallel_moves()[1]);
+  }
+  auto move = gap->GetOrCreateParallelMove(
+      static_cast<GapInstruction::InnerPosition>(0), code_zone());
+  // Delete relevant entries in predecessors and move everything to block.
+  bool first_iteration = true;
+  for (auto pred_index : block->predecessors()) {
+    auto pred = code()->InstructionBlockAt(pred_index);
+    auto gap = LastGap(pred);
+    auto move_ops = gap->parallel_moves()[0]->move_operands();
+    for (auto op = move_ops->begin(); op != move_ops->end(); ++op) {
+      if (op->IsRedundant()) continue;
+      MoveKey key = {*op->source(), *op->destination()};
+      auto it = move_map.find(key);
+      USE(it);
+      DCHECK(it != move_map.end());
+      if (first_iteration) {
+        move->AddMove(op->source(), op->destination(), code_zone());
+      }
+      op->Eliminate();
+    }
+    first_iteration = false;
+  }
+  // Compress.
+  if (!gap_initialized) {
+    CompressMoves(&temp_vector_0(), gap->parallel_moves()[0],
+                  gap->parallel_moves()[1]);
+  }
+}
+
+
 // Split multiple loads of the same constant or stack slot off into the second
 // slot and keep remaining moves in the first slot.
 void MoveOptimizer::FinalizeMoves(GapInstruction* gap) {
index 2bde09e..e5fa125 100644 (file)
@@ -30,6 +30,8 @@ class MoveOptimizer FINAL {
   void CompressBlock(InstructionBlock* blocke);
   void CompressMoves(MoveOpVector* eliminated, ParallelMove* left,
                      ParallelMove* right);
+  GapInstruction* LastGap(InstructionBlock* block);
+  void OptimizeMerge(InstructionBlock* block);
   void FinalizeMoves(GapInstruction* gap);
 
   Zone* const local_zone_;
diff --git a/deps/v8/src/compiler/node-matchers.cc b/deps/v8/src/compiler/node-matchers.cc
new file mode 100644 (file)
index 0000000..c6ae390
--- /dev/null
@@ -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.
+
+#include "src/compiler/node-matchers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+bool NodeMatcher::IsComparison() const {
+  return IrOpcode::IsComparisonOpcode(opcode());
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
index fc11a0a..48ff3d7 100644 (file)
@@ -7,6 +7,8 @@
 
 #include <cmath>
 
+// TODO(turbofan): Move ExternalReference out of assembler.h
+#include "src/assembler.h"
 #include "src/compiler/node.h"
 #include "src/compiler/operator.h"
 #include "src/unique.h"
@@ -28,6 +30,8 @@ struct NodeMatcher {
   }
   Node* InputAt(int index) const { return node()->InputAt(index); }
 
+  bool IsComparison() const;
+
 #define DEFINE_IS_OPCODE(Opcode) \
   bool Is##Opcode() const { return opcode() == IrOpcode::k##Opcode; }
   ALL_OP_LIST(DEFINE_IS_OPCODE)
@@ -153,6 +157,32 @@ struct HeapObjectMatcher FINAL
 };
 
 
+// A pattern matcher for external reference constants.
+struct ExternalReferenceMatcher FINAL
+    : public ValueMatcher<ExternalReference, IrOpcode::kExternalConstant> {
+  explicit ExternalReferenceMatcher(Node* node)
+      : ValueMatcher<ExternalReference, IrOpcode::kExternalConstant>(node) {}
+};
+
+
+// For shorter pattern matching code, this struct matches the inputs to
+// machine-level load operations.
+template <typename Object>
+struct LoadMatcher : public NodeMatcher {
+  explicit LoadMatcher(Node* node)
+      : NodeMatcher(node), object_(InputAt(0)), index_(InputAt(1)) {}
+
+  typedef Object ObjectMatcher;
+
+  Object const& object() const { return object_; }
+  IntPtrMatcher const& index() const { return index_; }
+
+ private:
+  Object const object_;
+  IntPtrMatcher const index_;
+};
+
+
 // For shorter pattern matching code, this struct matches both the left and
 // 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.
index 47de74e..8956915 100644 (file)
@@ -2,9 +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/node-properties.h"
-
 #include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/node-properties.h"
 #include "src/compiler/operator-properties.h"
 
 namespace v8 {
@@ -58,9 +58,9 @@ Node* NodeProperties::GetContextInput(Node* node) {
 
 
 // static
-Node* NodeProperties::GetFrameStateInput(Node* node) {
-  DCHECK(OperatorProperties::HasFrameStateInput(node->op()));
-  return node->InputAt(FirstFrameStateIndex(node));
+Node* NodeProperties::GetFrameStateInput(Node* node, int index) {
+  DCHECK_LT(index, OperatorProperties::GetFrameStateInputCount(node->op()));
+  return node->InputAt(FirstFrameStateIndex(node) + index);
 }
 
 
@@ -138,9 +138,10 @@ void NodeProperties::ReplaceEffectInput(Node* node, Node* effect, int index) {
 
 
 // static
-void NodeProperties::ReplaceFrameStateInput(Node* node, Node* frame_state) {
-  DCHECK(OperatorProperties::HasFrameStateInput(node->op()));
-  node->ReplaceInput(FirstFrameStateIndex(node), frame_state);
+void NodeProperties::ReplaceFrameStateInput(Node* node, int index,
+                                            Node* frame_state) {
+  DCHECK_LT(index, OperatorProperties::GetFrameStateInputCount(node->op()));
+  node->ReplaceInput(FirstFrameStateIndex(node) + index, frame_state);
 }
 
 
@@ -150,16 +151,40 @@ void NodeProperties::RemoveNonValueInputs(Node* node) {
 }
 
 
+void NodeProperties::MergeControlToEnd(Graph* graph,
+                                       CommonOperatorBuilder* common,
+                                       Node* node) {
+  // Connect the node to the merge exiting the graph.
+  Node* end_pred = NodeProperties::GetControlInput(graph->end());
+  if (end_pred->opcode() == IrOpcode::kMerge) {
+    int inputs = end_pred->op()->ControlInputCount() + 1;
+    end_pred->AppendInput(graph->zone(), node);
+    end_pred->set_op(common->Merge(inputs));
+  } else {
+    Node* merge = graph->NewNode(common->Merge(2), end_pred, node);
+    NodeProperties::ReplaceControlInput(graph->end(), merge);
+  }
+}
+
+
 // static
-void NodeProperties::ReplaceWithValue(Node* node, Node* value, Node* effect) {
-  DCHECK(node->op()->ControlOutputCount() == 0);
+void NodeProperties::ReplaceWithValue(Node* node, Node* value, Node* effect,
+                                      Node* control) {
   if (!effect && node->op()->EffectInputCount() > 0) {
     effect = NodeProperties::GetEffectInput(node);
   }
+  if (control == nullptr && node->op()->ControlInputCount() > 0) {
+    control = NodeProperties::GetControlInput(node);
+  }
 
-  // Requires distinguishing between value and effect edges.
+  // Requires distinguishing between value, effect and control edges.
   for (Edge edge : node->use_edges()) {
-    if (IsEffectEdge(edge)) {
+    if (IsControlEdge(edge)) {
+      DCHECK_EQ(IrOpcode::kIfSuccess, edge.from()->opcode());
+      DCHECK_NOT_NULL(control);
+      edge.from()->ReplaceUses(control);
+      edge.UpdateTo(NULL);
+    } else if (IsEffectEdge(edge)) {
       DCHECK_NOT_NULL(effect);
       edge.UpdateTo(effect);
     } else {
@@ -185,16 +210,13 @@ Node* NodeProperties::FindProjection(Node* node, size_t projection_index) {
 void NodeProperties::CollectControlProjections(Node* node, Node** projections,
                                                size_t projection_count) {
 #ifdef DEBUG
-  DCHECK_EQ(static_cast<int>(projection_count), node->UseCount());
+  DCHECK_LE(static_cast<int>(projection_count), node->UseCount());
   std::memset(projections, 0, sizeof(*projections) * projection_count);
 #endif
   size_t if_value_index = 0;
   for (Node* const use : node->uses()) {
     size_t index;
     switch (use->opcode()) {
-      default:
-        UNREACHABLE();
-      // Fall through.
       case IrOpcode::kIfTrue:
         DCHECK_EQ(IrOpcode::kBranch, node->opcode());
         index = 0;
@@ -203,6 +225,14 @@ void NodeProperties::CollectControlProjections(Node* node, Node** projections,
         DCHECK_EQ(IrOpcode::kBranch, node->opcode());
         index = 1;
         break;
+      case IrOpcode::kIfSuccess:
+        DCHECK_EQ(IrOpcode::kCall, node->opcode());
+        index = 0;
+        break;
+      case IrOpcode::kIfException:
+        DCHECK_EQ(IrOpcode::kCall, node->opcode());
+        index = 1;
+        break;
       case IrOpcode::kIfValue:
         DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
         index = if_value_index++;
@@ -211,6 +241,8 @@ void NodeProperties::CollectControlProjections(Node* node, Node** projections,
         DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
         index = projection_count - 1;
         break;
+      default:
+        continue;
     }
     DCHECK_LT(if_value_index, projection_count);
     DCHECK_LT(index, projection_count);
index a13eea3..350e083 100644 (file)
@@ -12,7 +12,9 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
+class Graph;
 class Operator;
+class CommonOperatorBuilder;
 
 // A facade that simplifies access to the different kinds of inputs to a node.
 class NodeProperties FINAL {
@@ -39,7 +41,7 @@ class NodeProperties FINAL {
 
   static Node* GetValueInput(Node* node, int index);
   static Node* GetContextInput(Node* node);
-  static Node* GetFrameStateInput(Node* node);
+  static Node* GetFrameStateInput(Node* node, int index);
   static Node* GetEffectInput(Node* node, int index = 0);
   static Node* GetControlInput(Node* node, int index = 0);
 
@@ -77,13 +79,19 @@ class NodeProperties FINAL {
   static void ReplaceContextInput(Node* node, Node* context);
   static void ReplaceControlInput(Node* node, Node* control);
   static void ReplaceEffectInput(Node* node, Node* effect, int index = 0);
-  static void ReplaceFrameStateInput(Node* node, Node* frame_state);
+  static void ReplaceFrameStateInput(Node* node, int index, Node* frame_state);
   static void RemoveNonValueInputs(Node* node);
 
-  // Replace value uses of {node} with {value} and effect uses of {node} with
-  // {effect}. If {effect == NULL}, then use the effect input to {node}.
-  static void ReplaceWithValue(Node* node, Node* value, Node* effect = nullptr);
+  // Merge the control node {node} into the end of the graph, introducing a
+  // merge node or expanding an existing merge node if necessary.
+  static void MergeControlToEnd(Graph* graph, CommonOperatorBuilder* common,
+                                Node* node);
 
+  // Replace value uses of {node} with {value} and effect uses of {node} with
+  // {effect}. If {effect == NULL}, then use the effect input to {node}. All
+  // control uses will be relaxed assuming {node} cannot throw.
+  static void ReplaceWithValue(Node* node, Node* value, Node* effect = nullptr,
+                               Node* control = nullptr);
 
   // ---------------------------------------------------------------------------
   // Miscellaneous utilities.
@@ -91,8 +99,9 @@ class NodeProperties FINAL {
   static Node* FindProjection(Node* node, size_t projection_index);
 
   // Collect the branch-related projections from a node, such as IfTrue,
-  // IfFalse, IfValue and IfDefault.
+  // IfFalse, IfSuccess, IfException, IfValue and IfDefault.
   //  - Branch: [ IfTrue, IfFalse ]
+  //  - Call  : [ IfSuccess, IfException ]
   //  - Switch: [ IfValue, ..., IfDefault ]
   static void CollectControlProjections(Node* node, Node** proj, size_t count);
 
index d38e9ce..1a9c326 100644 (file)
@@ -40,7 +40,7 @@ Node* Node::New(Zone* zone, NodeId id, const Operator* op, int input_count,
 
 void Node::Kill() {
   DCHECK_NOT_NULL(op());
-  RemoveAllInputs();
+  NullAllInputs();
   DCHECK(uses().empty());
 }
 
@@ -89,7 +89,7 @@ void Node::RemoveInput(int index) {
 }
 
 
-void Node::RemoveAllInputs() {
+void Node::NullAllInputs() {
   for (Edge edge : input_edges()) edge.UpdateTo(nullptr);
 }
 
@@ -118,33 +118,23 @@ int Node::UseCount() const {
 }
 
 
-Node* Node::UseAt(int index) const {
-  DCHECK_LE(0, index);
-  DCHECK_LT(index, UseCount());
-  const Use* use = first_use_;
-  while (index-- != 0) {
-    use = use->next;
-  }
-  return use->from;
-}
-
+void Node::ReplaceUses(Node* that) {
+  DCHECK(this->first_use_ == nullptr || this->first_use_->prev == nullptr);
+  DCHECK(that->first_use_ == nullptr || that->first_use_->prev == nullptr);
 
-void Node::ReplaceUses(Node* replace_to) {
-  for (Use* use = first_use_; use; use = use->next) {
-    use->from->GetInputRecordPtr(use->input_index)->to = replace_to;
+  // Update the pointers to {this} to point to {that}.
+  Use* last_use = nullptr;
+  for (Use* use = this->first_use_; use; use = use->next) {
+    use->from->GetInputRecordPtr(use->input_index)->to = that;
+    last_use = use;
   }
-  if (!replace_to->last_use_) {
-    DCHECK(!replace_to->first_use_);
-    replace_to->first_use_ = first_use_;
-    replace_to->last_use_ = last_use_;
-  } else if (first_use_) {
-    DCHECK_NOT_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_;
+  if (last_use) {
+    // Concat the use list of {this} and {that}.
+    last_use->next = that->first_use_;
+    if (that->first_use_) that->first_use_->prev = last_use;
+    that->first_use_ = this->first_use_;
   }
   first_use_ = nullptr;
-  last_use_ = nullptr;
 }
 
 
@@ -174,8 +164,7 @@ Node::Node(NodeId id, const Operator* op, int input_count,
       bit_field_(InputCountField::encode(input_count) |
                  ReservedInputCountField::encode(reserved_input_count) |
                  HasAppendableInputsField::encode(false)),
-      first_use_(nullptr),
-      last_use_(nullptr) {}
+      first_use_(nullptr) {}
 
 
 void Node::EnsureAppendableInputs(Zone* zone) {
@@ -192,24 +181,21 @@ void Node::EnsureAppendableInputs(Zone* zone) {
 
 
 void Node::AppendUse(Use* const use) {
-  use->next = nullptr;
-  use->prev = last_use_;
-  if (last_use_) {
-    last_use_->next = use;
-  } else {
-    first_use_ = use;
-  }
-  last_use_ = use;
+  DCHECK(first_use_ == nullptr || first_use_->prev == nullptr);
+  use->next = first_use_;
+  use->prev = nullptr;
+  if (first_use_) first_use_->prev = use;
+  first_use_ = use;
 }
 
 
 void Node::RemoveUse(Use* const use) {
-  if (use == last_use_) {
-    last_use_ = use->prev;
-  }
+  DCHECK(first_use_ == nullptr || first_use_->prev == nullptr);
   if (use->prev) {
+    DCHECK_NE(first_use_, use);
     use->prev->next = use->next;
   } else {
+    DCHECK_EQ(first_use_, use);
     first_use_ = use->next;
   }
   if (use->next) {
index 57a0ebb..e4bd0d0 100644 (file)
@@ -63,11 +63,10 @@ class Node FINAL {
   void AppendInput(Zone* zone, Node* new_to);
   void InsertInput(Zone* zone, int index, Node* new_to);
   void RemoveInput(int index);
-  void RemoveAllInputs();
+  void NullAllInputs();
   void TrimInputCount(int new_input_count);
 
   int UseCount() const;
-  Node* UseAt(int index) const;
   void ReplaceUses(Node* replace_to);
 
   class InputEdges FINAL {
@@ -226,7 +225,6 @@ class Node FINAL {
   NodeId const id_;
   unsigned bit_field_;
   Use* first_use_;
-  Use* last_use_;
   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.
@@ -249,6 +247,7 @@ std::ostream& operator<<(std::ostream& os, const Node& n);
 
 // Typedefs to shorten commonly used Node containers.
 typedef ZoneDeque<Node*> NodeDeque;
+typedef ZoneSet<Node*> NodeSet;
 typedef ZoneVector<Node*> NodeVector;
 typedef ZoneVector<NodeVector> NodeVectorVector;
 
index a4f8d3e..73ce698 100644 (file)
   V(Dead)                        \
   V(Loop)                        \
   V(Branch)                      \
+  V(Switch)                      \
   V(IfTrue)                      \
   V(IfFalse)                     \
-  V(Switch)                      \
+  V(IfSuccess)                   \
+  V(IfException)                 \
   V(IfValue)                     \
   V(IfDefault)                   \
   V(Merge)                       \
+  V(Deoptimize)                  \
   V(Return)                      \
   V(OsrNormalEntry)              \
   V(OsrLoopEntry)                \
@@ -45,6 +48,7 @@
   V(Finish)              \
   V(FrameState)          \
   V(StateValues)         \
+  V(TypedStateValues)    \
   V(Call)                \
   V(Parameter)           \
   V(OsrValue)            \
   V(JSCallFunction)         \
   V(JSCallRuntime)          \
   V(JSYield)                \
-  V(JSDebugger)
+  V(JSStackCheck)
 
 #define JS_OP_LIST(V)     \
   JS_SIMPLE_BINOP_LIST(V) \
   JS_OTHER_OP_LIST(V)
 
 // Opcodes for VirtuaMachine-level operators.
-#define SIMPLIFIED_OP_LIST(V) \
-  V(AnyToBoolean)             \
-  V(BooleanNot)               \
-  V(BooleanToNumber)          \
-  V(NumberEqual)              \
-  V(NumberLessThan)           \
-  V(NumberLessThanOrEqual)    \
-  V(NumberAdd)                \
-  V(NumberSubtract)           \
-  V(NumberMultiply)           \
-  V(NumberDivide)             \
-  V(NumberModulus)            \
-  V(NumberToInt32)            \
-  V(NumberToUint32)           \
-  V(PlainPrimitiveToNumber)   \
-  V(ReferenceEqual)           \
-  V(StringEqual)              \
-  V(StringLessThan)           \
-  V(StringLessThanOrEqual)    \
-  V(StringAdd)                \
-  V(ChangeTaggedToInt32)      \
-  V(ChangeTaggedToUint32)     \
-  V(ChangeTaggedToFloat64)    \
-  V(ChangeInt32ToTagged)      \
-  V(ChangeUint32ToTagged)     \
-  V(ChangeFloat64ToTagged)    \
-  V(ChangeBoolToBit)          \
-  V(ChangeBitToBool)          \
-  V(LoadField)                \
-  V(LoadBuffer)               \
-  V(LoadElement)              \
-  V(StoreField)               \
-  V(StoreBuffer)              \
-  V(StoreElement)             \
-  V(ObjectIsSmi)              \
+#define SIMPLIFIED_COMPARE_BINOP_LIST(V) \
+  V(NumberEqual)                         \
+  V(NumberLessThan)                      \
+  V(NumberLessThanOrEqual)               \
+  V(ReferenceEqual)                      \
+  V(StringEqual)                         \
+  V(StringLessThan)                      \
+  V(StringLessThanOrEqual)
+
+#define SIMPLIFIED_OP_LIST(V)      \
+  SIMPLIFIED_COMPARE_BINOP_LIST(V) \
+  V(BooleanNot)                    \
+  V(BooleanToNumber)               \
+  V(NumberAdd)                     \
+  V(NumberSubtract)                \
+  V(NumberMultiply)                \
+  V(NumberDivide)                  \
+  V(NumberModulus)                 \
+  V(NumberToInt32)                 \
+  V(NumberToUint32)                \
+  V(PlainPrimitiveToNumber)        \
+  V(StringAdd)                     \
+  V(ChangeTaggedToInt32)           \
+  V(ChangeTaggedToUint32)          \
+  V(ChangeTaggedToFloat64)         \
+  V(ChangeInt32ToTagged)           \
+  V(ChangeUint32ToTagged)          \
+  V(ChangeFloat64ToTagged)         \
+  V(ChangeBoolToBit)               \
+  V(ChangeBitToBool)               \
+  V(LoadField)                     \
+  V(LoadBuffer)                    \
+  V(LoadElement)                   \
+  V(StoreField)                    \
+  V(StoreBuffer)                   \
+  V(StoreElement)                  \
+  V(ObjectIsSmi)                   \
   V(ObjectIsNonNegativeSmi)
 
 // Opcodes for Machine-level operators.
-#define MACHINE_OP_LIST(V)    \
-  V(Load)                     \
-  V(Store)                    \
-  V(Word32And)                \
-  V(Word32Or)                 \
-  V(Word32Xor)                \
-  V(Word32Shl)                \
-  V(Word32Shr)                \
-  V(Word32Sar)                \
-  V(Word32Ror)                \
-  V(Word32Equal)              \
-  V(Word64And)                \
-  V(Word64Or)                 \
-  V(Word64Xor)                \
-  V(Word64Shl)                \
-  V(Word64Shr)                \
-  V(Word64Sar)                \
-  V(Word64Ror)                \
-  V(Word64Equal)              \
-  V(Int32Add)                 \
-  V(Int32AddWithOverflow)     \
-  V(Int32Sub)                 \
-  V(Int32SubWithOverflow)     \
-  V(Int32Mul)                 \
-  V(Int32MulHigh)             \
-  V(Int32Div)                 \
-  V(Int32Mod)                 \
-  V(Int32LessThan)            \
-  V(Int32LessThanOrEqual)     \
-  V(Uint32Div)                \
-  V(Uint32LessThan)           \
-  V(Uint32LessThanOrEqual)    \
-  V(Uint32Mod)                \
-  V(Uint32MulHigh)            \
-  V(Int64Add)                 \
-  V(Int64Sub)                 \
-  V(Int64Mul)                 \
-  V(Int64Div)                 \
-  V(Int64Mod)                 \
-  V(Int64LessThan)            \
-  V(Int64LessThanOrEqual)     \
-  V(Uint64Div)                \
-  V(Uint64LessThan)           \
-  V(Uint64Mod)                \
-  V(ChangeFloat32ToFloat64)   \
-  V(ChangeFloat64ToInt32)     \
-  V(ChangeFloat64ToUint32)    \
-  V(ChangeInt32ToFloat64)     \
-  V(ChangeInt32ToInt64)       \
-  V(ChangeUint32ToFloat64)    \
-  V(ChangeUint32ToUint64)     \
-  V(TruncateFloat64ToFloat32) \
-  V(TruncateFloat64ToInt32)   \
-  V(TruncateInt64ToInt32)     \
-  V(Float64Add)               \
-  V(Float64Sub)               \
-  V(Float64Mul)               \
-  V(Float64Div)               \
-  V(Float64Mod)               \
-  V(Float64Sqrt)              \
-  V(Float64Equal)             \
-  V(Float64LessThan)          \
-  V(Float64LessThanOrEqual)   \
-  V(Float64Floor)             \
-  V(Float64Ceil)              \
-  V(Float64RoundTruncate)     \
-  V(Float64RoundTiesAway)     \
-  V(LoadStackPointer)         \
-  V(CheckedLoad)              \
+#define MACHINE_COMPARE_BINOP_LIST(V) \
+  V(Word32Equal)                      \
+  V(Word64Equal)                      \
+  V(Int32LessThan)                    \
+  V(Int32LessThanOrEqual)             \
+  V(Uint32LessThan)                   \
+  V(Uint32LessThanOrEqual)            \
+  V(Int64LessThan)                    \
+  V(Int64LessThanOrEqual)             \
+  V(Uint64LessThan)                   \
+  V(Float64Equal)                     \
+  V(Float64LessThan)                  \
+  V(Float64LessThanOrEqual)
+
+#define MACHINE_OP_LIST(V)      \
+  MACHINE_COMPARE_BINOP_LIST(V) \
+  V(Load)                       \
+  V(Store)                      \
+  V(Word32And)                  \
+  V(Word32Or)                   \
+  V(Word32Xor)                  \
+  V(Word32Shl)                  \
+  V(Word32Shr)                  \
+  V(Word32Sar)                  \
+  V(Word32Ror)                  \
+  V(Word32Clz)                  \
+  V(Word64And)                  \
+  V(Word64Or)                   \
+  V(Word64Xor)                  \
+  V(Word64Shl)                  \
+  V(Word64Shr)                  \
+  V(Word64Sar)                  \
+  V(Word64Ror)                  \
+  V(Int32Add)                   \
+  V(Int32AddWithOverflow)       \
+  V(Int32Sub)                   \
+  V(Int32SubWithOverflow)       \
+  V(Int32Mul)                   \
+  V(Int32MulHigh)               \
+  V(Int32Div)                   \
+  V(Int32Mod)                   \
+  V(Uint32Div)                  \
+  V(Uint32Mod)                  \
+  V(Uint32MulHigh)              \
+  V(Int64Add)                   \
+  V(Int64Sub)                   \
+  V(Int64Mul)                   \
+  V(Int64Div)                   \
+  V(Int64Mod)                   \
+  V(Uint64Div)                  \
+  V(Uint64Mod)                  \
+  V(ChangeFloat32ToFloat64)     \
+  V(ChangeFloat64ToInt32)       \
+  V(ChangeFloat64ToUint32)      \
+  V(ChangeInt32ToFloat64)       \
+  V(ChangeInt32ToInt64)         \
+  V(ChangeUint32ToFloat64)      \
+  V(ChangeUint32ToUint64)       \
+  V(TruncateFloat64ToFloat32)   \
+  V(TruncateFloat64ToInt32)     \
+  V(TruncateInt64ToInt32)       \
+  V(Float64Add)                 \
+  V(Float64Sub)                 \
+  V(Float64Mul)                 \
+  V(Float64Div)                 \
+  V(Float64Mod)                 \
+  V(Float64Max)                 \
+  V(Float64Min)                 \
+  V(Float64Sqrt)                \
+  V(Float64RoundDown)           \
+  V(Float64RoundTruncate)       \
+  V(Float64RoundTiesAway)       \
+  V(Float64ExtractLowWord32)    \
+  V(Float64ExtractHighWord32)   \
+  V(Float64InsertLowWord32)     \
+  V(Float64InsertHighWord32)    \
+  V(LoadStackPointer)           \
+  V(CheckedLoad)                \
   V(CheckedStore)
 
 #define VALUE_OP_LIST(V) \
@@ -291,7 +306,7 @@ class IrOpcode {
 
   // Returns true if opcode for JavaScript operator.
   static bool IsJsOpcode(Value value) {
-    return kJSEqual <= value && value <= kJSDebugger;
+    return kJSEqual <= value && value <= kJSStackCheck;
   }
 
   // Returns true if opcode for constant operator.
@@ -299,8 +314,23 @@ class IrOpcode {
     return kInt32Constant <= value && value <= kHeapConstant;
   }
 
-  static bool IsPhiOpcode(Value val) {
-    return val == kPhi || val == kEffectPhi;
+  static bool IsPhiOpcode(Value value) {
+    return value == kPhi || value == kEffectPhi;
+  }
+
+  static bool IsMergeOpcode(Value value) {
+    return value == kMerge || value == kLoop;
+  }
+
+  static bool IsIfProjectionOpcode(Value value) {
+    return kIfTrue <= value && value <= kIfDefault;
+  }
+
+  // Returns true if opcode for comparison operator.
+  static bool IsComparisonOpcode(Value value) {
+    return (kJSEqual <= value && value <= kJSGreaterThanOrEqual) ||
+           (kNumberEqual <= value && value <= kStringLessThanOrEqual) ||
+           (kWord32Equal <= value && value <= kFloat64LessThanOrEqual);
   }
 };
 
index 53bd16c..3a91fd6 100644 (file)
@@ -20,13 +20,13 @@ bool OperatorProperties::HasContextInput(const Operator* op) {
 
 
 // static
-bool OperatorProperties::HasFrameStateInput(const Operator* op) {
+int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
   if (!FLAG_turbo_deoptimization) {
-    return false;
+    return 0;
   }
   switch (op->opcode()) {
     case IrOpcode::kFrameState:
-      return true;
+      return 1;
     case IrOpcode::kJSCallRuntime: {
       const CallRuntimeParameters& p = CallRuntimeParametersOf(op);
       return Linkage::NeedsFrameState(p.id());
@@ -35,7 +35,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
     // Strict equality cannot lazily deoptimize.
     case IrOpcode::kJSStrictEqual:
     case IrOpcode::kJSStrictNotEqual:
-      return false;
+      return 0;
 
     // Calls
     case IrOpcode::kJSCallFunction:
@@ -51,19 +51,6 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
     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::kJSModulus:
-    case IrOpcode::kJSMultiply:
-    case IrOpcode::kJSShiftLeft:
-    case IrOpcode::kJSShiftRight:
-    case IrOpcode::kJSShiftRightLogical:
-    case IrOpcode::kJSSubtract:
-
     // Context operations
     case IrOpcode::kJSCreateWithContext:
 
@@ -72,16 +59,40 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
     case IrOpcode::kJSToNumber:
     case IrOpcode::kJSToName:
 
+    // Misc operations
+    case IrOpcode::kJSStackCheck:
+
     // Properties
     case IrOpcode::kJSLoadNamed:
-    case IrOpcode::kJSLoadProperty:
     case IrOpcode::kJSStoreNamed:
-    case IrOpcode::kJSStoreProperty:
+    case IrOpcode::kJSLoadProperty:
     case IrOpcode::kJSDeleteProperty:
-      return true;
+      return 1;
+
+    // StoreProperty provides a second frame state just before
+    // the operation. This is used to lazy-deoptimize a to-number
+    // conversion for typed arrays.
+    case IrOpcode::kJSStoreProperty:
+      return 2;
+
+    // Binary operators that can deopt in the middle the operation (e.g.,
+    // as a result of lazy deopt in ToNumber conversion) need a second frame
+    // state so that we can resume before the operation.
+    case IrOpcode::kJSMultiply:
+    case IrOpcode::kJSAdd:
+    case IrOpcode::kJSBitwiseAnd:
+    case IrOpcode::kJSBitwiseOr:
+    case IrOpcode::kJSBitwiseXor:
+    case IrOpcode::kJSDivide:
+    case IrOpcode::kJSModulus:
+    case IrOpcode::kJSShiftLeft:
+    case IrOpcode::kJSShiftRight:
+    case IrOpcode::kJSShiftRightLogical:
+    case IrOpcode::kJSSubtract:
+      return 2;
 
     default:
-      return false;
+      return 0;
   }
 }
 
@@ -100,7 +111,8 @@ bool OperatorProperties::IsBasicBlockBegin(const Operator* op) {
   return opcode == IrOpcode::kStart || opcode == IrOpcode::kEnd ||
          opcode == IrOpcode::kDead || opcode == IrOpcode::kLoop ||
          opcode == IrOpcode::kMerge || opcode == IrOpcode::kIfTrue ||
-         opcode == IrOpcode::kIfFalse || opcode == IrOpcode::kIfValue ||
+         opcode == IrOpcode::kIfFalse || opcode == IrOpcode::kIfSuccess ||
+         opcode == IrOpcode::kIfException || opcode == IrOpcode::kIfValue ||
          opcode == IrOpcode::kIfDefault;
 }
 
index 37c9755..15ce2e1 100644 (file)
@@ -18,14 +18,11 @@ class Operator;
 class OperatorProperties FINAL {
  public:
   static bool HasContextInput(const Operator* op);
-  static bool HasFrameStateInput(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 GetFrameStateInputCount(const Operator* op);
+
   static int GetTotalInputCount(const Operator* op);
 
   static bool IsBasicBlockBegin(const Operator* op);
index 6407499..ec365fa 100644 (file)
@@ -97,6 +97,14 @@ class Operator : public ZoneObject {
   int EffectOutputCount() const { return effect_out_; }
   int ControlOutputCount() const { return control_out_; }
 
+  static size_t ZeroIfEliminatable(Properties properties) {
+    return (properties & kEliminatable) == kEliminatable ? 0 : 1;
+  }
+
+  static size_t ZeroIfNoThrow(Properties properties) {
+    return (properties & kNoThrow) == kNoThrow ? 0 : 2;
+  }
+
   static size_t ZeroIfPure(Properties properties) {
     return (properties & kPure) == kPure ? 0 : 1;
   }
index b7cd7ec..2ab5d73 100644 (file)
@@ -26,6 +26,18 @@ OsrHelper::OsrHelper(CompilationInfo* info)
                         info->osr_expr_stack_height()) {}
 
 
+#ifdef DEBUG
+#define TRACE_COND (FLAG_trace_turbo_graph && FLAG_trace_osr)
+#else
+#define TRACE_COND false
+#endif
+
+#define TRACE(...)                       \
+  do {                                   \
+    if (TRACE_COND) PrintF(__VA_ARGS__); \
+  } while (false)
+
+
 // Peel outer loops and rewire the graph so that control reduction can
 // produce a properly formed graph.
 static void PeelOuterLoopsForOsr(Graph* graph, CommonOperatorBuilder* common,
@@ -44,6 +56,9 @@ static void PeelOuterLoopsForOsr(Graph* graph, CommonOperatorBuilder* common,
     NodeVector* mapping =
         new (stuff) NodeVector(original_count, sentinel, tmp_zone);
     copies.push_back(mapping);
+    TRACE("OsrDuplication #%zu, depth %zu, header #%d:%s\n", copies.size(),
+          loop->depth(), loop_tree->HeaderNode(loop)->id(),
+          loop_tree->HeaderNode(loop)->op()->mnemonic());
 
     // Prepare the mapping for OSR values and the OSR loop entry.
     mapping->at(osr_normal_entry->id()) = dead;
@@ -54,6 +69,8 @@ static void PeelOuterLoopsForOsr(Graph* graph, CommonOperatorBuilder* common,
          outer = outer->parent()) {
       for (Node* node : loop_tree->HeaderNodes(outer)) {
         mapping->at(node->id()) = dead;
+        TRACE(" ---- #%d:%s -> dead (header)\n", node->id(),
+              node->op()->mnemonic());
       }
     }
 
@@ -82,71 +99,132 @@ static void PeelOuterLoopsForOsr(Graph* graph, CommonOperatorBuilder* common,
         NodeProperties::SetBounds(copy, NodeProperties::GetBounds(orig));
       }
       mapping->at(orig->id()) = copy;
+      TRACE(" copy #%d:%s -> #%d\n", orig->id(), orig->op()->mnemonic(),
+            copy->id());
     }
 
     // Fix missing inputs.
-    for (size_t i = 0; i < all.live.size(); i++) {
-      Node* orig = all.live[i];
+    for (Node* orig : all.live) {
       Node* copy = mapping->at(orig->id());
       for (int j = 0; j < copy->InputCount(); j++) {
-        Node* input = copy->InputAt(j);
-        if (input == sentinel)
+        if (copy->InputAt(j) == sentinel) {
           copy->ReplaceInput(j, mapping->at(orig->InputAt(j)->id()));
+        }
       }
     }
 
-    // Construct the transfer from the previous graph copies to the new copy.
+    // Construct the entry into this loop from previous copies.
+
+    // Gather the live loop header nodes, {loop_header} first.
     Node* loop_header = loop_tree->HeaderNode(loop);
-    NodeVector* previous =
-        copies.size() > 1 ? copies[copies.size() - 2] : nullptr;
-    const int backedges = loop_header->op()->ControlInputCount() - 1;
-    if (backedges == 1) {
-      // Simple case. Map the incoming edges to the loop to the previous copy.
-      for (Node* node : loop_tree->HeaderNodes(loop)) {
-        if (!all.IsLive(node)) continue;  // dead phi hanging off loop.
+    NodeVector header_nodes(tmp_zone);
+    header_nodes.reserve(loop->HeaderSize());
+    header_nodes.push_back(loop_header);  // put the loop header first.
+    for (Node* node : loop_tree->HeaderNodes(loop)) {
+      if (node != loop_header && all.IsLive(node)) {
+        header_nodes.push_back(node);
+      }
+    }
+
+    // Gather backedges from the previous copies of the inner loops of {loop}.
+    NodeVectorVector backedges(tmp_zone);
+    TRACE("Gathering backedges...\n");
+    for (int i = 1; i < loop_header->InputCount(); i++) {
+      if (TRACE_COND) {
+        Node* control = loop_header->InputAt(i);
+        size_t incoming_depth = 0;
+        for (int j = 0; j < control->op()->ControlInputCount(); j++) {
+          Node* k = NodeProperties::GetControlInput(control, j);
+          incoming_depth =
+              std::max(incoming_depth, loop_tree->ContainingLoop(k)->depth());
+        }
+
+        TRACE(" edge @%d #%d:%s, incoming depth %zu\n", i, control->id(),
+              control->op()->mnemonic(), incoming_depth);
+      }
+
+      for (int pos = static_cast<int>(copies.size()) - 1; pos >= 0; pos--) {
+        backedges.push_back(NodeVector(tmp_zone));
+        backedges.back().reserve(header_nodes.size());
+
+        NodeVector* previous_map = pos > 0 ? copies[pos - 1] : nullptr;
+
+        for (Node* node : header_nodes) {
+          Node* input = node->InputAt(i);
+          if (previous_map) input = previous_map->at(input->id());
+          backedges.back().push_back(input);
+          TRACE("   node #%d:%s(@%d) = #%d:%s\n", node->id(),
+                node->op()->mnemonic(), i, input->id(),
+                input->op()->mnemonic());
+        }
+      }
+    }
+
+    int backedge_count = static_cast<int>(backedges.size());
+    if (backedge_count == 1) {
+      // Simple case of single backedge, therefore a single entry.
+      int index = 0;
+      for (Node* node : header_nodes) {
         Node* copy = mapping->at(node->id());
-        Node* backedge = node->InputAt(1);
-        if (previous) backedge = previous->at(backedge->id());
-        copy->ReplaceInput(0, backedge);
+        Node* input = backedges[0][index];
+        copy->ReplaceInput(0, input);
+        TRACE(" header #%d:%s(0) => #%d:%s\n", copy->id(),
+              copy->op()->mnemonic(), input->id(), input->op()->mnemonic());
+        index++;
       }
     } else {
-      // Complex case. Multiple backedges. Introduce a merge for incoming edges.
-      tmp_inputs.clear();
-      for (int i = 0; i < backedges; i++) {
-        Node* backedge = loop_header->InputAt(i + 1);
-        if (previous) backedge = previous->at(backedge->id());
-        tmp_inputs.push_back(backedge);
-      }
-      Node* merge =
-          graph->NewNode(common->Merge(backedges), backedges, &tmp_inputs[0]);
-      for (Node* node : loop_tree->HeaderNodes(loop)) {
-        if (!all.IsLive(node)) continue;  // dead phi hanging off loop.
+      // Complex case of multiple backedges from previous copies requires
+      // merging the backedges to create the entry into the loop header.
+      Node* merge = nullptr;
+      int index = 0;
+      for (Node* node : header_nodes) {
+        // Gather edge inputs into {tmp_inputs}.
+        tmp_inputs.clear();
+        for (int edge = 0; edge < backedge_count; edge++) {
+          tmp_inputs.push_back(backedges[edge][index]);
+        }
         Node* copy = mapping->at(node->id());
+        Node* input;
         if (node == loop_header) {
-          // The entry to the loop is the merge.
+          // Create the merge for the entry into the loop header.
+          input = merge = graph->NewNode(common->Merge(backedge_count),
+                                         backedge_count, &tmp_inputs[0]);
           copy->ReplaceInput(0, merge);
         } else {
-          // Merge inputs to the phi at the loop entry.
-          tmp_inputs.clear();
-          for (int i = 0; i < backedges; i++) {
-            Node* backedge = node->InputAt(i + 1);
-            if (previous) backedge = previous->at(backedge->id());
-            tmp_inputs.push_back(backedge);
-          }
+          // Create a phi that merges values at entry into the loop header.
+          DCHECK_NOT_NULL(merge);
+          DCHECK(IrOpcode::IsPhiOpcode(node->opcode()));
           tmp_inputs.push_back(merge);
-          Node* phi =
-              graph->NewNode(common->ResizeMergeOrPhi(node->op(), backedges),
-                             backedges + 1, &tmp_inputs[0]);
+          Node* phi = input = graph->NewNode(
+              common->ResizeMergeOrPhi(node->op(), backedge_count),
+              backedge_count + 1, &tmp_inputs[0]);
           copy->ReplaceInput(0, phi);
         }
+
+        // Print the merge.
+        if (TRACE_COND) {
+          TRACE(" header #%d:%s(0) => #%d:%s(", copy->id(),
+                copy->op()->mnemonic(), input->id(), input->op()->mnemonic());
+          for (size_t i = 0; i < tmp_inputs.size(); i++) {
+            if (i > 0) TRACE(", ");
+            Node* input = tmp_inputs[i];
+            TRACE("#%d:%s", input->id(), input->op()->mnemonic());
+          }
+          TRACE(")\n");
+        }
+
+        index++;
       }
     }
   }
 
   // Kill the outer loops in the original graph.
+  TRACE("Killing outer loop headers...\n");
   for (LoopTree::Loop* outer = osr_loop->parent(); outer;
        outer = outer->parent()) {
-    loop_tree->HeaderNode(outer)->ReplaceUses(dead);
+    Node* loop_header = loop_tree->HeaderNode(outer);
+    loop_header->ReplaceUses(dead);
+    TRACE(" ---- #%d:%s\n", loop_header->id(), loop_header->op()->mnemonic());
   }
 
   // Merge the ends of the graph copies.
index 5ec5d08..b1d7fda 100644 (file)
@@ -8,7 +8,6 @@
 #include <sstream>
 
 #include "src/base/platform/elapsed-timer.h"
-#include "src/bootstrapper.h"  // TODO(mstarzinger): Only temporary.
 #include "src/compiler/ast-graph-builder.h"
 #include "src/compiler/ast-loop-assignment-analyzer.h"
 #include "src/compiler/basic-block-instrumentor.h"
@@ -26,6 +25,7 @@
 #include "src/compiler/js-generic-lowering.h"
 #include "src/compiler/js-inlining.h"
 #include "src/compiler/js-intrinsic-lowering.h"
+#include "src/compiler/js-type-feedback.h"
 #include "src/compiler/js-typed-lowering.h"
 #include "src/compiler/jump-threading.h"
 #include "src/compiler/load-elimination.h"
@@ -47,6 +47,7 @@
 #include "src/compiler/verifier.h"
 #include "src/compiler/zone-pool.h"
 #include "src/ostreams.h"
+#include "src/type-info.h"
 #include "src/utils.h"
 
 namespace v8 {
@@ -73,6 +74,7 @@ class PipelineData {
         common_(nullptr),
         javascript_(nullptr),
         jsgraph_(nullptr),
+        js_type_feedback_(nullptr),
         typer_(nullptr),
         schedule_(nullptr),
         instruction_zone_scope_(zone_pool_),
@@ -112,6 +114,7 @@ class PipelineData {
         common_(nullptr),
         javascript_(nullptr),
         jsgraph_(nullptr),
+        js_type_feedback_(nullptr),
         typer_(nullptr),
         schedule_(schedule),
         instruction_zone_scope_(zone_pool_),
@@ -138,6 +141,7 @@ class PipelineData {
         common_(nullptr),
         javascript_(nullptr),
         jsgraph_(nullptr),
+        js_type_feedback_(nullptr),
         typer_(nullptr),
         schedule_(nullptr),
         instruction_zone_scope_(zone_pool_),
@@ -175,6 +179,10 @@ class PipelineData {
   CommonOperatorBuilder* common() const { return common_; }
   JSOperatorBuilder* javascript() const { return javascript_; }
   JSGraph* jsgraph() const { return jsgraph_; }
+  JSTypeFeedbackTable* js_type_feedback() { return js_type_feedback_; }
+  void set_js_type_feedback(JSTypeFeedbackTable* js_type_feedback) {
+    js_type_feedback_ = js_type_feedback;
+  }
   Typer* typer() const { return typer_.get(); }
 
   LoopAssignmentAnalysis* loop_assignment() const { return loop_assignment_; }
@@ -208,6 +216,7 @@ class PipelineData {
     common_ = nullptr;
     javascript_ = nullptr;
     jsgraph_ = nullptr;
+    js_type_feedback_ = nullptr;
     schedule_ = nullptr;
   }
 
@@ -260,6 +269,7 @@ class PipelineData {
   CommonOperatorBuilder* common_;
   JSOperatorBuilder* javascript_;
   JSGraph* jsgraph_;
+  JSTypeFeedbackTable* js_type_feedback_;
   // TODO(dcarney): make this into a ZoneObject.
   SmartPointer<Typer> typer_;
   Schedule* schedule_;
@@ -292,20 +302,17 @@ static void TraceSchedule(Schedule* 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);
-    }
+  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) + 1;
+    SmartArrayPointer<char> name(new char[len]);
+    memcpy(name.get(), major_name, len);
+    return name;
   } else {
     AllowHandleDereference allow_deref;
-    name = info->function()->debug_name()->ToCString();
+    return info->function()->debug_name()->ToCString();
   }
-  return name;
 }
 
 
@@ -314,14 +321,16 @@ class AstGraphBuilderWithPositions : public AstGraphBuilder {
   AstGraphBuilderWithPositions(Zone* local_zone, CompilationInfo* info,
                                JSGraph* jsgraph,
                                LoopAssignmentAnalysis* loop_assignment,
+                               JSTypeFeedbackTable* js_type_feedback,
                                SourcePositionTable* source_positions)
-      : AstGraphBuilder(local_zone, info, jsgraph, loop_assignment),
+      : AstGraphBuilder(local_zone, info, jsgraph, loop_assignment,
+                        js_type_feedback),
         source_positions_(source_positions),
         start_position_(info->shared_info()->start_position()) {}
 
-  bool CreateGraph(bool constant_context) {
+  bool CreateGraph(bool constant_context, bool stack_check) {
     SourcePositionTable::Scope pos_scope(source_positions_, start_position_);
-    return AstGraphBuilder::CreateGraph(constant_context);
+    return AstGraphBuilder::CreateGraph(constant_context, stack_check);
   }
 
 #define DEF_VISIT(type)                                               \
@@ -423,8 +432,9 @@ struct GraphBuilderPhase {
   void Run(PipelineData* data, Zone* temp_zone, bool constant_context) {
     AstGraphBuilderWithPositions graph_builder(
         temp_zone, data->info(), data->jsgraph(), data->loop_assignment(),
-        data->source_positions());
-    if (!graph_builder.CreateGraph(constant_context)) {
+        data->js_type_feedback(), data->source_positions());
+    bool stack_check = !data->info()->IsStub();
+    if (!graph_builder.CreateGraph(constant_context, stack_check)) {
       data->set_compilation_failed();
     }
   }
@@ -451,7 +461,10 @@ struct InliningPhase {
   void Run(PipelineData* data, Zone* temp_zone) {
     SourcePositionTable::Scope pos(data->source_positions(),
                                    SourcePosition::Unknown());
-    JSInliner inliner(temp_zone, data->info(), data->jsgraph());
+    JSInliner inliner(data->info()->is_inlining_enabled()
+                          ? JSInliner::kGeneralInlining
+                          : JSInliner::kBuiltinsInlining,
+                      temp_zone, data->info(), data->jsgraph());
     GraphReducer graph_reducer(data->graph(), temp_zone);
     AddReducer(data, &graph_reducer, &inliner);
     graph_reducer.ReduceGraph();
@@ -480,21 +493,38 @@ struct OsrDeconstructionPhase {
 };
 
 
+struct JSTypeFeedbackPhase {
+  static const char* phase_name() { return "type feedback specializing"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    SourcePositionTable::Scope pos(data->source_positions(),
+                                   SourcePosition::Unknown());
+    Handle<Context> native_context(data->info()->context()->native_context());
+    TypeFeedbackOracle oracle(data->isolate(), temp_zone,
+                              data->info()->unoptimized_code(),
+                              data->info()->feedback_vector(), native_context);
+    GraphReducer graph_reducer(data->graph(), temp_zone);
+    JSTypeFeedbackSpecializer specializer(data->jsgraph(),
+                                          data->js_type_feedback(), &oracle);
+    AddReducer(data, &graph_reducer, &specializer);
+    graph_reducer.ReduceGraph();
+  }
+};
+
+
 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);
     JSIntrinsicLowering intrinsic_lowering(data->jsgraph());
     SimplifiedOperatorReducer simple_reducer(data->jsgraph());
-    CommonOperatorReducer common_reducer;
+    CommonOperatorReducer common_reducer(data->jsgraph());
     GraphReducer graph_reducer(data->graph(), temp_zone);
-    AddReducer(data, &graph_reducer, &vn_reducer);
     AddReducer(data, &graph_reducer, &builtin_reducer);
     AddReducer(data, &graph_reducer, &typed_lowering);
     AddReducer(data, &graph_reducer, &intrinsic_lowering);
@@ -518,7 +548,7 @@ struct SimplifiedLoweringPhase {
     ValueNumberingReducer vn_reducer(temp_zone);
     SimplifiedOperatorReducer simple_reducer(data->jsgraph());
     MachineOperatorReducer machine_reducer(data->jsgraph());
-    CommonOperatorReducer common_reducer;
+    CommonOperatorReducer common_reducer(data->jsgraph());
     GraphReducer graph_reducer(data->graph(), temp_zone);
     AddReducer(data, &graph_reducer, &vn_reducer);
     AddReducer(data, &graph_reducer, &simple_reducer);
@@ -533,6 +563,8 @@ struct ControlFlowOptimizationPhase {
   static const char* phase_name() { return "control flow optimization"; }
 
   void Run(PipelineData* data, Zone* temp_zone) {
+    SourcePositionTable::Scope pos(data->source_positions(),
+                                   SourcePosition::Unknown());
     ControlFlowOptimizer optimizer(data->jsgraph(), temp_zone);
     optimizer.Optimize();
   }
@@ -549,7 +581,7 @@ struct ChangeLoweringPhase {
     SimplifiedOperatorReducer simple_reducer(data->jsgraph());
     ChangeLowering lowering(data->jsgraph());
     MachineOperatorReducer machine_reducer(data->jsgraph());
-    CommonOperatorReducer common_reducer;
+    CommonOperatorReducer common_reducer(data->jsgraph());
     GraphReducer graph_reducer(data->graph(), temp_zone);
     AddReducer(data, &graph_reducer, &vn_reducer);
     AddReducer(data, &graph_reducer, &simple_reducer);
@@ -744,7 +776,7 @@ struct JumpThreadingPhase {
   static const char* phase_name() { return "jump threading"; }
 
   void Run(PipelineData* data, Zone* temp_zone) {
-    ZoneVector<BasicBlock::RpoNumber> result(temp_zone);
+    ZoneVector<RpoNumber> result(temp_zone);
     if (JumpThreading::ComputeForwarding(temp_zone, result, data->sequence())) {
       JumpThreading::ApplyForwarding(result, data->sequence());
     }
@@ -835,11 +867,10 @@ Handle<Code> Pipeline::GenerateCode() {
   // the correct solution is to restore the context register after invoking
   // builtins from full-codegen.
   Handle<SharedFunctionInfo> shared = info()->shared_info();
-  if (isolate()->bootstrapper()->IsActive() ||
-      shared->disable_optimization_reason() ==
-          kBuiltinFunctionCannotBeOptimized) {
-    shared->DisableOptimization(kBuiltinFunctionCannotBeOptimized);
-    return Handle<Code>::null();
+  for (int i = 0; i < Builtins::NumberOfJavaScriptBuiltins(); i++) {
+    Builtins::JavaScript id = static_cast<Builtins::JavaScript>(i);
+    Object* builtin = isolate()->js_builtins_object()->javascript_builtin(id);
+    if (*info()->closure() == builtin) return Handle<Code>::null();
   }
 
   // TODO(dslomov): support turbo optimization of subclass constructors.
@@ -885,6 +916,11 @@ Handle<Code> Pipeline::GenerateCode() {
   PipelineData data(&zone_pool, info(), pipeline_statistics.get());
   this->data_ = &data;
 
+  if (info()->is_type_feedback_enabled()) {
+    data.set_js_type_feedback(new (data.graph_zone())
+                                  JSTypeFeedbackTable(data.graph_zone()));
+  }
+
   BeginPhaseKind("graph creation");
 
   if (FLAG_trace_turbo) {
@@ -915,7 +951,7 @@ Handle<Code> Pipeline::GenerateCode() {
     RunPrintAndVerify("Context specialized", true);
   }
 
-  if (info()->is_inlining_enabled()) {
+  if (info()->is_builtin_inlining_enabled() || info()->is_inlining_enabled()) {
     Run<InliningPhase>();
     RunPrintAndVerify("Inlined", true);
   }
@@ -952,19 +988,24 @@ Handle<Code> Pipeline::GenerateCode() {
       RunPrintAndVerify("OSR deconstruction");
     }
 
+    if (info()->is_type_feedback_enabled()) {
+      Run<JSTypeFeedbackPhase>();
+      RunPrintAndVerify("JSType feedback");
+    }
+
     // Lower simplified operators and insert changes.
     Run<SimplifiedLoweringPhase>();
     RunPrintAndVerify("Lowered simplified");
 
     // Optimize control flow.
-    if (FLAG_turbo_switch) {
+    if (FLAG_turbo_cf_optimization) {
       Run<ControlFlowOptimizationPhase>();
       RunPrintAndVerify("Control flow optimized");
     }
 
     // Lower changes that have been inserted before.
     Run<ChangeLoweringPhase>();
-    // // TODO(jarin, rossberg): Remove UNTYPED once machine typing works.
+    // TODO(jarin, rossberg): Remove UNTYPED once machine typing works.
     RunPrintAndVerify("Lowered changes", true);
 
     Run<LateControlReductionPhase>();
diff --git a/deps/v8/src/compiler/ppc/OWNERS b/deps/v8/src/compiler/ppc/OWNERS
new file mode 100644 (file)
index 0000000..beecb3d
--- /dev/null
@@ -0,0 +1,3 @@
+joransiu@ca.ibm.com
+mbrandy@us.ibm.com
+michael_dawson@ca.ibm.com
index 467d035..c619833 100644 (file)
@@ -52,7 +52,7 @@ class PPCOperandConverter FINAL : public InstructionOperandConverter {
     return false;
   }
 
-  Operand InputImmediate(int index) {
+  Operand InputImmediate(size_t index) {
     Constant constant = ToConstant(instr_->InputAt(index));
     switch (constant.type()) {
       case Constant::kInt32:
@@ -76,8 +76,8 @@ class PPCOperandConverter FINAL : public InstructionOperandConverter {
     return Operand::Zero();
   }
 
-  MemOperand MemoryOperand(AddressingMode* mode, int* first_index) {
-    const int index = *first_index;
+  MemOperand MemoryOperand(AddressingMode* mode, size_t* first_index) {
+    const size_t index = *first_index;
     *mode = AddressingModeField::decode(instr_->opcode());
     switch (*mode) {
       case kMode_None:
@@ -93,7 +93,7 @@ class PPCOperandConverter FINAL : public InstructionOperandConverter {
     return MemOperand(r0);
   }
 
-  MemOperand MemoryOperand(AddressingMode* mode, int first_index = 0) {
+  MemOperand MemoryOperand(AddressingMode* mode, size_t first_index = 0) {
     return MemoryOperand(mode, &first_index);
   }
 
@@ -109,7 +109,7 @@ class PPCOperandConverter FINAL : public InstructionOperandConverter {
 };
 
 
-static inline bool HasRegisterInput(Instruction* instr, int index) {
+static inline bool HasRegisterInput(Instruction* instr, size_t index) {
   return instr->InputAt(index)->IsRegister();
 }
 
@@ -339,6 +339,22 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
   } while (0)
 
 
+#define ASSEMBLE_FLOAT_MAX(scratch_reg)                                       \
+  do {                                                                        \
+    __ fsub(scratch_reg, i.InputDoubleRegister(0), i.InputDoubleRegister(1)); \
+    __ fsel(i.OutputDoubleRegister(), scratch_reg, i.InputDoubleRegister(0),  \
+            i.InputDoubleRegister(1));                                        \
+  } while (0)
+
+
+#define ASSEMBLE_FLOAT_MIN(scratch_reg)                                       \
+  do {                                                                        \
+    __ fsub(scratch_reg, i.InputDoubleRegister(0), i.InputDoubleRegister(1)); \
+    __ fsel(i.OutputDoubleRegister(), scratch_reg, i.InputDoubleRegister(1),  \
+            i.InputDoubleRegister(0));                                        \
+  } while (0)
+
+
 #define ASSEMBLE_LOAD_FLOAT(asm_instr, asm_instrx)    \
   do {                                                \
     DoubleRegister result = i.OutputDoubleRegister(); \
@@ -369,7 +385,7 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
 
 #define ASSEMBLE_STORE_FLOAT(asm_instr, asm_instrx)      \
   do {                                                   \
-    int index = 0;                                       \
+    size_t index = 0;                                    \
     AddressingMode mode = kMode_None;                    \
     MemOperand operand = i.MemoryOperand(&mode, &index); \
     DoubleRegister value = i.InputDoubleRegister(index); \
@@ -384,7 +400,7 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
 
 #define ASSEMBLE_STORE_INTEGER(asm_instr, asm_instrx)    \
   do {                                                   \
-    int index = 0;                                       \
+    size_t index = 0;                                    \
     AddressingMode mode = kMode_None;                    \
     MemOperand operand = i.MemoryOperand(&mode, &index); \
     Register value = i.InputRegister(index);             \
@@ -401,8 +417,9 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
 #define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr, asm_instrx, width)  \
   do {                                                             \
     DoubleRegister result = i.OutputDoubleRegister();              \
+    size_t index = 0;                                              \
     AddressingMode mode = kMode_None;                              \
-    MemOperand operand = i.MemoryOperand(&mode, 0);                \
+    MemOperand operand = i.MemoryOperand(&mode, index);            \
     DCHECK_EQ(kMode_MRR, mode);                                    \
     Register offset = operand.rb();                                \
     __ extsw(offset, offset);                                      \
@@ -427,8 +444,9 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr, asm_instrx) \
   do {                                                       \
     Register result = i.OutputRegister();                    \
+    size_t index = 0;                                        \
     AddressingMode mode = kMode_None;                        \
-    MemOperand operand = i.MemoryOperand(&mode, 0);          \
+    MemOperand operand = i.MemoryOperand(&mode, index);      \
     DCHECK_EQ(kMode_MRR, mode);                              \
     Register offset = operand.rb();                          \
     __ extsw(offset, offset);                                \
@@ -453,8 +471,9 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
 #define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr, asm_instrx) \
   do {                                                      \
     Label done;                                             \
+    size_t index = 0;                                       \
     AddressingMode mode = kMode_None;                       \
-    MemOperand operand = i.MemoryOperand(&mode, 0);         \
+    MemOperand operand = i.MemoryOperand(&mode, index);     \
     DCHECK_EQ(kMode_MRR, mode);                             \
     Register offset = operand.rb();                         \
     __ extsw(offset, offset);                               \
@@ -479,8 +498,9 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr, asm_instrx) \
   do {                                                        \
     Label done;                                               \
+    size_t index = 0;                                         \
     AddressingMode mode = kMode_None;                         \
-    MemOperand operand = i.MemoryOperand(&mode, 0);           \
+    MemOperand operand = i.MemoryOperand(&mode, index);       \
     DCHECK_EQ(kMode_MRR, mode);                               \
     Register offset = operand.rb();                           \
     __ extsw(offset, offset);                                 \
@@ -532,7 +552,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
                 RelocInfo::CODE_TARGET);
       }
-      AddSafepointAndDeopt(instr);
+      RecordCallPosition(instr);
       DCHECK_EQ(LeaveRC, i.OutputRCBit());
       break;
     }
@@ -548,7 +568,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       }
       __ LoadP(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
       __ Call(ip);
-      AddSafepointAndDeopt(instr);
+      RecordCallPosition(instr);
       DCHECK_EQ(LeaveRC, i.OutputRCBit());
       break;
     }
@@ -556,10 +576,24 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       AssembleArchJump(i.InputRpo(0));
       DCHECK_EQ(LeaveRC, i.OutputRCBit());
       break;
+    case kArchLookupSwitch:
+      AssembleArchLookupSwitch(instr);
+      DCHECK_EQ(LeaveRC, i.OutputRCBit());
+      break;
+    case kArchTableSwitch:
+      AssembleArchTableSwitch(instr);
+      DCHECK_EQ(LeaveRC, i.OutputRCBit());
+      break;
     case kArchNop:
       // don't emit code for nops.
       DCHECK_EQ(LeaveRC, i.OutputRCBit());
       break;
+    case kArchDeoptimize: {
+      int deopt_state_id =
+          BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
+      AssembleDeoptimizerCall(deopt_state_id, Deoptimizer::EAGER);
+      break;
+    }
     case kArchRet:
       AssembleReturn();
       DCHECK_EQ(LeaveRC, i.OutputRCBit());
@@ -781,6 +815,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kPPC_Neg64:
       __ neg(i.OutputRegister(), i.InputRegister(0), LeaveOE, i.OutputRCBit());
       break;
+    case kPPC_MaxFloat64:
+      ASSEMBLE_FLOAT_MAX(kScratchDoubleReg);
+      break;
+    case kPPC_MinFloat64:
+      ASSEMBLE_FLOAT_MIN(kScratchDoubleReg);
+      break;
     case kPPC_SqrtFloat64:
       ASSEMBLE_FLOAT_UNOP_RC(fsqrt);
       break;
@@ -799,6 +839,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kPPC_NegFloat64:
       ASSEMBLE_FLOAT_UNOP_RC(fneg);
       break;
+    case kPPC_Cntlz32:
+      __ cntlzw_(i.OutputRegister(), i.InputRegister(0));
+      DCHECK_EQ(LeaveRC, i.OutputRCBit());
+      break;
     case kPPC_Cmp32:
       ASSEMBLE_COMPARE(cmpw, cmplw);
       break;
@@ -885,6 +929,32 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ Move(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       DCHECK_EQ(LeaveRC, i.OutputRCBit());
       break;
+    case kPPC_Float64ExtractLowWord32:
+      __ MovDoubleLowToInt(i.OutputRegister(), i.InputDoubleRegister(0));
+      DCHECK_EQ(LeaveRC, i.OutputRCBit());
+      break;
+    case kPPC_Float64ExtractHighWord32:
+      __ MovDoubleHighToInt(i.OutputRegister(), i.InputDoubleRegister(0));
+      DCHECK_EQ(LeaveRC, i.OutputRCBit());
+      break;
+    case kPPC_Float64InsertLowWord32:
+      __ InsertDoubleLow(i.OutputDoubleRegister(), i.InputRegister(1), r0);
+      DCHECK_EQ(LeaveRC, i.OutputRCBit());
+      break;
+    case kPPC_Float64InsertHighWord32:
+      __ InsertDoubleHigh(i.OutputDoubleRegister(), i.InputRegister(1), r0);
+      DCHECK_EQ(LeaveRC, i.OutputRCBit());
+      break;
+    case kPPC_Float64Construct:
+#if V8_TARGET_ARCH_PPC64
+      __ MovInt64ComponentsToDouble(i.OutputDoubleRegister(),
+                                    i.InputRegister(0), i.InputRegister(1), r0);
+#else
+      __ MovInt64ToDouble(i.OutputDoubleRegister(), i.InputRegister(0),
+                          i.InputRegister(1));
+#endif
+      DCHECK_EQ(LeaveRC, i.OutputRCBit());
+      break;
     case kPPC_LoadWordU8:
       ASSEMBLE_LOAD_INTEGER(lbz, lbzx);
       break;
@@ -1008,7 +1078,7 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
 }
 
 
-void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+void CodeGenerator::AssembleArchJump(RpoNumber target) {
   if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
 }
 
@@ -1075,32 +1145,53 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
 }
 
 
-void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
+void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
+  PPCOperandConverter i(this, instr);
+  Register input = i.InputRegister(0);
+  for (size_t index = 2; index < instr->InputCount(); index += 2) {
+    __ Cmpi(input, Operand(i.InputInt32(index + 0)), r0);
+    __ beq(GetLabel(i.InputRpo(index + 1)));
+  }
+  AssembleArchJump(i.InputRpo(1));
+}
+
+
+void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
+  PPCOperandConverter i(this, instr);
+  Register input = i.InputRegister(0);
+  int32_t const case_count = static_cast<int32_t>(instr->InputCount() - 2);
+  Label** cases = zone()->NewArray<Label*>(case_count);
+  for (int32_t index = 0; index < case_count; ++index) {
+    cases[index] = GetLabel(i.InputRpo(index + 2));
+  }
+  Label* const table = AddJumpTable(cases, case_count);
+  __ Cmpli(input, Operand(case_count), r0);
+  __ bge(GetLabel(i.InputRpo(1)));
+  __ mov_label_addr(kScratchReg, table);
+  __ ShiftLeftImm(r0, input, Operand(kPointerSizeLog2));
+  __ LoadPX(kScratchReg, MemOperand(kScratchReg, r0));
+  __ Jump(kScratchReg);
+}
+
+
+void CodeGenerator::AssembleDeoptimizerCall(
+    int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
-      isolate(), deoptimization_id, Deoptimizer::LAZY);
+      isolate(), deoptimization_id, bailout_type);
   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
 }
 
 
 void CodeGenerator::AssemblePrologue() {
   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
+  int stack_slots = frame()->GetSpillSlotCount();
   if (descriptor->kind() == CallDescriptor::kCallAddress) {
-#if ABI_USES_FUNCTION_DESCRIPTORS
     __ function_descriptor();
-#endif
     int register_save_area_size = 0;
     RegList frame_saves = fp.bit();
     __ mflr(r0);
-#if V8_OOL_CONSTANT_POOL
-    __ Push(r0, fp, kConstantPoolRegister);
-    // Adjust FP to point to saved FP.
-    __ subi(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset));
-    register_save_area_size += kPointerSize;
-    frame_saves |= kConstantPoolRegister.bit();
-#else
     __ Push(r0, fp);
     __ mr(fp, sp);
-#endif
     // Save callee-saved registers.
     const RegList saves = descriptor->CalleeSavedRegisters() & ~frame_saves;
     for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
@@ -1114,12 +1205,11 @@ void CodeGenerator::AssemblePrologue() {
     __ Prologue(info->IsCodePreAgingActive());
     frame()->SetRegisterSaveAreaSize(
         StandardFrameConstants::kFixedFrameSizeFromFp);
-  } else {
+  } else if (stack_slots > 0) {
     __ StubPrologue();
     frame()->SetRegisterSaveAreaSize(
         StandardFrameConstants::kFixedFrameSizeFromFp);
   }
-  int stack_slots = frame()->GetSpillSlotCount();
 
   if (info()->is_osr()) {
     // TurboFan OSR-compiled functions cannot be entered directly.
@@ -1131,6 +1221,8 @@ void CodeGenerator::AssemblePrologue() {
     // remaining stack slots.
     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
     osr_pc_offset_ = __ pc_offset();
+    // TODO(titzer): cannot address target function == local #-1
+    __ LoadP(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
     DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
     stack_slots -= frame()->GetOsrStackSlotCount();
   }
@@ -1143,18 +1235,15 @@ void CodeGenerator::AssemblePrologue() {
 
 void CodeGenerator::AssembleReturn() {
   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
+  int stack_slots = frame()->GetSpillSlotCount();
   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) {
         __ Add(sp, sp, stack_slots * kPointerSize, r0);
       }
       // Restore registers.
       RegList frame_saves = fp.bit();
-#if V8_OOL_CONSTANT_POOL
-      frame_saves |= kConstantPoolRegister.bit();
-#endif
       const RegList saves = descriptor->CalleeSavedRegisters() & ~frame_saves;
       if (saves != 0) {
         __ MultiPop(saves);
@@ -1162,12 +1251,14 @@ void CodeGenerator::AssembleReturn() {
     }
     __ LeaveFrame(StackFrame::MANUAL);
     __ Ret();
-  } else {
+  } else if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
     int pop_count = descriptor->IsJSFunctionCall()
                         ? static_cast<int>(descriptor->JSParameterCount())
                         : 0;
     __ LeaveFrame(StackFrame::MANUAL, pop_count * kPointerSize);
     __ Ret();
+  } else {
+    __ Ret();
   }
 }
 
@@ -1289,8 +1380,8 @@ void CodeGenerator::AssembleSwap(InstructionOperand* source,
   } else if (source->IsStackSlot() || source->IsDoubleStackSlot()) {
 #else
   } else if (source->IsStackSlot()) {
-#endif
     DCHECK(destination->IsStackSlot());
+#endif
     Register temp_0 = kScratchReg;
     Register temp_1 = r0;
     MemOperand src = g.ToMemOperand(source);
@@ -1333,6 +1424,13 @@ void CodeGenerator::AssembleSwap(InstructionOperand* source,
 }
 
 
+void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
+  for (size_t index = 0; index < target_count; ++index) {
+    __ emit_label_addr(targets[index]);
+  }
+}
+
+
 void CodeGenerator::AddNopForSmiCodeInlining() {
   // We do not insert nops for inlined Smi code.
 }
index 715a904..bb0a771 100644 (file)
@@ -67,6 +67,9 @@ namespace compiler {
   V(PPC_CeilFloat64)               \
   V(PPC_TruncateFloat64)           \
   V(PPC_RoundFloat64)              \
+  V(PPC_MaxFloat64)                \
+  V(PPC_MinFloat64)                \
+  V(PPC_Cntlz32)                   \
   V(PPC_Cmp32)                     \
   V(PPC_Cmp64)                     \
   V(PPC_CmpFloat64)                \
@@ -84,6 +87,11 @@ namespace compiler {
   V(PPC_Float64ToInt32)            \
   V(PPC_Float64ToUint32)           \
   V(PPC_Float64ToFloat32)          \
+  V(PPC_Float64ExtractLowWord32)   \
+  V(PPC_Float64ExtractHighWord32)  \
+  V(PPC_Float64InsertLowWord32)    \
+  V(PPC_Float64InsertHighWord32)   \
+  V(PPC_Float64Construct)          \
   V(PPC_LoadWordS8)                \
   V(PPC_LoadWordU8)                \
   V(PPC_LoadWordS16)               \
index 6d39df6..ae4c97a 100644 (file)
@@ -132,9 +132,8 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
   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();
+  selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
+                 inputs);
 }
 
 
@@ -737,6 +736,12 @@ void InstructionSelector::VisitWord64Ror(Node* node) {
 #endif
 
 
+void InstructionSelector::VisitWord32Clz(Node* node) {
+  PPCOperandGenerator g(this);
+  Emit(kPPC_Cntlz32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitInt32Add(Node* node) {
   VisitBinop<Int32BinopMatcher>(this, node, kPPC_Add32, kInt16Imm);
 }
@@ -925,6 +930,21 @@ void InstructionSelector::VisitFloat64Add(Node* node) {
 
 void InstructionSelector::VisitFloat64Sub(Node* node) {
   // TODO(mbrandy): detect multiply-subtract
+  PPCOperandGenerator g(this);
+  Float64BinopMatcher m(node);
+  if (m.left().IsMinusZero() && m.right().IsFloat64RoundDown() &&
+      CanCover(m.node(), m.right().node())) {
+    if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
+        CanCover(m.right().node(), m.right().InputAt(0))) {
+      Float64BinopMatcher mright0(m.right().InputAt(0));
+      if (mright0.left().IsMinusZero()) {
+        // -floor(-x) = ceil(x)
+        Emit(kPPC_CeilFloat64, g.DefineAsRegister(node),
+             g.UseRegister(mright0.right().node()));
+        return;
+      }
+    }
+  }
   VisitRRRFloat64(this, node, kPPC_SubFloat64);
 }
 
@@ -948,18 +968,23 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
 }
 
 
-void InstructionSelector::VisitFloat64Sqrt(Node* node) {
-  VisitRRFloat64(this, kPPC_SqrtFloat64, node);
+void InstructionSelector::VisitFloat64Max(Node* node) {
+  VisitRRRFloat64(this, node, kPPC_MaxFloat64);
 }
 
 
-void InstructionSelector::VisitFloat64Floor(Node* node) {
-  VisitRRFloat64(this, kPPC_FloorFloat64, node);
+void InstructionSelector::VisitFloat64Min(Node* node) {
+  VisitRRRFloat64(this, node, kPPC_MinFloat64);
 }
 
 
-void InstructionSelector::VisitFloat64Ceil(Node* node) {
-  VisitRRFloat64(this, kPPC_CeilFloat64, node);
+void InstructionSelector::VisitFloat64Sqrt(Node* node) {
+  VisitRRFloat64(this, kPPC_SqrtFloat64, node);
+}
+
+
+void InstructionSelector::VisitFloat64RoundDown(Node* node) {
+  VisitRRFloat64(this, kPPC_FloorFloat64, node);
 }
 
 
@@ -1020,8 +1045,7 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
   opcode = cont->Encode(opcode);
   if (cont->IsBranch()) {
     selector->Emit(opcode, g.NoOutput(), left, right,
-                   g.Label(cont->true_block()),
-                   g.Label(cont->false_block()))->MarkAsControl();
+                   g.Label(cont->true_block()), g.Label(cont->false_block()));
   } else {
     DCHECK(cont->IsSet());
     selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
@@ -1111,19 +1135,9 @@ static void VisitWordCompareZero(InstructionSelector* selector, Node* user,
         cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
         return VisitWord32Compare(selector, value, cont);
 #if V8_TARGET_ARCH_PPC64
-      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;
-        }
+      case IrOpcode::kWord64Equal:
         cont->OverwriteAndNegateIfEqual(kEqual);
         return VisitWord64Compare(selector, value, cont);
-      }
       case IrOpcode::kInt64LessThan:
         cont->OverwriteAndNegateIfEqual(kSignedLessThan);
         return VisitWord64Compare(selector, value, cont);
@@ -1235,6 +1249,34 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
 }
 
 
+void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
+  PPCOperandGenerator g(this);
+  InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
+
+  // Emit either ArchTableSwitch or ArchLookupSwitch.
+  size_t table_space_cost = 4 + sw.value_range;
+  size_t table_time_cost = 3;
+  size_t lookup_space_cost = 3 + 2 * sw.case_count;
+  size_t lookup_time_cost = sw.case_count;
+  if (sw.case_count > 0 &&
+      table_space_cost + 3 * table_time_cost <=
+          lookup_space_cost + 3 * lookup_time_cost &&
+      sw.min_value > std::numeric_limits<int32_t>::min()) {
+    InstructionOperand index_operand = value_operand;
+    if (sw.min_value) {
+      index_operand = g.TempRegister();
+      Emit(kPPC_Sub32, index_operand, value_operand,
+           g.TempImmediate(sw.min_value));
+    }
+    // Generate a table lookup.
+    return EmitTableSwitch(sw, index_operand);
+  }
+
+  // Generate a sequence of conditional jumps.
+  return EmitLookupSwitch(sw, value_operand);
+}
+
+
 void InstructionSelector::VisitWord32Equal(Node* const node) {
   FlagsContinuation cont(kEqual, node);
   Int32BinopMatcher m(node);
@@ -1317,7 +1359,7 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
 }
 
 
-void InstructionSelector::VisitCall(Node* node) {
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
   PPCOperandGenerator g(this);
   const CallDescriptor* descriptor = OpParameter<CallDescriptor*>(node);
 
@@ -1342,6 +1384,13 @@ void InstructionSelector::VisitCall(Node* node) {
     Emit(kPPC_Push, g.NoOutput(), g.UseRegister(*i));
   }
 
+  // Pass label of exception handler block.
+  CallDescriptor::Flags flags = descriptor->flags();
+  if (handler != nullptr) {
+    flags |= CallDescriptor::kHasExceptionHandler;
+    buffer.instruction_args.push_back(g.Label(handler));
+  }
+
   // Select the appropriate opcode based on the call type.
   InstructionCode opcode;
   switch (descriptor->kind()) {
@@ -1356,7 +1405,7 @@ void InstructionSelector::VisitCall(Node* node) {
       UNREACHABLE();
       return;
   }
-  opcode |= MiscField::encode(descriptor->flags());
+  opcode |= MiscField::encode(flags);
 
   // Emit the call instruction.
   InstructionOperand* first_output =
@@ -1368,11 +1417,58 @@ void InstructionSelector::VisitCall(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
+  PPCOperandGenerator g(this);
+  Emit(kPPC_Float64ExtractLowWord32, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
+  PPCOperandGenerator g(this);
+  Emit(kPPC_Float64ExtractHighWord32, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
+  PPCOperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 &&
+      CanCover(node, left)) {
+    left = left->InputAt(1);
+    Emit(kPPC_Float64Construct, g.DefineAsRegister(node), g.UseRegister(left),
+         g.UseRegister(right));
+    return;
+  }
+  Emit(kPPC_Float64InsertLowWord32, g.DefineSameAsFirst(node),
+       g.UseRegister(left), g.UseRegister(right));
+}
+
+
+void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
+  PPCOperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 &&
+      CanCover(node, left)) {
+    left = left->InputAt(1);
+    Emit(kPPC_Float64Construct, g.DefineAsRegister(node), g.UseRegister(right),
+         g.UseRegister(left));
+    return;
+  }
+  Emit(kPPC_Float64InsertHighWord32, g.DefineSameAsFirst(node),
+       g.UseRegister(left), g.UseRegister(right));
+}
+
+
 // static
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
-  return MachineOperatorBuilder::kFloat64Floor |
-         MachineOperatorBuilder::kFloat64Ceil |
+  return MachineOperatorBuilder::kFloat64Max |
+         MachineOperatorBuilder::kFloat64Min |
+         MachineOperatorBuilder::kFloat64RoundDown |
          MachineOperatorBuilder::kFloat64RoundTruncate |
          MachineOperatorBuilder::kFloat64RoundTiesAway;
   // We omit kWord32ShiftIsSafe as s[rl]w use 0x3f as a mask rather than 0x1f.
index 3811722..39ebb63 100644 (file)
@@ -53,9 +53,10 @@ CallDescriptor* Linkage::GetRuntimeCallDescriptor(
 CallDescriptor* Linkage::GetStubCallDescriptor(
     Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
     int stack_parameter_count, CallDescriptor::Flags flags,
-    Operator::Properties properties) {
+    Operator::Properties properties, MachineType return_type) {
   return LH::GetStubCallDescriptor(isolate, zone, descriptor,
-                                   stack_parameter_count, flags, properties);
+                                   stack_parameter_count, flags, properties,
+                                   return_type);
 }
 
 
index 04b1dc6..bcc9680 100644 (file)
@@ -90,6 +90,9 @@ class RawMachineAssembler : public GraphBuilder {
     Unique<HeapObject> val = Unique<HeapObject>::CreateUninitialized(object);
     return NewNode(common()->HeapConstant(val));
   }
+  Node* ExternalConstant(ExternalReference address) {
+    return NewNode(common()->ExternalConstant(address));
+  }
 
   Node* Projection(int index, Node* a) {
     return NewNode(common()->Projection(index), a);
@@ -97,14 +100,14 @@ class RawMachineAssembler : public GraphBuilder {
 
   // Memory Operations.
   Node* Load(MachineType rep, Node* base) {
-    return Load(rep, base, Int32Constant(0));
+    return Load(rep, base, IntPtrConstant(0));
   }
   Node* Load(MachineType rep, Node* base, Node* 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);
+    Store(rep, base, IntPtrConstant(0), value);
   }
   void Store(MachineType rep, Node* base, Node* index, Node* value) {
     NewNode(machine()->Store(StoreRepresentation(rep, kNoWriteBarrier)), base,
@@ -172,6 +175,7 @@ class RawMachineAssembler : public GraphBuilder {
   Node* Word32Ror(Node* a, Node* b) {
     return NewNode(machine()->Word32Ror(), a, b);
   }
+  Node* Word32Clz(Node* a) { return NewNode(machine()->Word32Clz(), a); }
   Node* Word32Equal(Node* a, Node* b) {
     return NewNode(machine()->Word32Equal(), a, b);
   }
@@ -281,6 +285,9 @@ class RawMachineAssembler : public GraphBuilder {
   Node* Int64LessThan(Node* a, Node* b) {
     return NewNode(machine()->Int64LessThan(), a, b);
   }
+  Node* Uint64LessThan(Node* a, Node* b) {
+    return NewNode(machine()->Uint64LessThan(), a, b);
+  }
   Node* Int64LessThanOrEqual(Node* a, Node* b) {
     return NewNode(machine()->Int64LessThanOrEqual(), a, b);
   }
@@ -384,8 +391,9 @@ class RawMachineAssembler : public GraphBuilder {
   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* Float64RoundDown(Node* a) {
+    return NewNode(machine()->Float64RoundDown(), a);
+  }
   Node* Float64RoundTruncate(Node* a) {
     return NewNode(machine()->Float64RoundTruncate(), a);
   }
@@ -393,6 +401,23 @@ class RawMachineAssembler : public GraphBuilder {
     return NewNode(machine()->Float64RoundTiesAway(), a);
   }
 
+  // Float64 bit operations.
+  Node* Float64ExtractLowWord32(Node* a) {
+    return NewNode(machine()->Float64ExtractLowWord32(), a);
+  }
+  Node* Float64ExtractHighWord32(Node* a) {
+    return NewNode(machine()->Float64ExtractHighWord32(), a);
+  }
+  Node* Float64InsertLowWord32(Node* a, Node* b) {
+    return NewNode(machine()->Float64InsertLowWord32(), a, b);
+  }
+  Node* Float64InsertHighWord32(Node* a, Node* b) {
+    return NewNode(machine()->Float64InsertHighWord32(), a, b);
+  }
+
+  // Stack operations.
+  Node* LoadStackPointer() { return NewNode(machine()->LoadStackPointer()); }
+
   // Parameters.
   Node* Parameter(size_t index);
 
index 434e965..c57591d 100644 (file)
@@ -162,6 +162,13 @@ void RegisterAllocatorVerifier::BuildConstraint(const InstructionOperand* op,
             constraint->type_ = kRegister;
           }
           break;
+        case UnallocatedOperand::MUST_HAVE_SLOT:
+          if (sequence()->IsDouble(vreg)) {
+            constraint->type_ = kDoubleSlot;
+          } else {
+            constraint->type_ = kSlot;
+          }
+          break;
         case UnallocatedOperand::SAME_AS_FIRST_INPUT:
           constraint->type_ = kSameAsFirst;
           break;
@@ -200,6 +207,12 @@ void RegisterAllocatorVerifier::CheckConstraint(
       CHECK(op->IsStackSlot());
       CHECK_EQ(op->index(), constraint->value_);
       return;
+    case kSlot:
+      CHECK(op->IsStackSlot());
+      return;
+    case kDoubleSlot:
+      CHECK(op->IsDoubleStackSlot());
+      return;
     case kNone:
       CHECK(op->IsRegister() || op->IsStackSlot());
       return;
@@ -214,7 +227,7 @@ void RegisterAllocatorVerifier::CheckConstraint(
 
 namespace {
 
-typedef BasicBlock::RpoNumber Rpo;
+typedef RpoNumber Rpo;
 
 static const int kInvalidVreg = InstructionOperand::kInvalidVirtualRegister;
 
@@ -245,8 +258,7 @@ class PhiMap : public ZoneMap<int, PhiData*>, public ZoneObject {
 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();
+    return *a < *b;
   }
 };
 
@@ -302,7 +314,10 @@ class OperandMap : public ZoneObject {
       if (i->IsEliminated()) continue;
       auto cur = map().find(i->source());
       CHECK(cur != map().end());
-      to_insert.insert(std::make_pair(i->destination(), cur->second));
+      auto res =
+          to_insert.insert(std::make_pair(i->destination(), cur->second));
+      // Ensure injectivity of moves.
+      CHECK(res.second);
     }
     // Drop current mappings.
     for (auto i = moves->begin(); i != moves->end(); ++i) {
index 86fda16..074e299 100644 (file)
@@ -30,6 +30,8 @@ class RegisterAllocatorVerifier FINAL : public ZoneObject {
     kFixedRegister,
     kDoubleRegister,
     kFixedDoubleRegister,
+    kSlot,
+    kDoubleSlot,
     kFixedSlot,
     kNone,
     kNoneDouble,
index 1de5773..20fae0c 100644 (file)
@@ -10,6 +10,11 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
+#define TRACE(...)                             \
+  do {                                         \
+    if (FLAG_trace_alloc) PrintF(__VA_ARGS__); \
+  } while (false)
+
 static inline LifetimePosition Min(LifetimePosition a, LifetimePosition b) {
   return a.Value() < b.Value() ? a : b;
 }
@@ -20,16 +25,6 @@ static inline LifetimePosition Max(LifetimePosition a, LifetimePosition b) {
 }
 
 
-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());
@@ -39,17 +34,22 @@ static void RemoveElement(ZoneVector<LiveRange*>* v, LiveRange* range) {
 
 UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand,
                          InstructionOperand* hint)
-    : operand_(operand),
-      hint_(hint),
-      pos_(pos),
-      next_(nullptr),
-      requires_reg_(false),
-      register_beneficial_(true) {
+    : operand_(operand), hint_(hint), pos_(pos), next_(nullptr), flags_(0) {
+  bool register_beneficial = true;
+  UsePositionType type = UsePositionType::kAny;
   if (operand_ != nullptr && operand_->IsUnallocated()) {
     const UnallocatedOperand* unalloc = UnallocatedOperand::cast(operand_);
-    requires_reg_ = unalloc->HasRegisterPolicy();
-    register_beneficial_ = !unalloc->HasAnyPolicy();
+    if (unalloc->HasRegisterPolicy()) {
+      type = UsePositionType::kRequiresRegister;
+    } else if (unalloc->HasSlotPolicy()) {
+      type = UsePositionType::kRequiresSlot;
+      register_beneficial = false;
+    } else {
+      register_beneficial = !unalloc->HasAnyPolicy();
+    }
   }
+  flags_ = TypeField::encode(type) |
+           RegisterBeneficialField::encode(register_beneficial);
   DCHECK(pos_.IsValid());
 }
 
@@ -59,10 +59,11 @@ bool UsePosition::HasHint() const {
 }
 
 
-bool UsePosition::RequiresRegister() const { return requires_reg_; }
-
-
-bool UsePosition::RegisterIsBeneficial() const { return register_beneficial_; }
+void UsePosition::set_type(UsePositionType type, bool register_beneficial) {
+  DCHECK_IMPLIES(type == UsePositionType::kRequiresSlot, !register_beneficial);
+  flags_ = TypeField::encode(type) |
+           RegisterBeneficialField::encode(register_beneficial);
+}
 
 
 void UseInterval::SplitAt(LifetimePosition pos, Zone* zone) {
@@ -117,6 +118,7 @@ bool LiveRange::HasOverlap(UseInterval* target) const {
 LiveRange::LiveRange(int id, Zone* zone)
     : id_(id),
       spilled_(false),
+      has_slot_use_(false),
       is_phi_(false),
       is_non_loop_phi_(false),
       kind_(UNALLOCATED_REGISTERS),
@@ -140,7 +142,7 @@ void LiveRange::set_assigned_register(int reg,
   DCHECK(!HasRegisterAssigned() && !IsSpilled());
   assigned_register_ = reg;
   // TODO(dcarney): stop aliasing hint operands.
-  ConvertUsesToOperand(GetAssignedOperand(operand_cache));
+  ConvertUsesToOperand(GetAssignedOperand(operand_cache), nullptr);
 }
 
 
@@ -161,16 +163,32 @@ void LiveRange::SpillAtDefinition(Zone* zone, int gap_index,
 
 
 void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence,
-                                         InstructionOperand* op) {
-  auto to_spill = TopLevel()->spills_at_definition_;
-  if (to_spill == nullptr) return;
+                                         InstructionOperand* op,
+                                         bool might_be_duplicated) {
+  DCHECK(!IsChild());
   auto zone = sequence->zone();
-  for (; to_spill != nullptr; to_spill = to_spill->next) {
+  for (auto to_spill = spills_at_definition_; to_spill != nullptr;
+       to_spill = to_spill->next) {
     auto gap = sequence->GapAt(to_spill->gap_index);
     auto move = gap->GetOrCreateParallelMove(GapInstruction::START, zone);
+    // Skip insertion if it's possible that the move exists already as a
+    // constraint move from a fixed output register to a slot.
+    if (might_be_duplicated) {
+      bool found = false;
+      auto move_ops = move->move_operands();
+      for (auto move_op = move_ops->begin(); move_op != move_ops->end();
+           ++move_op) {
+        if (move_op->IsEliminated()) continue;
+        if (move_op->source()->Equals(to_spill->operand) &&
+            move_op->destination()->Equals(op)) {
+          found = true;
+          break;
+        }
+      }
+      if (found) continue;
+    }
     move->AddMove(to_spill->operand, op, zone);
   }
-  TopLevel()->spills_at_definition_ = nullptr;
 }
 
 
@@ -234,7 +252,7 @@ UsePosition* LiveRange::PreviousUsePositionRegisterIsBeneficial(
 
 UsePosition* LiveRange::NextRegisterPosition(LifetimePosition start) {
   UsePosition* pos = NextUsePosition(start);
-  while (pos != nullptr && !pos->RequiresRegister()) {
+  while (pos != nullptr && pos->type() != UsePositionType::kRequiresRegister) {
     pos = pos->next();
   }
   return pos;
@@ -424,7 +442,7 @@ bool LiveRange::ShouldBeAllocatedBefore(const LiveRange* other) const {
 
 
 void LiveRange::ShortenTo(LifetimePosition start) {
-  TraceAlloc("Shorten live range %d to [%d\n", id_, start.Value());
+  TRACE("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());
@@ -434,8 +452,8 @@ void LiveRange::ShortenTo(LifetimePosition start) {
 
 void LiveRange::EnsureInterval(LifetimePosition start, LifetimePosition end,
                                Zone* zone) {
-  TraceAlloc("Ensure live range %d in interval [%d %d[\n", id_, start.Value(),
-             end.Value());
+  TRACE("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()) {
@@ -456,8 +474,8 @@ void LiveRange::EnsureInterval(LifetimePosition start, LifetimePosition end,
 
 void LiveRange::AddUseInterval(LifetimePosition start, LifetimePosition end,
                                Zone* zone) {
-  TraceAlloc("Add to live range %d interval [%d %d[\n", id_, start.Value(),
-             end.Value());
+  TRACE("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;
@@ -484,7 +502,7 @@ void LiveRange::AddUseInterval(LifetimePosition start, LifetimePosition end,
 void LiveRange::AddUsePosition(LifetimePosition pos,
                                InstructionOperand* operand,
                                InstructionOperand* hint, Zone* zone) {
-  TraceAlloc("Add to live range %d use position %d\n", id_, pos.Value());
+  TRACE("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;
@@ -509,18 +527,27 @@ void LiveRange::AddUsePosition(LifetimePosition pos,
 }
 
 
-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());
-
-    if (use_pos->HasOperand()) {
-      DCHECK(op->IsRegister() || op->IsDoubleRegister() ||
-             !use_pos->RequiresRegister());
-      use_pos->operand()->ConvertTo(op->kind(), op->index());
+void LiveRange::ConvertUsesToOperand(InstructionOperand* op,
+                                     InstructionOperand* spill_op) {
+  for (auto pos = first_pos(); pos != nullptr; pos = pos->next()) {
+    DCHECK(Start().Value() <= pos->pos().Value() &&
+           pos->pos().Value() <= End().Value());
+    if (!pos->HasOperand()) {
+      continue;
+    }
+    switch (pos->type()) {
+      case UsePositionType::kRequiresSlot:
+        if (spill_op != nullptr) {
+          pos->operand()->ConvertTo(spill_op->kind(), spill_op->index());
+        }
+        break;
+      case UsePositionType::kRequiresRegister:
+        DCHECK(op->IsRegister() || op->IsDoubleRegister());
+      // Fall through.
+      case UsePositionType::kAny:
+        pos->operand()->ConvertTo(op->kind(), op->index());
+        break;
     }
-    use_pos = use_pos->next();
   }
 }
 
@@ -679,7 +706,7 @@ int RegisterAllocator::FixedDoubleLiveRangeID(int index) {
 
 InstructionOperand* RegisterAllocator::AllocateFixed(
     UnallocatedOperand* operand, int pos, bool is_tagged) {
-  TraceAlloc("Allocating fixed reg for op %d\n", operand->virtual_register());
+  TRACE("Allocating fixed reg for op %d\n", operand->virtual_register());
   DCHECK(operand->HasFixedPolicy());
   if (operand->HasFixedSlotPolicy()) {
     operand->ConvertTo(InstructionOperand::STACK_SLOT,
@@ -694,7 +721,7 @@ InstructionOperand* RegisterAllocator::AllocateFixed(
     UNREACHABLE();
   }
   if (is_tagged) {
-    TraceAlloc("Fixed reg is tagged at %d\n", pos);
+    TRACE("Fixed reg is tagged at %d\n", pos);
     auto instr = InstructionAt(pos);
     if (instr->HasPointerMap()) {
       instr->pointer_map()->RecordPointer(operand, code_zone());
@@ -704,15 +731,19 @@ InstructionOperand* RegisterAllocator::AllocateFixed(
 }
 
 
+LiveRange* RegisterAllocator::NewLiveRange(int index) {
+  // The LiveRange object itself can go in the local zone, but the
+  // InstructionOperand needs to go in the code zone, since it may survive
+  // register allocation.
+  return new (local_zone()) LiveRange(index, code_zone());
+}
+
+
 LiveRange* RegisterAllocator::FixedLiveRangeFor(int index) {
   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 (local_zone()) LiveRange(FixedLiveRangeID(index), code_zone());
+    result = NewLiveRange(FixedLiveRangeID(index));
     DCHECK(result->IsFixed());
     result->kind_ = GENERAL_REGISTERS;
     SetLiveRangeAssignedRegister(result, index);
@@ -726,8 +757,7 @@ LiveRange* RegisterAllocator::FixedDoubleLiveRangeFor(int index) {
   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());
+    result = NewLiveRange(FixedDoubleLiveRangeID(index));
     DCHECK(result->IsFixed());
     result->kind_ = DOUBLE_REGISTERS;
     SetLiveRangeAssignedRegister(result, index);
@@ -743,7 +773,7 @@ LiveRange* RegisterAllocator::LiveRangeFor(int index) {
   }
   auto result = live_ranges()[index];
   if (result == nullptr) {
-    result = new (local_zone()) LiveRange(index, code_zone());
+    result = NewLiveRange(index);
     live_ranges()[index] = result;
   }
   return result;
@@ -957,12 +987,15 @@ void RegisterAllocator::AssignSpillSlots() {
 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->GetAssignedOperand(operand_cache());
-    range->ConvertUsesToOperand(assigned);
-    if (range->IsSpilled()) {
-      range->CommitSpillsAtDefinition(code(), assigned);
+    InstructionOperand* spill_operand = nullptr;
+    if (!range->TopLevel()->HasNoSpillType()) {
+      spill_operand = range->TopLevel()->GetSpillOperand();
+    }
+    range->ConvertUsesToOperand(assigned, spill_operand);
+    if (!range->IsChild() && spill_operand != nullptr) {
+      range->CommitSpillsAtDefinition(code(), spill_operand,
+                                      range->has_slot_use());
     }
   }
 }
@@ -977,7 +1010,7 @@ SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) {
 
 bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) {
   if (range->IsChild() || !range->is_phi()) return false;
-  DCHECK(range->HasNoSpillType());
+  DCHECK(!range->HasSpillOperand());
 
   auto lookup = phi_map_.find(range->id());
   DCHECK(lookup != phi_map_.end());
@@ -1040,12 +1073,16 @@ bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) {
   }
   auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos);
   if (pos == nullptr) {
-    auto spill_range = AssignSpillRangeToLiveRange(range->TopLevel());
+    auto spill_range = range->TopLevel()->HasSpillRange()
+                           ? range->TopLevel()->GetSpillRange()
+                           : 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());
+    auto spill_range = range->TopLevel()->HasSpillRange()
+                           ? range->TopLevel()->GetSpillRange()
+                           : AssignSpillRangeToLiveRange(range->TopLevel());
     CHECK(first_op_spill->TryMerge(spill_range));
     SpillBetween(range, range->Start(), pos->pos());
     DCHECK(UnhandledIsSorted());
@@ -1304,6 +1341,8 @@ void RegisterAllocator::ProcessInstructions(const InstructionBlock* block,
       for (size_t i = 0; i < instr->OutputCount(); i++) {
         auto output = instr->OutputAt(i);
         if (output->IsUnallocated()) {
+          // Unsupported.
+          DCHECK(!UnallocatedOperand::cast(output)->HasSlotPolicy());
           int out_vreg = UnallocatedOperand::cast(output)->virtual_register();
           live->Remove(out_vreg);
         } else if (output->IsConstant()) {
@@ -1344,14 +1383,22 @@ void RegisterAllocator::ProcessInstructions(const InstructionBlock* block,
           use_pos = curr_position.InstructionEnd();
         }
 
-        Use(block_start_position, use_pos, input, nullptr);
         if (input->IsUnallocated()) {
-          live->Add(UnallocatedOperand::cast(input)->virtual_register());
+          UnallocatedOperand* unalloc = UnallocatedOperand::cast(input);
+          int vreg = unalloc->virtual_register();
+          live->Add(vreg);
+          if (unalloc->HasSlotPolicy()) {
+            LiveRangeFor(vreg)->set_has_slot_use(true);
+          }
         }
+        Use(block_start_position, use_pos, input, nullptr);
       }
 
       for (size_t i = 0; i < instr->TempCount(); i++) {
         auto temp = instr->TempAt(i);
+        // Unsupported.
+        DCHECK_IMPLIES(temp->IsUnallocated(),
+                       !UnallocatedOperand::cast(temp)->HasSlotPolicy());
         if (instr->ClobbersTemps()) {
           if (temp->IsRegister()) continue;
           if (temp->IsUnallocated()) {
@@ -1415,22 +1462,6 @@ void RegisterAllocator::ResolvePhis() {
 }
 
 
-ParallelMove* RegisterAllocator::GetConnectingParallelMove(
-    LifetimePosition pos) {
-  int index = pos.InstructionIndex();
-  if (code()->IsGapAt(index)) {
-    auto gap = code()->GapAt(index);
-    return gap->GetOrCreateParallelMove(
-        pos.IsInstructionStart() ? GapInstruction::START : GapInstruction::END,
-        code_zone());
-  }
-  int gap_pos = pos.IsInstructionStart() ? (index - 1) : (index + 1);
-  return code()->GapAt(gap_pos)->GetOrCreateParallelMove(
-      (gap_pos < index) ? GapInstruction::AFTER : GapInstruction::START,
-      code_zone());
-}
-
-
 const InstructionBlock* RegisterAllocator::GetInstructionBlock(
     LifetimePosition pos) {
   return code()->GetInstructionBlock(pos.InstructionIndex());
@@ -1438,34 +1469,75 @@ const InstructionBlock* RegisterAllocator::GetInstructionBlock(
 
 
 void RegisterAllocator::ConnectRanges() {
+  ZoneMap<std::pair<ParallelMove*, InstructionOperand*>, InstructionOperand*>
+      delayed_insertion_map(local_zone());
   for (auto first_range : live_ranges()) {
     if (first_range == nullptr || first_range->IsChild()) continue;
-    auto second_range = first_range->next();
-    while (second_range != nullptr) {
+    for (auto second_range = first_range->next(); second_range != nullptr;
+         first_range = second_range, second_range = second_range->next()) {
       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(GetInstructionBlock(pos));
-          }
-          if (should_insert) {
-            auto move = GetConnectingParallelMove(pos);
-            auto prev_operand =
-                first_range->GetAssignedOperand(operand_cache());
-            auto cur_operand =
-                second_range->GetAssignedOperand(operand_cache());
-            move->AddMove(prev_operand, cur_operand, code_zone());
-          }
-        }
+      // Add gap move if the two live ranges touch and there is no block
+      // boundary.
+      if (second_range->IsSpilled()) continue;
+      if (first_range->End().Value() != pos.Value()) continue;
+      if (IsBlockBoundary(pos) &&
+          !CanEagerlyResolveControlFlow(GetInstructionBlock(pos))) {
+        continue;
+      }
+      auto prev_operand = first_range->GetAssignedOperand(operand_cache());
+      auto cur_operand = second_range->GetAssignedOperand(operand_cache());
+      if (prev_operand->Equals(cur_operand)) continue;
+      int index = pos.InstructionIndex();
+      bool delay_insertion = false;
+      GapInstruction::InnerPosition gap_pos;
+      int gap_index = index;
+      if (code()->IsGapAt(index)) {
+        gap_pos = pos.IsInstructionStart() ? GapInstruction::START
+                                           : GapInstruction::END;
+      } else {
+        gap_index = pos.IsInstructionStart() ? (index - 1) : (index + 1);
+        delay_insertion = gap_index < index;
+        gap_pos = delay_insertion ? GapInstruction::END : GapInstruction::START;
+      }
+      auto move = code()->GapAt(gap_index)->GetOrCreateParallelMove(
+          gap_pos, code_zone());
+      if (!delay_insertion) {
+        move->AddMove(prev_operand, cur_operand, code_zone());
+      } else {
+        delayed_insertion_map.insert(
+            std::make_pair(std::make_pair(move, prev_operand), cur_operand));
       }
-      first_range = second_range;
-      second_range = second_range->next();
     }
   }
+  if (delayed_insertion_map.empty()) return;
+  // Insert all the moves which should occur after the stored move.
+  ZoneVector<MoveOperands> to_insert(local_zone());
+  ZoneVector<MoveOperands*> to_eliminate(local_zone());
+  to_insert.reserve(4);
+  to_eliminate.reserve(4);
+  auto move = delayed_insertion_map.begin()->first.first;
+  for (auto it = delayed_insertion_map.begin();; ++it) {
+    bool done = it == delayed_insertion_map.end();
+    if (done || it->first.first != move) {
+      // Commit the MoveOperands for current ParallelMove.
+      for (auto move_ops : to_eliminate) {
+        move_ops->Eliminate();
+      }
+      for (auto move_ops : to_insert) {
+        move->AddMove(move_ops.source(), move_ops.destination(), code_zone());
+      }
+      if (done) break;
+      // Reset state.
+      to_eliminate.clear();
+      to_insert.clear();
+      move = it->first.first;
+    }
+    // Gather all MoveOperands for a single ParallelMove.
+    MoveOperands move_ops(it->first.second, it->second);
+    auto eliminate = move->PrepareInsertAfter(&move_ops);
+    to_insert.push_back(move_ops);
+    if (eliminate != nullptr) to_eliminate.push_back(eliminate);
+  }
 }
 
 
@@ -1681,8 +1753,7 @@ void RegisterAllocator::BuildLiveRanges() {
   // Process the blocks in reverse order.
   for (int block_id = code()->InstructionBlockCount() - 1; block_id >= 0;
        --block_id) {
-    auto block =
-        code()->InstructionBlockAt(BasicBlock::RpoNumber::FromInt(block_id));
+    auto block = code()->InstructionBlockAt(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.
@@ -1749,20 +1820,25 @@ void RegisterAllocator::BuildLiveRanges() {
   for (auto range : live_ranges()) {
     if (range == nullptr) continue;
     range->kind_ = RequiredRegisterKind(range->id());
+    // Give slots to all ranges with a non fixed slot use.
+    if (range->has_slot_use() && range->HasNoSpillType()) {
+      AssignSpillRangeToLiveRange(range);
+    }
     // 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?
+        if (pos->type() == UsePositionType::kRequiresSlot) continue;
+        UsePositionType new_type = UsePositionType::kAny;
         // Can't mark phis as needing a register.
         if (!code()
                  ->InstructionAt(pos->pos().InstructionIndex())
                  ->IsGapMoves()) {
-          pos->requires_reg_ = true;
+          new_type = UsePositionType::kRequiresRegister;
         }
+        pos->set_type(new_type, true);
       }
     }
   }
@@ -1860,13 +1936,13 @@ void RegisterAllocator::PopulatePointerMaps() {
       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",
-                   range->id(), range->spill_start_index(), safe_point);
+        TRACE("Pointer for range %d (spilled at %d) at safe point %d\n",
+              range->id(), range->spill_start_index(), safe_point);
         map->RecordPointer(range->GetSpillOperand(), code_zone());
       }
 
       if (!cur->IsSpilled()) {
-        TraceAlloc(
+        TRACE(
             "Pointer in register for range %d (start at %d) "
             "at safe point %d\n",
             cur->id(), cur->Start().Value(), safe_point);
@@ -1933,11 +2009,10 @@ void RegisterAllocator::AllocateRegisters() {
 #ifdef DEBUG
     allocation_finger_ = position;
 #endif
-    TraceAlloc("Processing interval %d start=%d\n", current->id(),
-               position.Value());
+    TRACE("Processing interval %d start=%d\n", current->id(), position.Value());
 
     if (!current->HasNoSpillType()) {
-      TraceAlloc("Live range %d already has a spill operand\n", current->id());
+      TRACE("Live range %d already has a spill operand\n", current->id());
       auto next_pos = position;
       if (code()->IsGapAt(next_pos.InstructionIndex())) {
         next_pos = next_pos.NextInstruction();
@@ -2018,13 +2093,13 @@ RegisterKind RegisterAllocator::RequiredRegisterKind(
 
 
 void RegisterAllocator::AddToActive(LiveRange* range) {
-  TraceAlloc("Add live range %d to active\n", range->id());
+  TRACE("Add live range %d to active\n", range->id());
   active_live_ranges().push_back(range);
 }
 
 
 void RegisterAllocator::AddToInactive(LiveRange* range) {
-  TraceAlloc("Add live range %d to inactive\n", range->id());
+  TRACE("Add live range %d to inactive\n", range->id());
   inactive_live_ranges().push_back(range);
 }
 
@@ -2037,13 +2112,13 @@ void RegisterAllocator::AddToUnhandledSorted(LiveRange* range) {
        --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);
+    TRACE("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());
+  TRACE("Add live range %d to unhandled at start\n", range->id());
   unhandled_live_ranges().insert(unhandled_live_ranges().begin(), range);
   DCHECK(UnhandledIsSorted());
 }
@@ -2052,7 +2127,7 @@ void RegisterAllocator::AddToUnhandledSorted(LiveRange* range) {
 void RegisterAllocator::AddToUnhandledUnsorted(LiveRange* range) {
   if (range == nullptr || range->IsEmpty()) return;
   DCHECK(!range->HasRegisterAssigned() && !range->IsSpilled());
-  TraceAlloc("Add live range %d to unhandled unsorted at end\n", range->id());
+  TRACE("Add live range %d to unhandled unsorted at end\n", range->id());
   unhandled_live_ranges().push_back(range);
 }
 
@@ -2069,7 +2144,7 @@ static bool UnhandledSortHelper(LiveRange* a, LiveRange* b) {
 // at the end of the array list.  This is convenient for the register allocation
 // algorithm because it is efficient to remove elements from the end.
 void RegisterAllocator::SortUnhandled() {
-  TraceAlloc("Sort unhandled\n");
+  TRACE("Sort unhandled\n");
   std::sort(unhandled_live_ranges().begin(), unhandled_live_ranges().end(),
             &UnhandledSortHelper);
 }
@@ -2088,27 +2163,27 @@ bool RegisterAllocator::UnhandledIsSorted() {
 
 void RegisterAllocator::ActiveToHandled(LiveRange* range) {
   RemoveElement(&active_live_ranges(), range);
-  TraceAlloc("Moving live range %d from active to handled\n", range->id());
+  TRACE("Moving live range %d from active to handled\n", range->id());
 }
 
 
 void RegisterAllocator::ActiveToInactive(LiveRange* range) {
   RemoveElement(&active_live_ranges(), range);
   inactive_live_ranges().push_back(range);
-  TraceAlloc("Moving live range %d from active to inactive\n", range->id());
+  TRACE("Moving live range %d from active to inactive\n", range->id());
 }
 
 
 void RegisterAllocator::InactiveToHandled(LiveRange* range) {
   RemoveElement(&inactive_live_ranges(), range);
-  TraceAlloc("Moving live range %d from inactive to handled\n", range->id());
+  TRACE("Moving live range %d from inactive to handled\n", range->id());
 }
 
 
 void RegisterAllocator::InactiveToActive(LiveRange* range) {
   RemoveElement(&inactive_live_ranges(), range);
   active_live_ranges().push_back(range);
-  TraceAlloc("Moving live range %d from inactive to active\n", range->id());
+  TRACE("Moving live range %d from inactive to active\n", range->id());
 }
 
 
@@ -2135,15 +2210,14 @@ bool RegisterAllocator::TryAllocateFreeReg(LiveRange* current) {
   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",
-        RegisterName(register_index), free_until_pos[register_index].Value(),
-        current->id(), current->End().Value());
+    TRACE("Found reg hint %s (free until [%d) for live range %d (end %d[).\n",
+          RegisterName(register_index), free_until_pos[register_index].Value(),
+          current->id(), current->End().Value());
 
     // The desired register is free until the end of the current live range.
     if (free_until_pos[register_index].Value() >= current->End().Value()) {
-      TraceAlloc("Assigning preferred reg %s to live range %d\n",
-                 RegisterName(register_index), current->id());
+      TRACE("Assigning preferred reg %s to live range %d\n",
+            RegisterName(register_index), current->id());
       SetLiveRangeAssignedRegister(current, register_index);
       return true;
     }
@@ -2174,8 +2248,8 @@ bool RegisterAllocator::TryAllocateFreeReg(LiveRange* current) {
   // Register reg is available at the range start and is free until
   // the range end.
   DCHECK(pos.Value() >= current->End().Value());
-  TraceAlloc("Assigning free reg %s to live range %d\n", RegisterName(reg),
-             current->id());
+  TRACE("Assigning free reg %s to live range %d\n", RegisterName(reg),
+        current->id());
   SetLiveRangeAssignedRegister(current, reg);
 
   return true;
@@ -2253,8 +2327,8 @@ void RegisterAllocator::AllocateBlockedReg(LiveRange* current) {
 
   // Register reg is not blocked for the whole range.
   DCHECK(block_pos[reg].Value() >= current->End().Value());
-  TraceAlloc("Assigning blocked reg %s to live range %d\n", RegisterName(reg),
-             current->id());
+  TRACE("Assigning blocked reg %s to live range %d\n", RegisterName(reg),
+        current->id());
   SetLiveRangeAssignedRegister(current, reg);
 
   // This register was not free. Thus we need to find and spill
@@ -2362,14 +2436,15 @@ bool RegisterAllocator::IsBlockBoundary(LifetimePosition pos) {
 LiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range,
                                            LifetimePosition pos) {
   DCHECK(!range->IsFixed());
-  TraceAlloc("Splitting live range %d at %d\n", range->id(), pos.Value());
+  TRACE("Splitting live range %d at %d\n", range->id(), pos.Value());
 
   if (pos.Value() <= range->Start().Value()) return range;
 
-  // We can't properly connect liveranges if split occured at the end
-  // of control instruction.
+  // We can't properly connect liveranges if splitting occurred at the end
+  // a block.
   DCHECK(pos.IsInstructionStart() ||
-         !InstructionAt(pos.InstructionIndex())->IsControl());
+         (code()->GetInstructionBlock(pos.InstructionIndex()))
+                 ->last_instruction_index() != pos.InstructionIndex());
 
   int vreg = GetVirtualRegister();
   auto result = LiveRangeFor(vreg);
@@ -2382,8 +2457,8 @@ LiveRange* RegisterAllocator::SplitBetween(LiveRange* range,
                                            LifetimePosition start,
                                            LifetimePosition end) {
   DCHECK(!range->IsFixed());
-  TraceAlloc("Splitting live range %d in position between [%d, %d]\n",
-             range->id(), start.Value(), end.Value());
+  TRACE("Splitting live range %d in position between [%d, %d]\n", range->id(),
+        start.Value(), end.Value());
 
   auto split_pos = FindOptimalSplitPos(start, end);
   DCHECK(split_pos.Value() >= start.Value());
@@ -2472,7 +2547,7 @@ void RegisterAllocator::SpillBetweenUntil(LiveRange* range,
 
 void RegisterAllocator::Spill(LiveRange* range) {
   DCHECK(!range->IsSpilled());
-  TraceAlloc("Spilling live range %d\n", range->id());
+  TRACE("Spilling live range %d\n", range->id());
   auto first = range->TopLevel();
   if (first->HasNoSpillType()) {
     AssignSpillRangeToLiveRange(first);
index d7dd1b7..9ee778d 100644 (file)
@@ -141,6 +141,9 @@ class UseInterval FINAL : public ZoneObject {
 };
 
 
+enum class UsePositionType : uint8_t { kAny, kRequiresRegister, kRequiresSlot };
+
+
 // Representation of a use position.
 class UsePosition FINAL : public ZoneObject {
  public:
@@ -152,22 +155,27 @@ class UsePosition FINAL : public ZoneObject {
 
   InstructionOperand* hint() const { return hint_; }
   bool HasHint() const;
-  bool RequiresRegister() const;
-  bool RegisterIsBeneficial() const;
+  bool RegisterIsBeneficial() const {
+    return RegisterBeneficialField::decode(flags_);
+  }
+  UsePositionType type() const { return TypeField::decode(flags_); }
 
   LifetimePosition pos() const { return pos_; }
   UsePosition* next() const { return next_; }
 
   void set_next(UsePosition* next) { next_ = next; }
+  void set_type(UsePositionType type, bool register_beneficial);
 
   InstructionOperand* const operand_;
   InstructionOperand* const hint_;
   LifetimePosition const pos_;
   UsePosition* next_;
-  bool requires_reg_ : 1;
-  bool register_beneficial_ : 1;
 
  private:
+  typedef BitField8<UsePositionType, 0, 2> TypeField;
+  typedef BitField8<bool, 2, 1> RegisterBeneficialField;
+  uint8_t flags_;
+
   DISALLOW_COPY_AND_ASSIGN(UsePosition);
 };
 
@@ -233,6 +241,8 @@ class LiveRange FINAL : public ZoneObject {
   void set_is_non_loop_phi(bool is_non_loop_phi) {
     is_non_loop_phi_ = is_non_loop_phi;
   }
+  bool has_slot_use() const { return has_slot_use_; }
+  void set_has_slot_use(bool has_slot_use) { has_slot_use_ = has_slot_use; }
 
   // Returns use position in this live range that follows both start
   // and last processed use position.
@@ -309,7 +319,8 @@ class LiveRange FINAL : public ZoneObject {
   void SetSpillRange(SpillRange* spill_range);
   void CommitSpillOperand(InstructionOperand* operand);
   void CommitSpillsAtDefinition(InstructionSequence* sequence,
-                                InstructionOperand* operand);
+                                InstructionOperand* operand,
+                                bool might_be_duplicated);
 
   void SetSpillStartIndex(int start) {
     spill_start_index_ = Min(start, spill_start_index_);
@@ -338,16 +349,18 @@ class LiveRange FINAL : public ZoneObject {
  private:
   struct SpillAtDefinitionList;
 
-  void ConvertUsesToOperand(InstructionOperand* op);
+  void ConvertUsesToOperand(InstructionOperand* op,
+                            InstructionOperand* spill_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_;
-  bool is_non_loop_phi_;
+  bool spilled_ : 1;
+  bool has_slot_use_ : 1;  // Relevant only for parent.
+  bool is_phi_ : 1;
+  bool is_non_loop_phi_ : 1;
   RegisterKind kind_;
   int assigned_register_;
   UseInterval* last_interval_;
@@ -457,6 +470,9 @@ class RegisterAllocator FINAL : public ZoneObject {
   // Returns the register kind required by the given virtual register.
   RegisterKind RequiredRegisterKind(int virtual_register) const;
 
+  // Creates a new live range.
+  LiveRange* NewLiveRange(int index);
+
   // This zone is for InstructionOperands and moves that live beyond register
   // allocation.
   Zone* code_zone() const { return code()->zone(); }
@@ -564,10 +580,6 @@ class RegisterAllocator FINAL : public ZoneObject {
 
   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.
   const InstructionBlock* GetInstructionBlock(LifetimePosition pos);
 
index 8924ae5..f30e5f6 100644 (file)
@@ -100,10 +100,14 @@ std::ostream& operator<<(std::ostream& os, const BasicBlock::Control& c) {
       return os << "none";
     case BasicBlock::kGoto:
       return os << "goto";
+    case BasicBlock::kCall:
+      return os << "call";
     case BasicBlock::kBranch:
       return os << "branch";
     case BasicBlock::kSwitch:
       return os << "switch";
+    case BasicBlock::kDeoptimize:
+      return os << "deoptimize";
     case BasicBlock::kReturn:
       return os << "return";
     case BasicBlock::kThrow:
@@ -119,11 +123,6 @@ std::ostream& operator<<(std::ostream& os, const BasicBlock::Id& id) {
 }
 
 
-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),
@@ -194,16 +193,27 @@ void Schedule::AddNode(BasicBlock* block, Node* node) {
 
 
 void Schedule::AddGoto(BasicBlock* block, BasicBlock* succ) {
-  DCHECK(block->control() == BasicBlock::kNone);
+  DCHECK_EQ(BasicBlock::kNone, block->control());
   block->set_control(BasicBlock::kGoto);
   AddSuccessor(block, succ);
 }
 
 
+void Schedule::AddCall(BasicBlock* block, Node* call, BasicBlock* success_block,
+                       BasicBlock* exception_block) {
+  DCHECK_EQ(BasicBlock::kNone, block->control());
+  DCHECK_EQ(IrOpcode::kCall, call->opcode());
+  block->set_control(BasicBlock::kCall);
+  AddSuccessor(block, success_block);
+  AddSuccessor(block, exception_block);
+  SetControlInput(block, call);
+}
+
+
 void Schedule::AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock,
                          BasicBlock* fblock) {
-  DCHECK(block->control() == BasicBlock::kNone);
-  DCHECK(branch->opcode() == IrOpcode::kBranch);
+  DCHECK_EQ(BasicBlock::kNone, block->control());
+  DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
   block->set_control(BasicBlock::kBranch);
   AddSuccessor(block, tblock);
   AddSuccessor(block, fblock);
@@ -224,15 +234,23 @@ void Schedule::AddSwitch(BasicBlock* block, Node* sw, BasicBlock** succ_blocks,
 
 
 void Schedule::AddReturn(BasicBlock* block, Node* input) {
-  DCHECK(block->control() == BasicBlock::kNone);
+  DCHECK_EQ(BasicBlock::kNone, block->control());
   block->set_control(BasicBlock::kReturn);
   SetControlInput(block, input);
   if (block != end()) AddSuccessor(block, end());
 }
 
 
+void Schedule::AddDeoptimize(BasicBlock* block, Node* input) {
+  DCHECK_EQ(BasicBlock::kNone, block->control());
+  block->set_control(BasicBlock::kDeoptimize);
+  SetControlInput(block, input);
+  if (block != end()) AddSuccessor(block, end());
+}
+
+
 void Schedule::AddThrow(BasicBlock* block, Node* input) {
-  DCHECK(block->control() == BasicBlock::kNone);
+  DCHECK_EQ(BasicBlock::kNone, block->control());
   block->set_control(BasicBlock::kThrow);
   SetControlInput(block, input);
   if (block != end()) AddSuccessor(block, end());
@@ -241,8 +259,8 @@ void Schedule::AddThrow(BasicBlock* block, Node* input) {
 
 void Schedule::InsertBranch(BasicBlock* block, BasicBlock* end, Node* branch,
                             BasicBlock* tblock, BasicBlock* fblock) {
-  DCHECK(block->control() != BasicBlock::kNone);
-  DCHECK(end->control() == BasicBlock::kNone);
+  DCHECK_NE(BasicBlock::kNone, block->control());
+  DCHECK_EQ(BasicBlock::kNone, end->control());
   end->set_control(block->control());
   block->set_control(BasicBlock::kBranch);
   MoveSuccessors(block, end);
@@ -306,14 +324,14 @@ void Schedule::SetBlockForNode(BasicBlock* block, Node* node) {
 
 std::ostream& operator<<(std::ostream& os, const Schedule& s) {
   for (BasicBlock* block : *s.rpo_order()) {
-    os << "--- BLOCK B" << block->id();
+    os << "--- BLOCK B" << block->rpo_number();
     if (block->deferred()) os << " (deferred)";
     if (block->PredecessorCount() != 0) os << " <- ";
     bool comma = false;
     for (BasicBlock const* predecessor : block->predecessors()) {
       if (comma) os << ", ";
       comma = true;
-      os << "B" << predecessor->id();
+      os << "B" << predecessor->rpo_number();
     }
     os << " ---\n";
     for (Node* node : *block) {
@@ -342,7 +360,7 @@ std::ostream& operator<<(std::ostream& os, const Schedule& s) {
       for (BasicBlock const* successor : block->successors()) {
         if (comma) os << ", ";
         comma = true;
-        os << "B" << successor->id();
+        os << "B" << successor->rpo_number();
       }
       os << "\n";
     }
index d4d6453..d940e54 100644 (file)
@@ -30,12 +30,15 @@ class BasicBlock FINAL : public ZoneObject {
  public:
   // Possible control nodes that can end a block.
   enum Control {
-    kNone,    // Control not initialized yet.
-    kGoto,    // Goto a single successor block.
-    kBranch,  // Branch if true to first successor, otherwise second.
-    kSwitch,  // Table dispatch to one of the successor blocks.
-    kReturn,  // Return a value from this method.
-    kThrow    // Throw an exception.
+    kNone,        // Control not initialized yet.
+    kGoto,        // Goto a single successor block.
+    kCall,        // Call with continuation as first successor, exception
+                  // second.
+    kBranch,      // Branch if true to first successor, otherwise second.
+    kSwitch,      // Table dispatch to one of the successor blocks.
+    kDeoptimize,  // Return a value from this method.
+    kReturn,      // Return a value from this method.
+    kThrow        // Throw an exception.
   };
 
   class Id {
@@ -50,35 +53,6 @@ class BasicBlock FINAL : public ZoneObject {
     size_t index_;
   };
 
-  static const int kInvalidRpoNumber = -1;
-  class RpoNumber FINAL {
-   public:
-    int ToInt() const {
-      DCHECK(IsValid());
-      return index_;
-    }
-    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); }
-
-    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_; }
@@ -159,7 +133,6 @@ class BasicBlock FINAL : public ZoneObject {
   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);
 
@@ -197,7 +170,6 @@ class BasicBlock FINAL : public ZoneObject {
 
 std::ostream& operator<<(std::ostream&, const BasicBlock::Control&);
 std::ostream& operator<<(std::ostream&, const BasicBlock::Id&);
-std::ostream& operator<<(std::ostream&, const BasicBlock::RpoNumber&);
 
 
 // A schedule represents the result of assigning nodes to basic blocks
@@ -233,6 +205,10 @@ class Schedule FINAL : public ZoneObject {
   // BasicBlock building: add a goto to the end of {block}.
   void AddGoto(BasicBlock* block, BasicBlock* succ);
 
+  // BasicBlock building: add a call at the end of {block}.
+  void AddCall(BasicBlock* block, Node* call, BasicBlock* success_block,
+               BasicBlock* exception_block);
+
   // BasicBlock building: add a branch at the end of {block}.
   void AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock,
                  BasicBlock* fblock);
@@ -241,6 +217,9 @@ class Schedule FINAL : public ZoneObject {
   void AddSwitch(BasicBlock* block, Node* sw, BasicBlock** succ_blocks,
                  size_t succ_count);
 
+  // BasicBlock building: add a deoptimize at the end of {block}.
+  void AddDeoptimize(BasicBlock* block, Node* input);
+
   // BasicBlock building: add a return at the end of {block}.
   void AddReturn(BasicBlock* block, Node* input);
 
index 6e105e3..1185cac 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "src/compiler/scheduler.h"
 
+#include <iomanip>
+
 #include "src/bit-vector.h"
 #include "src/compiler/common-operator.h"
 #include "src/compiler/control-equivalence.h"
@@ -17,15 +19,10 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
-static inline 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);
-  }
-}
-
+#define TRACE(...)                                       \
+  do {                                                   \
+    if (FLAG_trace_turbo_scheduler) PrintF(__VA_ARGS__); \
+  } while (false)
 
 Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule, Flags flags)
     : zone_(zone),
@@ -64,7 +61,6 @@ Scheduler::SchedulerData Scheduler::DefaultSchedulerData() {
 
 
 Scheduler::SchedulerData* Scheduler::GetData(Node* node) {
-  DCHECK(node->id() < static_cast<int>(node_data_.size()));
   return &node_data_[node->id()];
 }
 
@@ -172,7 +168,7 @@ void Scheduler::IncrementUnscheduledUseCount(Node* node, int index,
 
   ++(GetData(node)->unscheduled_count_);
   if (FLAG_trace_turbo_scheduler) {
-    Trace("  Use count of #%d:%s (used by #%d:%s)++ = %d\n", node->id(),
+    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_);
   }
@@ -196,12 +192,12 @@ void Scheduler::DecrementUnscheduledUseCount(Node* node, int index,
   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(),
+    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());
+    TRACE("    newly eligible #%d:%s\n", node->id(), node->op()->mnemonic());
     schedule_queue_.push(node);
   }
 }
@@ -267,7 +263,7 @@ class CFGBuilder : public ZoneObject {
       // 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());
+        TRACE("Found SESE at #%d:%s\n", node->id(), node->op()->mnemonic());
         DCHECK(!component_entry_);
         component_entry_ = node;
         continue;
@@ -286,7 +282,7 @@ class CFGBuilder : public ZoneObject {
   }
 
  private:
-  // TODO(mstarzinger): Only for Scheduler::FuseFloatingControl.
+  friend class ScheduleLateNodeVisitor;
   friend class Scheduler;
 
   void FixNode(BasicBlock* block, Node* node) {
@@ -320,6 +316,11 @@ class CFGBuilder : public ZoneObject {
       case IrOpcode::kSwitch:
         BuildBlocksForSuccessors(node);
         break;
+      case IrOpcode::kCall:
+        if (IsExceptionalCall(node)) {
+          BuildBlocksForSuccessors(node);
+        }
+        break;
       default:
         break;
     }
@@ -339,6 +340,10 @@ class CFGBuilder : public ZoneObject {
         scheduler_->UpdatePlacement(node, Scheduler::kFixed);
         ConnectSwitch(node);
         break;
+      case IrOpcode::kDeoptimize:
+        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
+        ConnectDeoptimize(node);
+        break;
       case IrOpcode::kReturn:
         scheduler_->UpdatePlacement(node, Scheduler::kFixed);
         ConnectReturn(node);
@@ -347,6 +352,12 @@ class CFGBuilder : public ZoneObject {
         scheduler_->UpdatePlacement(node, Scheduler::kFixed);
         ConnectThrow(node);
         break;
+      case IrOpcode::kCall:
+        if (IsExceptionalCall(node)) {
+          scheduler_->UpdatePlacement(node, Scheduler::kFixed);
+          ConnectCall(node);
+        }
+        break;
       default:
         break;
     }
@@ -356,7 +367,7 @@ class CFGBuilder : public ZoneObject {
     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(),
+      TRACE("Create block id:%d for #%d:%s\n", block->id().ToInt(), node->id(),
             node->op()->mnemonic());
       FixNode(block, node);
     }
@@ -381,6 +392,31 @@ class CFGBuilder : public ZoneObject {
     }
   }
 
+  BasicBlock* FindPredecessorBlock(Node* node) {
+    BasicBlock* predecessor_block = nullptr;
+    while (true) {
+      predecessor_block = schedule_->block(node);
+      if (predecessor_block != nullptr) break;
+      node = NodeProperties::GetControlInput(node);
+    }
+    return predecessor_block;
+  }
+
+  void ConnectCall(Node* call) {
+    BasicBlock* successor_blocks[2];
+    CollectSuccessorBlocks(call, successor_blocks, arraysize(successor_blocks));
+
+    // Consider the exception continuation to be deferred.
+    successor_blocks[1]->set_deferred(true);
+
+    Node* call_control = NodeProperties::GetControlInput(call);
+    BasicBlock* call_block = FindPredecessorBlock(call_control);
+    TraceConnect(call, call_block, successor_blocks[0]);
+    TraceConnect(call, call_block, successor_blocks[1]);
+    schedule_->AddCall(call_block, call, successor_blocks[0],
+                       successor_blocks[1]);
+  }
+
   void ConnectBranch(Node* branch) {
     BasicBlock* successor_blocks[2];
     CollectSuccessorBlocks(branch, successor_blocks,
@@ -404,10 +440,8 @@ class CFGBuilder : public ZoneObject {
       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_NOT_NULL(branch_block);
-
+      Node* branch_control = NodeProperties::GetControlInput(branch);
+      BasicBlock* branch_block = FindPredecessorBlock(branch_control);
       TraceConnect(branch, branch_block, successor_blocks[0]);
       TraceConnect(branch, branch_block, successor_blocks[1]);
       schedule_->AddBranch(branch_block, branch, successor_blocks[0],
@@ -428,14 +462,12 @@ class CFGBuilder : public ZoneObject {
       schedule_->InsertSwitch(component_start_, component_end_, sw,
                               successor_blocks, successor_count);
     } else {
-      Node* sw_block_node = NodeProperties::GetControlInput(sw);
-      BasicBlock* sw_block = schedule_->block(sw_block_node);
-      DCHECK_NOT_NULL(sw_block);
-
+      Node* switch_control = NodeProperties::GetControlInput(sw);
+      BasicBlock* switch_block = FindPredecessorBlock(switch_control);
       for (size_t index = 0; index < successor_count; ++index) {
-        TraceConnect(sw, sw_block, successor_blocks[index]);
+        TraceConnect(sw, switch_block, successor_blocks[index]);
       }
-      schedule_->AddSwitch(sw_block, sw, successor_blocks, successor_count);
+      schedule_->AddSwitch(switch_block, sw, successor_blocks, successor_count);
     }
   }
 
@@ -448,22 +480,29 @@ class CFGBuilder : public ZoneObject {
     // For all of the merge's control inputs, add a goto at the end to the
     // merge's basic block.
     for (Node* const input : merge->inputs()) {
-      BasicBlock* predecessor_block = schedule_->block(input);
+      BasicBlock* predecessor_block = FindPredecessorBlock(input);
       TraceConnect(merge, predecessor_block, block);
       schedule_->AddGoto(predecessor_block, block);
     }
   }
 
   void ConnectReturn(Node* ret) {
-    Node* return_block_node = NodeProperties::GetControlInput(ret);
-    BasicBlock* return_block = schedule_->block(return_block_node);
+    Node* return_control = NodeProperties::GetControlInput(ret);
+    BasicBlock* return_block = FindPredecessorBlock(return_control);
     TraceConnect(ret, return_block, NULL);
     schedule_->AddReturn(return_block, ret);
   }
 
+  void ConnectDeoptimize(Node* deopt) {
+    Node* deoptimize_control = NodeProperties::GetControlInput(deopt);
+    BasicBlock* deoptimize_block = FindPredecessorBlock(deoptimize_control);
+    TraceConnect(deopt, deoptimize_block, NULL);
+    schedule_->AddDeoptimize(deoptimize_block, deopt);
+  }
+
   void ConnectThrow(Node* thr) {
-    Node* throw_block_node = NodeProperties::GetControlInput(thr);
-    BasicBlock* throw_block = schedule_->block(throw_block_node);
+    Node* throw_control = NodeProperties::GetControlInput(thr);
+    BasicBlock* throw_block = FindPredecessorBlock(throw_control);
     TraceConnect(thr, throw_block, NULL);
     schedule_->AddThrow(throw_block, thr);
   }
@@ -471,12 +510,19 @@ class CFGBuilder : public ZoneObject {
   void TraceConnect(Node* node, BasicBlock* block, BasicBlock* succ) {
     DCHECK_NOT_NULL(block);
     if (succ == NULL) {
-      Trace("Connect #%d:%s, B%d -> end\n", node->id(), node->op()->mnemonic(),
-            block->id().ToInt());
+      TRACE("Connect #%d:%s, id:%d -> end\n", node->id(),
+            node->op()->mnemonic(), block->id().ToInt());
     } else {
-      Trace("Connect #%d:%s, B%d -> B%d\n", node->id(), node->op()->mnemonic(),
-            block->id().ToInt(), succ->id().ToInt());
+      TRACE("Connect #%d:%s, id:%d -> id:%d\n", node->id(),
+            node->op()->mnemonic(), block->id().ToInt(), succ->id().ToInt());
+    }
+  }
+
+  bool IsExceptionalCall(Node* node) {
+    for (Node* const use : node->uses()) {
+      if (use->opcode() == IrOpcode::kIfException) return true;
     }
+    return false;
   }
 
   bool IsFinalMerge(Node* node) {
@@ -509,7 +555,7 @@ class CFGBuilder : public ZoneObject {
 
 
 void Scheduler::BuildCFG() {
-  Trace("--- CREATING CFG -------------------------------------------\n");
+  TRACE("--- CREATING CFG -------------------------------------------\n");
 
   // Instantiate a new control equivalence algorithm for the graph.
   equivalence_ = new (zone_) ControlEquivalence(zone_, graph_);
@@ -549,7 +595,8 @@ class SpecialRPONumberer : public ZoneObject {
         loops_(zone),
         backedges_(zone),
         stack_(zone),
-        previous_block_count_(0) {}
+        previous_block_count_(0),
+        empty_(0, zone) {}
 
   // 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.
@@ -586,6 +633,14 @@ class SpecialRPONumberer : public ZoneObject {
 #endif
   }
 
+  const ZoneList<BasicBlock*>& GetOutgoingBlocks(BasicBlock* block) {
+    if (HasLoopNumber(block)) {
+      LoopInfo const& loop = loops_[GetLoopNumber(block)];
+      if (loop.outgoing) return *loop.outgoing;
+    }
+    return empty_;
+  }
+
  private:
   typedef std::pair<BasicBlock*, size_t> Backedge;
 
@@ -828,18 +883,19 @@ class SpecialRPONumberer : public ZoneObject {
         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",
+        TRACE("id:%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(),
+        TRACE("id:%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());
+        TRACE("id:%d has loop header id:%d, (depth == %d)\n",
+              current->id().ToInt(), current->loop_header()->id().ToInt(),
+              current->loop_depth());
       }
     }
   }
@@ -905,30 +961,27 @@ class SpecialRPONumberer : public ZoneObject {
       os << " (";
       for (size_t i = 0; i < loops_.size(); i++) {
         if (i > 0) os << " ";
-        os << "B" << loops_[i].header->id();
+        os << "id:" << 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() << ":";
+      os << std::setw(5) << "B" << 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 << ": ";
+      os << "  id:" << block->id() << ": ";
       if (block->loop_end() != NULL) {
-        os << " range: [" << block->rpo_number() << ", "
+        os << " range: [B" << block->rpo_number() << ", B"
            << block->loop_end()->rpo_number() << ")";
       }
       if (block->loop_header() != NULL) {
-        os << " header: B" << block->loop_header()->id();
+        os << " header: id:" << block->loop_header()->id();
       }
       if (block->loop_depth() > 0) {
         os << " depth: " << block->loop_depth();
@@ -969,7 +1022,7 @@ class SpecialRPONumberer : public ZoneObject {
         DCHECK(block->rpo_number() == links + header->rpo_number());
         links++;
         block = block->rpo_next();
-        DCHECK(links < static_cast<int>(2 * order->size()));  // cycle?
+        DCHECK_LT(links, static_cast<int>(2 * order->size()));  // cycle?
       }
       DCHECK(links > 0);
       DCHECK(links == end->rpo_number() - header->rpo_number());
@@ -1008,6 +1061,7 @@ class SpecialRPONumberer : public ZoneObject {
   ZoneVector<Backedge> backedges_;
   ZoneVector<SpecialRPOStackFrame> stack_;
   size_t previous_block_count_;
+  ZoneList<BasicBlock*> const empty_;
 };
 
 
@@ -1021,7 +1075,7 @@ BasicBlockVector* Scheduler::ComputeSpecialRPO(Zone* zone, Schedule* schedule) {
 
 
 void Scheduler::ComputeSpecialRPONumbering() {
-  Trace("--- COMPUTING SPECIAL RPO ----------------------------------\n");
+  TRACE("--- COMPUTING SPECIAL RPO ----------------------------------\n");
 
   // Compute the special reverse-post-order for basic blocks.
   special_rpo_ = new (zone_) SpecialRPONumberer(zone_, schedule_);
@@ -1035,6 +1089,7 @@ void Scheduler::PropagateImmediateDominators(BasicBlock* block) {
     auto end = block->predecessors().end();
     DCHECK(pred != end);  // All blocks except start have predecessors.
     BasicBlock* dominator = *pred;
+    bool deferred = dominator->deferred();
     // 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.
@@ -1042,19 +1097,19 @@ void Scheduler::PropagateImmediateDominators(BasicBlock* block) {
       // Don't examine backwards edges.
       if ((*pred)->dominator_depth() < 0) continue;
       dominator = BasicBlock::GetCommonDominator(dominator, *pred);
+      deferred = deferred & (*pred)->deferred();
     }
     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(),
+    block->set_deferred(deferred | block->deferred());
+    TRACE("Block id:%d's idom is id:%d, depth = %d\n", block->id().ToInt(),
           dominator->id().ToInt(), block->dominator_depth());
   }
 }
 
 
 void Scheduler::GenerateImmediateDominatorTree() {
-  Trace("--- IMMEDIATE BLOCK DOMINATORS -----------------------------\n");
+  TRACE("--- IMMEDIATE BLOCK DOMINATORS -----------------------------\n");
 
   // Seed start block to be the first dominator.
   schedule_->start()->set_dominator_depth(0);
@@ -1079,7 +1134,7 @@ class PrepareUsesVisitor {
       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(),
+        TRACE("Scheduling fixed position node #%d:%s\n", node->id(),
               node->op()->mnemonic());
         IrOpcode::Value opcode = node->opcode();
         BasicBlock* block =
@@ -1109,7 +1164,7 @@ class PrepareUsesVisitor {
 
 
 void Scheduler::PrepareUses() {
-  Trace("--- PREPARE USES -------------------------------------------\n");
+  TRACE("--- PREPARE USES -------------------------------------------\n");
 
   // Count the uses of every node, which is used to ensure that all of a
   // node's uses are scheduled before the node itself.
@@ -1166,7 +1221,7 @@ class ScheduleEarlyNodeVisitor {
     // 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",
+      TRACE("Fixing #%d:%s minimum_block = id:%d, dominator_depth = %d\n",
             node->id(), node->op()->mnemonic(),
             data->minimum_block_->id().ToInt(),
             data->minimum_block_->dominator_depth());
@@ -1204,7 +1259,7 @@ class ScheduleEarlyNodeVisitor {
     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",
+      TRACE("Propagating #%d:%s minimum_block = id:%d, dominator_depth = %d\n",
             node->id(), node->op()->mnemonic(),
             data->minimum_block_->id().ToInt(),
             data->minimum_block_->dominator_depth());
@@ -1225,13 +1280,13 @@ class ScheduleEarlyNodeVisitor {
 
 
 void Scheduler::ScheduleEarly() {
-  Trace("--- SCHEDULE EARLY -----------------------------------------\n");
+  TRACE("--- SCHEDULE EARLY -----------------------------------------\n");
   if (FLAG_trace_turbo_scheduler) {
-    Trace("roots: ");
+    TRACE("roots: ");
     for (Node* node : schedule_root_nodes_) {
-      Trace("#%d:%s ", node->id(), node->op()->mnemonic());
+      TRACE("#%d:%s ", node->id(), node->op()->mnemonic());
     }
-    Trace("\n");
+    TRACE("\n");
   }
 
   // Compute the minimum block for each node thereby determining the earliest
@@ -1293,29 +1348,30 @@ class ScheduleLateNodeVisitor {
 
     // 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());
+    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, BasicBlock::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());
+    TRACE(
+        "Schedule late of #%d:%s is id:%d at loop depth %d, minimum = id:%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);
+    BasicBlock* hoist_block = GetHoistBlock(block);
     if (hoist_block &&
         hoist_block->dominator_depth() >= min_block->dominator_depth()) {
       do {
-        Trace("  hoisting #%d:%s to block B%d\n", node->id(),
+        TRACE("  hoisting #%d:%s to block id:%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);
+        hoist_block = GetHoistBlock(hoist_block);
       } while (hoist_block &&
                hoist_block->dominator_depth() >= min_block->dominator_depth());
     } else if (scheduler_->flags_ & Scheduler::kSplitNodes) {
@@ -1324,7 +1380,7 @@ class ScheduleLateNodeVisitor {
     }
 
     // Schedule the node or a floating control structure.
-    if (NodeProperties::IsControl(node)) {
+    if (IrOpcode::IsMergeOpcode(node->opcode())) {
       ScheduleFloatingControl(block, node);
     } else {
       ScheduleNode(block, node);
@@ -1345,6 +1401,8 @@ class ScheduleLateNodeVisitor {
   BasicBlock* SplitNode(BasicBlock* block, Node* node) {
     // For now, we limit splitting to pure nodes.
     if (!node->op()->HasProperty(Operator::kPure)) return block;
+    // TODO(titzer): fix the special case of splitting of projections.
+    if (node->opcode() == IrOpcode::kProjection) return block;
 
     // The {block} is common dominator of all uses of {node}, so we cannot
     // split anything unless the {block} has at least two successors.
@@ -1361,7 +1419,7 @@ class ScheduleLateNodeVisitor {
       BasicBlock* use_block = GetBlockForUse(edge);
       if (use_block == nullptr || marked_[use_block->id().ToSize()]) continue;
       if (use_block == block) {
-        Trace("  not splitting #%d:%s, it is used in B%d\n", node->id(),
+        TRACE("  not splitting #%d:%s, it is used in id:%d\n", node->id(),
               node->op()->mnemonic(), block->id().ToInt());
         marking_queue_.clear();
         return block;
@@ -1389,7 +1447,7 @@ class ScheduleLateNodeVisitor {
     // {block} to the end contain at least one use of {node}, and hence there's
     // no point in splitting the {node} in this case.
     if (marked_[block->id().ToSize()]) {
-      Trace("  not splitting #%d:%s, its common dominator B%d is perfect\n",
+      TRACE("  not splitting #%d:%s, its common dominator id:%d is perfect\n",
             node->id(), node->op()->mnemonic(), block->id().ToInt());
       return block;
     }
@@ -1411,12 +1469,12 @@ class ScheduleLateNodeVisitor {
           // Place the {node} at {use_block}.
           block = use_block;
           use_node = node;
-          Trace("  pushing #%d:%s down to B%d\n", node->id(),
+          TRACE("  pushing #%d:%s down to id:%d\n", node->id(),
                 node->op()->mnemonic(), block->id().ToInt());
         } else {
           // Place a copy of {node} at {use_block}.
           use_node = CloneNode(node);
-          Trace("  cloning #%d:%s for B%d\n", use_node->id(),
+          TRACE("  cloning #%d:%s for id:%d\n", use_node->id(),
                 use_node->op()->mnemonic(), use_block->id().ToInt());
           scheduler_->schedule_queue_.push(use_node);
         }
@@ -1426,14 +1484,23 @@ class ScheduleLateNodeVisitor {
     return block;
   }
 
-  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* GetHoistBlock(BasicBlock* block) {
+    if (block->IsLoopHeader()) return block->dominator();
+    // We have to check to make sure that the {block} dominates all
+    // of the outgoing blocks.  If it doesn't, then there is a path
+    // out of the loop which does not execute this {block}, so we
+    // can't hoist operations from this {block} out of the loop, as
+    // that would introduce additional computations.
+    if (BasicBlock* header_block = block->loop_header()) {
+      for (BasicBlock* outgoing_block :
+           scheduler_->special_rpo_->GetOutgoingBlocks(header_block)) {
+        if (BasicBlock::GetCommonDominator(block, outgoing_block) != block) {
+          return nullptr;
+        }
+      }
+      return header_block->dominator();
     }
+    return nullptr;
   }
 
   BasicBlock* GetCommonDominatorOfUses(Node* node) {
@@ -1448,32 +1515,43 @@ class ScheduleLateNodeVisitor {
     return block;
   }
 
+  BasicBlock* FindPredecessorBlock(Node* node) {
+    return scheduler_->control_flow_builder_->FindPredecessorBlock(node);
+  }
+
   BasicBlock* GetBlockForUse(Edge edge) {
     Node* use = edge.from();
-    IrOpcode::Value opcode = use->opcode();
-    if (IrOpcode::IsPhiOpcode(opcode)) {
+    if (IrOpcode::IsPhiOpcode(use->opcode())) {
       // 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(),
+        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 the use is from a fixed (i.e. non-floating) phi, we use the
+      // predecessor 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(),
+        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());
+        DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
+        Node* input = NodeProperties::GetControlInput(merge, edge.index());
+        return FindPredecessorBlock(input);
+      }
+    } else if (IrOpcode::IsMergeOpcode(use->opcode())) {
+      // If the use is from a fixed (i.e. non-floating) merge, we use the
+      // predecessor block of the current input to the merge.
+      if (scheduler_->GetPlacement(use) == Scheduler::kFixed) {
+        TRACE("  input@%d into a fixed merge #%d:%s\n", edge.index(), use->id(),
+              use->op()->mnemonic());
+        return FindPredecessorBlock(edge.to());
       }
     }
     BasicBlock* result = schedule_->block(use);
     if (result == NULL) return NULL;
-    Trace("  must dominate use #%d:%s in B%d\n", use->id(),
+    TRACE("  must dominate use #%d:%s in id:%d\n", use->id(),
           use->op()->mnemonic(), result->id().ToInt());
     return result;
   }
@@ -1497,6 +1575,8 @@ class ScheduleLateNodeVisitor {
       inputs[index] = input;
     }
     Node* copy = scheduler_->graph_->NewNode(node->op(), input_count, inputs);
+    TRACE(("clone #%d:%s -> #%d\n"), node->id(), node->op()->mnemonic(),
+          copy->id());
     scheduler_->node_data_.resize(copy->id() + 1,
                                   scheduler_->DefaultSchedulerData());
     scheduler_->node_data_[copy->id()] = scheduler_->node_data_[node->id()];
@@ -1511,13 +1591,13 @@ class ScheduleLateNodeVisitor {
 
 
 void Scheduler::ScheduleLate() {
-  Trace("--- SCHEDULE LATE ------------------------------------------\n");
+  TRACE("--- SCHEDULE LATE ------------------------------------------\n");
   if (FLAG_trace_turbo_scheduler) {
-    Trace("roots: ");
+    TRACE("roots: ");
     for (Node* node : schedule_root_nodes_) {
-      Trace("#%d:%s ", node->id(), node->op()->mnemonic());
+      TRACE("#%d:%s ", node->id(), node->op()->mnemonic());
     }
-    Trace("\n");
+    TRACE("\n");
   }
 
   // Schedule: Places nodes in dominator block of all their uses.
@@ -1531,7 +1611,7 @@ void Scheduler::ScheduleLate() {
 
 
 void Scheduler::SealFinalSchedule() {
-  Trace("--- SEAL FINAL SCHEDULE ------------------------------------\n");
+  TRACE("--- SEAL FINAL SCHEDULE ------------------------------------\n");
 
   // Serialize the assembly order and reverse-post-order numbering.
   special_rpo_->SerializeRPOIntoSchedule();
@@ -1553,7 +1633,7 @@ void Scheduler::SealFinalSchedule() {
 
 
 void Scheduler::FuseFloatingControl(BasicBlock* block, Node* node) {
-  Trace("--- FUSE FLOATING CONTROL ----------------------------------\n");
+  TRACE("--- FUSE FLOATING CONTROL ----------------------------------\n");
   if (FLAG_trace_turbo_scheduler) {
     OFStream os(stdout);
     os << "Schedule before control flow fusion:\n" << *schedule_;
@@ -1582,11 +1662,11 @@ void Scheduler::FuseFloatingControl(BasicBlock* block, Node* node) {
     }
   }
   if (FLAG_trace_turbo_scheduler) {
-    Trace("propagation roots: ");
+    TRACE("propagation roots: ");
     for (Node* node : propagation_roots) {
-      Trace("#%d:%s ", node->id(), node->op()->mnemonic());
+      TRACE("#%d:%s ", node->id(), node->op()->mnemonic());
     }
-    Trace("\n");
+    TRACE("\n");
   }
   ScheduleEarlyNodeVisitor schedule_early_visitor(zone_, this);
   schedule_early_visitor.Run(&propagation_roots);
@@ -1604,7 +1684,7 @@ void Scheduler::FuseFloatingControl(BasicBlock* block, Node* node) {
 
 
 void Scheduler::MovePlannedNodes(BasicBlock* from, BasicBlock* to) {
-  Trace("Move planned nodes from B%d to B%d\n", from->id().ToInt(),
+  TRACE("Move planned nodes from id:%d to id:%d\n", from->id().ToInt(),
         to->id().ToInt());
   NodeVector* nodes = &(scheduled_nodes_[from->id().ToSize()]);
   for (Node* const node : *nodes) {
index 59dd741..d216009 100644 (file)
@@ -25,8 +25,10 @@ namespace internal {
 namespace compiler {
 
 // Macro for outputting trace information from representation inference.
-#define TRACE(x) \
-  if (FLAG_trace_representation) PrintF x
+#define TRACE(...)                                      \
+  do {                                                  \
+    if (FLAG_trace_representation) PrintF(__VA_ARGS__); \
+  } while (false)
 
 // Representation selection and lowering of {Simplified} operators to machine
 // operators are interwined. We use a fixpoint calculation to compute both the
@@ -85,7 +87,7 @@ class RepresentationSelector {
 
   void Run(SimplifiedLowering* lowering) {
     // Run propagation phase to a fixpoint.
-    TRACE(("--{Propagation phase}--\n"));
+    TRACE("--{Propagation phase}--\n");
     phase_ = PROPAGATE;
     Enqueue(jsgraph_->graph()->end());
     // Process nodes from the queue until it is empty.
@@ -94,20 +96,20 @@ class RepresentationSelector {
       NodeInfo* info = GetInfo(node);
       queue_.pop();
       info->queued = false;
-      TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic()));
+      TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
       VisitNode(node, info->use, NULL);
-      TRACE(("  ==> output "));
+      TRACE("  ==> output ");
       PrintInfo(info->output);
-      TRACE(("\n"));
+      TRACE("\n");
     }
 
     // Run lowering and change insertion phase.
-    TRACE(("--{Simplified lowering phase}--\n"));
+    TRACE("--{Simplified lowering phase}--\n");
     phase_ = LOWER;
     // Process nodes from the collected {nodes_} vector.
     for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {
       Node* node = *i;
-      TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic()));
+      TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
       // Reuse {VisitNode()} so the representation rules are in one place.
       if (FLAG_turbo_source_positions) {
         SourcePositionTable::Scope scope(
@@ -124,6 +126,11 @@ class RepresentationSelector {
       Node* node = *i;
       Node* replacement = *(++i);
       node->ReplaceUses(replacement);
+      // We also need to replace the node in the rest of the vector.
+      for (NodeVector::iterator j = i + 1; j != replacements_.end(); ++j) {
+        ++j;
+        if (*j == node) *j = replacement;
+      }
     }
   }
 
@@ -138,21 +145,21 @@ class RepresentationSelector {
       info->queued = true;
       nodes_.push_back(node);
       queue_.push(node);
-      TRACE(("  initial: "));
+      TRACE("  initial: ");
       info->use |= use;
       PrintUseInfo(node);
       return;
     }
-    TRACE(("   queue?: "));
+    TRACE("   queue?: ");
     PrintUseInfo(node);
     if ((info->use & use) != use) {
       // New usage information for the node is available.
       if (!info->queued) {
         queue_.push(node);
         info->queued = true;
-        TRACE(("   added: "));
+        TRACE("   added: ");
       } else {
-        TRACE((" inqueue: "));
+        TRACE(" inqueue: ");
       }
       info->use |= use;
       PrintUseInfo(node);
@@ -190,14 +197,14 @@ class RepresentationSelector {
       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 "));
+        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 "));
+        TRACE(" to ");
         PrintInfo(use);
-        TRACE(("\n"));
+        TRACE("\n");
         Node* n = changer_->GetTruncatedWord32For(input, output);
         node->ReplaceInput(index, n);
       }
@@ -215,14 +222,14 @@ class RepresentationSelector {
       MachineTypeUnion output = GetInfo(input)->output;
       if ((output & kRepMask & use) == 0) {
         // Output representation doesn't match usage.
-        TRACE(("  change: #%d:%s(@%d #%d:%s) ", node->id(),
-               node->op()->mnemonic(), index, input->id(),
-               input->op()->mnemonic()));
-        TRACE((" from "));
+        TRACE("  change: #%d:%s(@%d #%d:%s) ", node->id(),
+              node->op()->mnemonic(), index, input->id(),
+              input->op()->mnemonic());
+        TRACE(" from ");
         PrintInfo(output);
-        TRACE((" to "));
+        TRACE(" to ");
         PrintInfo(use);
-        TRACE(("\n"));
+        TRACE("\n");
         Node* n = changer_->GetRepresentationFor(input, output, use);
         node->ReplaceInput(index, n);
       }
@@ -243,38 +250,37 @@ class RepresentationSelector {
   }
 
   // The default, most general visitation case. For {node}, process all value,
-  // context, effect, and control inputs, assuming that value inputs should have
-  // {kRepTagged} representation and can observe all output values {kTypeAny}.
+  // context, frame state, effect, and control inputs, assuming that value
+  // inputs should have {kRepTagged} representation and can observe all output
+  // values {kTypeAny}.
   void VisitInputs(Node* node) {
-    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
-    }
-    for (int j = OperatorProperties::GetFrameStateInputCount(node->op()); j > 0;
-         ++i, j--) {
-      Enqueue((*i).to());  // FrameState inputs: just visit
+    int tagged_count = node->op()->ValueInputCount() +
+                       OperatorProperties::GetContextInputCount(node->op());
+    // Visit value and context inputs as tagged.
+    for (int i = 0; i < tagged_count; i++) {
+      ProcessInput(node, i, kMachAnyTagged);
     }
-    for (int j = node->op()->EffectInputCount(); j > 0; ++i, j--) {
-      Enqueue((*i).to());  // Effect inputs: just visit
+    // Only enqueue other inputs (framestates, effects, control).
+    for (int i = tagged_count; i < node->InputCount(); i++) {
+      Enqueue(node->InputAt(i));
     }
-    for (int j = node->op()->ControlInputCount(); j > 0; ++i, j--) {
-      Enqueue((*i).to());  // Control inputs: just visit
-    }
-    DCHECK(i == node->input_edges().end());
+    // Assume the output is tagged.
     SetOutput(node, kMachAnyTagged);
   }
 
+  // Helper for binops of the R x L -> O variety.
+  void VisitBinop(Node* node, MachineTypeUnion left_use,
+                  MachineTypeUnion right_use, MachineTypeUnion output) {
+    DCHECK_EQ(2, node->InputCount());
+    ProcessInput(node, 0, left_use);
+    ProcessInput(node, 1, right_use);
+    SetOutput(node, output);
+  }
+
   // Helper for binops of the I x I -> O variety.
   void VisitBinop(Node* node, MachineTypeUnion input_use,
                   MachineTypeUnion output) {
-    DCHECK_EQ(2, node->InputCount());
-    ProcessInput(node, 0, input_use);
-    ProcessInput(node, 1, input_use);
-    SetOutput(node, output);
+    VisitBinop(node, input_use, input_use, output);
   }
 
   // Helper for unops of the I -> O variety.
@@ -324,7 +330,8 @@ class RepresentationSelector {
       } 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 ||
+      } else if (((use & kRepMask) == kRepWord32 &&
+                  !CanObserveNonWord32(use)) ||
                  (use & kTypeMask) == kTypeInt32 ||
                  (use & kTypeMask) == kTypeUint32) {
         // We only use 32 bits or we use the result consistently.
@@ -393,21 +400,36 @@ class RepresentationSelector {
       }
 
       // Convert inputs to the output representation of this phi.
-      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 ? output_type : 0);
-        values--;
+      for (int i = 0; i < node->InputCount(); i++) {
+        ProcessInput(node, i, i < values ? output_type : 0);
       }
     } 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--;
+      for (int i = 0; i < node->InputCount(); i++) {
+        ProcessInput(node, i, i < values ? use_type : 0);
+      }
+    }
+  }
+
+  void VisitStateValues(Node* node) {
+    if (phase_ == PROPAGATE) {
+      for (int i = 0; i < node->InputCount(); i++) {
+        Enqueue(node->InputAt(i), kTypeAny);
+      }
+    } else {
+      Zone* zone = jsgraph_->zone();
+      ZoneVector<MachineType>* types =
+          new (zone->New(sizeof(ZoneVector<MachineType>)))
+              ZoneVector<MachineType>(node->InputCount(), zone);
+      for (int i = 0; i < node->InputCount(); i++) {
+        MachineTypeUnion input_type = GetInfo(node->InputAt(i))->output;
+        (*types)[i] = static_cast<MachineType>(input_type);
       }
+      node->set_op(jsgraph_->common()->TypedStateValues(types));
     }
+    SetOutput(node, kMachAnyTagged);
   }
 
   const Operator* Int32Op(Node* node) {
@@ -426,18 +448,8 @@ class RepresentationSelector {
     return BothInputsAre(node, Type::Signed32()) && !CanObserveNonInt32(use);
   }
 
-  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)) &&
+    return BothInputsAre(node, safe_int_additive_range_) &&
            !CanObserveNonInt32(use);
   }
 
@@ -446,11 +458,14 @@ class RepresentationSelector {
   }
 
   bool CanLowerToUint32AdditiveBinop(Node* node, MachineTypeUnion use) {
-    return IsSafeIntAdditiveOperand(node->InputAt(0)) &&
-           IsSafeIntAdditiveOperand(node->InputAt(1)) &&
+    return BothInputsAre(node, safe_int_additive_range_) &&
            !CanObserveNonUint32(use);
   }
 
+  bool CanObserveNonWord32(MachineTypeUnion use) {
+    return (use & ~(kTypeUint32 | kTypeInt32)) != 0;
+  }
+
   bool CanObserveNonInt32(MachineTypeUnion use) {
     return (use & (kTypeUint32 | kTypeNumber | kTypeAny)) != 0;
   }
@@ -531,24 +546,6 @@ class RepresentationSelector {
       //------------------------------------------------------------------
       // Simplified operators.
       //------------------------------------------------------------------
-      case IrOpcode::kAnyToBoolean: {
-        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(
-              jsgraph_->isolate(), jsgraph_->zone(), callable.descriptor(), 0,
-              flags, properties);
-          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;
@@ -900,7 +897,7 @@ class RepresentationSelector {
         MachineTypeUnion tBase = kRepTagged | kMachPtr;
         LoadRepresentation rep = OpParameter<LoadRepresentation>(node);
         ProcessInput(node, 0, tBase);   // pointer or object
-        ProcessInput(node, 1, kMachInt32);  // index
+        ProcessInput(node, 1, kMachIntPtr);  // index
         ProcessRemainingInputs(node, 2);
         SetOutput(node, rep);
         break;
@@ -910,7 +907,7 @@ class RepresentationSelector {
         MachineTypeUnion tBase = kRepTagged | kMachPtr;
         StoreRepresentation rep = OpParameter<StoreRepresentation>(node);
         ProcessInput(node, 0, tBase);   // pointer or object
-        ProcessInput(node, 1, kMachInt32);  // index
+        ProcessInput(node, 1, kMachIntPtr);  // index
         ProcessInput(node, 2, rep.machine_type());
         ProcessRemainingInputs(node, 3);
         SetOutput(node, 0);
@@ -931,6 +928,9 @@ class RepresentationSelector {
       case IrOpcode::kWord32Equal:
         return VisitBinop(node, kRepWord32, kRepBit);
 
+      case IrOpcode::kWord32Clz:
+        return VisitUnop(node, kMachUint32, kMachUint32);
+
       case IrOpcode::kInt32Add:
       case IrOpcode::kInt32Sub:
       case IrOpcode::kInt32Mul:
@@ -1012,10 +1012,10 @@ class RepresentationSelector {
       case IrOpcode::kFloat64Mul:
       case IrOpcode::kFloat64Div:
       case IrOpcode::kFloat64Mod:
+      case IrOpcode::kFloat64Min:
         return VisitFloat64Binop(node);
       case IrOpcode::kFloat64Sqrt:
-      case IrOpcode::kFloat64Floor:
-      case IrOpcode::kFloat64Ceil:
+      case IrOpcode::kFloat64RoundDown:
       case IrOpcode::kFloat64RoundTruncate:
       case IrOpcode::kFloat64RoundTiesAway:
         return VisitUnop(node, kMachFloat64, kMachFloat64);
@@ -1023,13 +1023,16 @@ class RepresentationSelector {
       case IrOpcode::kFloat64LessThan:
       case IrOpcode::kFloat64LessThanOrEqual:
         return VisitFloat64Cmp(node);
+      case IrOpcode::kFloat64ExtractLowWord32:
+      case IrOpcode::kFloat64ExtractHighWord32:
+        return VisitUnop(node, kMachFloat64, kMachInt32);
+      case IrOpcode::kFloat64InsertLowWord32:
+      case IrOpcode::kFloat64InsertHighWord32:
+        return VisitBinop(node, kMachFloat64, kMachInt32, kMachFloat64);
       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);
+        VisitStateValues(node);
         break;
       default:
         VisitInputs(node);
@@ -1038,11 +1041,10 @@ class RepresentationSelector {
   }
 
   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()));
-    }
+    TRACE("defer replacement #%d:%s with #%d:%s\n", node->id(),
+          node->op()->mnemonic(), replacement->id(),
+          replacement->op()->mnemonic());
+
     if (replacement->id() < count_ &&
         GetInfo(replacement)->output == GetInfo(node)->output) {
       // Replace with a previously existing node eagerly only if the type is the
@@ -1056,13 +1058,13 @@ class RepresentationSelector {
       replacements_.push_back(node);
       replacements_.push_back(replacement);
     }
-    // TODO(titzer) node->RemoveAllInputs();  // Node is now dead.
+    node->NullAllInputs();  // Node is now dead.
   }
 
   void PrintUseInfo(Node* node) {
-    TRACE(("#%d:%-20s ", node->id(), node->op()->mnemonic()));
+    TRACE("#%d:%-20s ", node->id(), node->op()->mnemonic());
     PrintInfo(GetUseInfo(node));
-    TRACE(("\n"));
+    TRACE("\n");
   }
 
   void PrintInfo(MachineTypeUnion info) {
@@ -1135,10 +1137,15 @@ Node* SimplifiedLowering::OffsetMinusTagConstant(int32_t offset) {
 }
 
 
-static WriteBarrierKind ComputeWriteBarrierKind(BaseTaggedness base_is_tagged,
-                                                MachineType representation,
-                                                Type* type) {
-  // TODO(turbofan): skip write barriers for Smis, etc.
+namespace {
+
+WriteBarrierKind ComputeWriteBarrierKind(BaseTaggedness base_is_tagged,
+                                         MachineType representation,
+                                         Type* type) {
+  if (type->Is(Type::TaggedSigned())) {
+    // Write barriers are only for writes of heap objects.
+    return kNoWriteBarrier;
+  }
   if (base_is_tagged == kTaggedBase &&
       RepresentationOf(representation) == kRepTagged) {
     // Write barriers are only for writes into heap objects (i.e. tagged base).
@@ -1147,6 +1154,8 @@ static WriteBarrierKind ComputeWriteBarrierKind(BaseTaggedness base_is_tagged,
   return kNoWriteBarrier;
 }
 
+}  // namespace
+
 
 void SimplifiedLowering::DoLoadField(Node* node) {
   const FieldAccess& access = FieldAccessOf(node->op());
@@ -1158,8 +1167,9 @@ void SimplifiedLowering::DoLoadField(Node* node) {
 
 void SimplifiedLowering::DoStoreField(Node* node) {
   const FieldAccess& access = FieldAccessOf(node->op());
-  WriteBarrierKind kind = ComputeWriteBarrierKind(
-      access.base_is_tagged, access.machine_type, access.type);
+  Type* type = NodeProperties::GetBounds(node->InputAt(1)).upper;
+  WriteBarrierKind kind =
+      ComputeWriteBarrierKind(access.base_is_tagged, access.machine_type, type);
   node->set_op(
       machine()->Store(StoreRepresentation(access.machine_type, kind)));
   Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag());
@@ -1264,10 +1274,11 @@ void SimplifiedLowering::DoLoadElement(Node* node) {
 
 void SimplifiedLowering::DoStoreElement(Node* node) {
   const ElementAccess& access = ElementAccessOf(node->op());
-  node->set_op(machine()->Store(StoreRepresentation(
-      access.machine_type,
-      ComputeWriteBarrierKind(access.base_is_tagged, access.machine_type,
-                              access.type))));
+  Type* type = NodeProperties::GetBounds(node->InputAt(2)).upper;
+  node->set_op(machine()->Store(
+      StoreRepresentation(access.machine_type,
+                          ComputeWriteBarrierKind(access.base_is_tagged,
+                                                  access.machine_type, type))));
   node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
 }
 
@@ -1292,7 +1303,7 @@ void SimplifiedLowering::DoStringAdd(Node* node) {
 Node* SimplifiedLowering::StringComparison(Node* node, bool requires_ordering) {
   CEntryStub stub(jsgraph()->isolate(), 1);
   Runtime::FunctionId f =
-      requires_ordering ? Runtime::kStringCompare : Runtime::kStringEquals;
+      requires_ordering ? Runtime::kStringCompareRT : Runtime::kStringEquals;
   ExternalReference ref(f, jsgraph()->isolate());
   Operator::Properties props = node->op()->properties();
   // TODO(mstarzinger): We should call StringCompareStub here instead, once an
@@ -1311,6 +1322,7 @@ Node* SimplifiedLowering::StringComparison(Node* node, bool requires_ordering) {
 Node* SimplifiedLowering::Int32Div(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();
 
@@ -1322,20 +1334,61 @@ Node* SimplifiedLowering::Int32Div(Node* const node) {
     return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
   }
 
-  Diamond if_zero(graph(), common(),
-                  graph()->NewNode(machine()->Word32Equal(), rhs, zero),
-                  BranchHint::kFalse);
+  // General case for signed integer division.
+  //
+  //    if 0 < rhs then
+  //      lhs / rhs
+  //    else
+  //      if rhs < -1 then
+  //        lhs / rhs
+  //      else if rhs == 0 then
+  //        0
+  //      else
+  //        0 - lhs
+  //
+  // 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 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, 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(), check1, if_false0);
+
+    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+    Node* true1 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true1);
+
+    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+    Node* false1;
+    {
+      Node* check2 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
+      Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1);
+
+      Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
+      Node* true2 = zero;
+
+      Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
+      Node* false2 = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
+
+      if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
+      false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
+    }
 
-  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);
+    if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
+    false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
+  }
 
-  return if_zero.Phi(kMachInt32, zero, if_minus_one.Phi(kMachInt32, sub, div));
+  Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
+  return graph()->NewNode(phi_op, true0, false0, merge0);
 }
 
 
index ad48379..047d251 100644 (file)
@@ -4,11 +4,9 @@
 
 #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/node-properties.h"
 #include "src/compiler/operator-properties.h"
 
 namespace v8 {
@@ -24,8 +22,6 @@ 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()))) {
@@ -111,32 +107,6 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
 }
 
 
-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));
@@ -175,11 +145,6 @@ Factory* SimplifiedOperatorReducer::factory() const {
 }
 
 
-CommonOperatorBuilder* SimplifiedOperatorReducer::common() const {
-  return jsgraph()->common();
-}
-
-
 MachineOperatorBuilder* SimplifiedOperatorReducer::machine() const {
   return jsgraph()->machine();
 }
index 32a7bcc..bc26723 100644 (file)
@@ -18,7 +18,6 @@ class Heap;
 namespace compiler {
 
 // Forward declarations.
-class CommonOperatorBuilder;
 class JSGraph;
 class MachineOperatorBuilder;
 
@@ -30,8 +29,6 @@ class SimplifiedOperatorReducer FINAL : public Reducer {
   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);
@@ -44,7 +41,6 @@ class SimplifiedOperatorReducer FINAL : public Reducer {
   Graph* graph() const;
   Factory* factory() const;
   JSGraph* jsgraph() const { return jsgraph_; }
-  CommonOperatorBuilder* common() const;
   MachineOperatorBuilder* machine() const;
   SimplifiedOperatorBuilder* simplified() { return &simplified_; }
 
index e1e8c30..a900d4e 100644 (file)
@@ -158,7 +158,6 @@ const ElementAccess& ElementAccessOf(const Operator* op) {
 
 
 #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)             \
index 5eed7c3..9cd2033 100644 (file)
@@ -128,8 +128,6 @@ class SimplifiedOperatorBuilder FINAL {
  public:
   explicit SimplifiedOperatorBuilder(Zone* zone);
 
-  const Operator* AnyToBoolean();
-
   const Operator* BooleanNot();
   const Operator* BooleanToNumber();
 
diff --git a/deps/v8/src/compiler/state-values-utils.cc b/deps/v8/src/compiler/state-values-utils.cc
new file mode 100644 (file)
index 0000000..2c7d0ed
--- /dev/null
@@ -0,0 +1,317 @@
+// 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.
+
+#include "src/compiler/state-values-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+StateValuesCache::StateValuesCache(JSGraph* js_graph)
+    : js_graph_(js_graph),
+      hash_map_(AreKeysEqual, ZoneHashMap::kDefaultHashMapCapacity,
+                ZoneAllocationPolicy(zone())),
+      working_space_(zone()),
+      empty_state_values_(nullptr) {}
+
+
+// static
+bool StateValuesCache::AreKeysEqual(void* key1, void* key2) {
+  NodeKey* node_key1 = reinterpret_cast<NodeKey*>(key1);
+  NodeKey* node_key2 = reinterpret_cast<NodeKey*>(key2);
+
+  if (node_key1->node == nullptr) {
+    if (node_key2->node == nullptr) {
+      return AreValueKeysEqual(reinterpret_cast<StateValuesKey*>(key1),
+                               reinterpret_cast<StateValuesKey*>(key2));
+    } else {
+      return IsKeysEqualToNode(reinterpret_cast<StateValuesKey*>(key1),
+                               node_key2->node);
+    }
+  } else {
+    if (node_key2->node == nullptr) {
+      // If the nodes are already processed, they must be the same.
+      return IsKeysEqualToNode(reinterpret_cast<StateValuesKey*>(key2),
+                               node_key1->node);
+    } else {
+      return node_key1->node == node_key2->node;
+    }
+  }
+  UNREACHABLE();
+}
+
+
+// static
+bool StateValuesCache::IsKeysEqualToNode(StateValuesKey* key, Node* node) {
+  if (key->count != static_cast<size_t>(node->InputCount())) {
+    return false;
+  }
+  for (size_t i = 0; i < key->count; i++) {
+    if (key->values[i] != node->InputAt(static_cast<int>(i))) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+// static
+bool StateValuesCache::AreValueKeysEqual(StateValuesKey* key1,
+                                         StateValuesKey* key2) {
+  if (key1->count != key2->count) {
+    return false;
+  }
+  for (size_t i = 0; i < key1->count; i++) {
+    if (key1->values[i] != key2->values[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+Node* StateValuesCache::GetEmptyStateValues() {
+  if (empty_state_values_ == nullptr) {
+    empty_state_values_ = graph()->NewNode(common()->StateValues(0));
+  }
+  return empty_state_values_;
+}
+
+
+NodeVector* StateValuesCache::GetWorkingSpace(size_t level) {
+  while (working_space_.size() <= level) {
+    void* space = zone()->New(sizeof(NodeVector));
+    working_space_.push_back(new (space)
+                                 NodeVector(kMaxInputCount, nullptr, zone()));
+  }
+  return working_space_[level];
+}
+
+namespace {
+
+int StateValuesHashKey(Node** nodes, size_t count) {
+  size_t hash = count;
+  for (size_t i = 0; i < count; i++) {
+    hash = hash * 23 + nodes[i]->id();
+  }
+  return static_cast<int>(hash & 0x7fffffff);
+}
+
+}  // namespace
+
+
+Node* StateValuesCache::GetValuesNodeFromCache(Node** nodes, size_t count) {
+  StateValuesKey key(count, nodes);
+  int hash = StateValuesHashKey(nodes, count);
+  ZoneHashMap::Entry* lookup =
+      hash_map_.Lookup(&key, hash, true, ZoneAllocationPolicy(zone()));
+  DCHECK_NOT_NULL(lookup);
+  Node* node;
+  if (lookup->value == nullptr) {
+    int input_count = static_cast<int>(count);
+    node = graph()->NewNode(common()->StateValues(input_count), input_count,
+                            nodes);
+    NodeKey* new_key = new (zone()->New(sizeof(NodeKey))) NodeKey(node);
+    lookup->key = new_key;
+    lookup->value = node;
+  } else {
+    node = reinterpret_cast<Node*>(lookup->value);
+  }
+  return node;
+}
+
+
+class StateValuesCache::ValueArrayIterator {
+ public:
+  ValueArrayIterator(Node** values, size_t count)
+      : values_(values), count_(count), current_(0) {}
+
+  void Advance() {
+    if (!done()) {
+      current_++;
+    }
+  }
+
+  bool done() { return current_ >= count_; }
+
+  Node* node() {
+    DCHECK(!done());
+    return values_[current_];
+  }
+
+ private:
+  Node** values_;
+  size_t count_;
+  size_t current_;
+};
+
+
+Node* StateValuesCache::BuildTree(ValueArrayIterator* it, size_t max_height) {
+  if (max_height == 0) {
+    Node* node = it->node();
+    it->Advance();
+    return node;
+  }
+  DCHECK(!it->done());
+
+  NodeVector* buffer = GetWorkingSpace(max_height);
+  size_t count = 0;
+  for (; count < kMaxInputCount; count++) {
+    if (it->done()) break;
+    (*buffer)[count] = BuildTree(it, max_height - 1);
+  }
+  if (count == 1) {
+    return (*buffer)[0];
+  } else {
+    return GetValuesNodeFromCache(&(buffer->front()), count);
+  }
+}
+
+
+Node* StateValuesCache::GetNodeForValues(Node** values, size_t count) {
+#if DEBUG
+  for (size_t i = 0; i < count; i++) {
+    DCHECK_NE(values[i]->opcode(), IrOpcode::kStateValues);
+    DCHECK_NE(values[i]->opcode(), IrOpcode::kTypedStateValues);
+  }
+#endif
+  if (count == 0) {
+    return GetEmptyStateValues();
+  }
+  size_t height = 0;
+  size_t max_nodes = 1;
+  while (count > max_nodes) {
+    height++;
+    max_nodes *= kMaxInputCount;
+  }
+
+  ValueArrayIterator it(values, count);
+
+  Node* tree = BuildTree(&it, height);
+
+  // If the 'tree' is a single node, equip it with a StateValues wrapper.
+  if (tree->opcode() != IrOpcode::kStateValues &&
+      tree->opcode() != IrOpcode::kTypedStateValues) {
+    tree = GetValuesNodeFromCache(&tree, 1);
+  }
+
+  return tree;
+}
+
+
+StateValuesAccess::iterator::iterator(Node* node) : current_depth_(0) {
+  // A hacky way initialize - just set the index before the node we want
+  // to process and then advance to it.
+  stack_[current_depth_].node = node;
+  stack_[current_depth_].index = -1;
+  Advance();
+}
+
+
+StateValuesAccess::iterator::StatePos* StateValuesAccess::iterator::Top() {
+  DCHECK(current_depth_ >= 0);
+  DCHECK(current_depth_ < kMaxInlineDepth);
+  return &(stack_[current_depth_]);
+}
+
+
+void StateValuesAccess::iterator::Push(Node* node) {
+  current_depth_++;
+  CHECK(current_depth_ < kMaxInlineDepth);
+  stack_[current_depth_].node = node;
+  stack_[current_depth_].index = 0;
+}
+
+
+void StateValuesAccess::iterator::Pop() {
+  DCHECK(current_depth_ >= 0);
+  current_depth_--;
+}
+
+
+bool StateValuesAccess::iterator::done() { return current_depth_ < 0; }
+
+
+void StateValuesAccess::iterator::Advance() {
+  // Advance the current index.
+  Top()->index++;
+
+  // Fix up the position to point to a valid node.
+  while (true) {
+    // TODO(jarin): Factor to a separate method.
+    Node* node = Top()->node;
+    int index = Top()->index;
+
+    if (index >= node->InputCount()) {
+      // Pop stack and move to the next sibling.
+      Pop();
+      if (done()) {
+        // Stack is exhausted, we have reached the end.
+        return;
+      }
+      Top()->index++;
+    } else if (node->InputAt(index)->opcode() == IrOpcode::kStateValues ||
+               node->InputAt(index)->opcode() == IrOpcode::kTypedStateValues) {
+      // Nested state, we need to push to the stack.
+      Push(node->InputAt(index));
+    } else {
+      // We are on a valid node, we can stop the iteration.
+      return;
+    }
+  }
+}
+
+
+Node* StateValuesAccess::iterator::node() {
+  return Top()->node->InputAt(Top()->index);
+}
+
+
+MachineType StateValuesAccess::iterator::type() {
+  Node* state = Top()->node;
+  if (state->opcode() == IrOpcode::kStateValues) {
+    return kMachAnyTagged;
+  } else {
+    DCHECK_EQ(IrOpcode::kTypedStateValues, state->opcode());
+    const ZoneVector<MachineType>* types =
+        OpParameter<const ZoneVector<MachineType>*>(state);
+    return (*types)[Top()->index];
+  }
+}
+
+
+bool StateValuesAccess::iterator::operator!=(iterator& other) {
+  // We only allow comparison with end().
+  CHECK(other.done());
+  return !done();
+}
+
+
+StateValuesAccess::iterator& StateValuesAccess::iterator::operator++() {
+  Advance();
+  return *this;
+}
+
+
+StateValuesAccess::TypedNode StateValuesAccess::iterator::operator*() {
+  return TypedNode(node(), type());
+}
+
+
+size_t StateValuesAccess::size() {
+  size_t count = 0;
+  for (int i = 0; i < node_->InputCount(); i++) {
+    if (node_->InputAt(i)->opcode() == IrOpcode::kStateValues ||
+        node_->InputAt(i)->opcode() == IrOpcode::kTypedStateValues) {
+      count += StateValuesAccess(node_->InputAt(i)).size();
+    } else {
+      count++;
+    }
+  }
+  return count;
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/deps/v8/src/compiler/state-values-utils.h b/deps/v8/src/compiler/state-values-utils.h
new file mode 100644 (file)
index 0000000..79550bd
--- /dev/null
@@ -0,0 +1,120 @@
+// 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.
+
+#ifndef V8_COMPILER_STATE_VALUES_UTILS_H_
+#define V8_COMPILER_STATE_VALUES_UTILS_H_
+
+#include "src/compiler/js-graph.h"
+
+namespace v8 {
+namespace internal {
+
+namespace compiler {
+
+class Graph;
+
+class StateValuesCache {
+ public:
+  explicit StateValuesCache(JSGraph* js_graph);
+
+  Node* GetNodeForValues(Node** values, size_t count);
+
+ private:
+  static const size_t kMaxInputCount = 8;
+
+  struct NodeKey {
+    Node* node;
+
+    explicit NodeKey(Node* node) : node(node) {}
+  };
+
+  struct StateValuesKey : public NodeKey {
+    // ValueArray - array of nodes ({node} has to be nullptr).
+    size_t count;
+    Node** values;
+
+    StateValuesKey(size_t count, Node** values)
+        : NodeKey(nullptr), count(count), values(values) {}
+  };
+
+  class ValueArrayIterator;
+
+  static bool AreKeysEqual(void* key1, void* key2);
+  static bool IsKeysEqualToNode(StateValuesKey* key, Node* node);
+  static bool AreValueKeysEqual(StateValuesKey* key1, StateValuesKey* key2);
+
+  Node* BuildTree(ValueArrayIterator* it, size_t max_height);
+  NodeVector* GetWorkingSpace(size_t level);
+  Node* GetEmptyStateValues();
+  Node* GetValuesNodeFromCache(Node** nodes, size_t count);
+
+  Graph* graph() { return js_graph_->graph(); }
+  CommonOperatorBuilder* common() { return js_graph_->common(); }
+
+  Zone* zone() { return graph()->zone(); }
+
+  JSGraph* js_graph_;
+  ZoneHashMap hash_map_;
+  ZoneVector<NodeVector*> working_space_;  // One working space per level.
+  Node* empty_state_values_;
+};
+
+class StateValuesAccess {
+ public:
+  struct TypedNode {
+    Node* node;
+    MachineType type;
+    TypedNode(Node* node, MachineType type) : node(node), type(type) {}
+  };
+
+  class iterator {
+   public:
+    // Bare minimum of operators needed for range iteration.
+    bool operator!=(iterator& other);
+    iterator& operator++();
+    TypedNode operator*();
+
+   private:
+    friend class StateValuesAccess;
+
+    iterator() : current_depth_(-1) {}
+    explicit iterator(Node* node);
+
+    Node* node();
+    MachineType type();
+    bool done();
+    void Advance();
+
+    struct StatePos {
+      Node* node;
+      int index;
+
+      explicit StatePos(Node* node) : node(node), index(0) {}
+      StatePos() {}
+    };
+
+    StatePos* Top();
+    void Push(Node* node);
+    void Pop();
+
+    static const int kMaxInlineDepth = 8;
+    StatePos stack_[kMaxInlineDepth];
+    int current_depth_;
+  };
+
+  explicit StateValuesAccess(Node* node) : node_(node) {}
+
+  size_t size();
+  iterator begin() { return iterator(node_); }
+  iterator end() { return iterator(); }
+
+ private:
+  Node* node_;
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_STATE_VALUES_UTILS_H_
index 9af6559..85b0c3e 100644 (file)
@@ -156,9 +156,7 @@ Typer::Typer(Isolate* isolate, Graph* graph, MaybeHandle<Context> context)
       graph_(graph),
       context_(context),
       decorator_(NULL),
-      cache_(new (graph->zone()) LazyTypeCache(isolate, graph->zone())),
-      weaken_min_limits_(graph->zone()),
-      weaken_max_limits_(graph->zone()) {
+      cache_(new (graph->zone()) LazyTypeCache(isolate, graph->zone())) {
   Zone* zone = this->zone();
   Factory* f = isolate->factory();
 
@@ -202,20 +200,6 @@ Typer::Typer(Isolate* isolate, Graph* graph, MaybeHandle<Context> context)
   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(0);
-  weaken_max_limits_.push_back(0);
-  for (int i = 0; i < limits_count; i++) {
-    weaken_min_limits_.push_back(-limit);
-    weaken_max_limits_.push_back(limit - 1);
-    limit *= 2;
-  }
-
   decorator_ = new (zone) Decorator(this);
   graph_->AddDecorator(decorator_);
 }
@@ -228,7 +212,8 @@ Typer::~Typer() {
 
 class Typer::Visitor : public Reducer {
  public:
-  explicit Visitor(Typer* typer) : typer_(typer) {}
+  explicit Visitor(Typer* typer)
+      : typer_(typer), weakened_nodes_(typer->zone()) {}
 
   Reduction Reduce(Node* node) OVERRIDE {
     if (node->op()->ValueOutputCount() == 0) return NoChange();
@@ -296,6 +281,7 @@ class Typer::Visitor : public Reducer {
  private:
   Typer* typer_;
   MaybeHandle<Context> context_;
+  ZoneSet<NodeId> weakened_nodes_;
 
 #define DECLARE_METHOD(x) inline Bounds Type##x(Node* node);
   DECLARE_METHOD(Start)
@@ -313,13 +299,18 @@ class Typer::Visitor : public Reducer {
   }
 
   Bounds WrapContextBoundsForInput(Node* node);
-  Type* Weaken(Type* current_type, Type* previous_type);
+  Type* Weaken(Node* node, Type* current_type, Type* previous_type);
 
   Zone* zone() { return typer_->zone(); }
   Isolate* isolate() { return typer_->isolate(); }
   Graph* graph() { return typer_->graph(); }
   MaybeHandle<Context> context() { return typer_->context(); }
 
+  void SetWeakened(NodeId node_id) { weakened_nodes_.insert(node_id); }
+  bool IsWeakened(NodeId node_id) {
+    return weakened_nodes_.find(node_id) != weakened_nodes_.end();
+  }
+
   typedef Type* (*UnaryTyperFun)(Type*, Typer* t);
   typedef Type* (*BinaryTyperFun)(Type*, Type*, Typer* t);
 
@@ -365,9 +356,11 @@ class Typer::Visitor : public Reducer {
     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);
+      if (node->opcode() == IrOpcode::kPhi) {
+        // Speed up termination in the presence of range types:
+        current.upper = Weaken(node, current.upper, previous.upper);
+        current.lower = Weaken(node, current.lower, previous.lower);
+      }
 
       // Types should not get less precise.
       DCHECK(previous.lower->Is(current.lower));
@@ -730,6 +723,11 @@ Bounds Typer::Visitor::TypeStateValues(Node* node) {
 }
 
 
+Bounds Typer::Visitor::TypeTypedStateValues(Node* node) {
+  return Bounds(Type::None(zone()), Type::Internal(zone()));
+}
+
+
 Bounds Typer::Visitor::TypeCall(Node* node) {
   return Bounds::Unbounded(zone());
 }
@@ -1302,46 +1300,72 @@ Bounds Typer::Visitor::TypeJSLoadNamed(Node* node) {
 // 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* Typer::Visitor::Weaken(Node* node, Type* current_type,
+                             Type* previous_type) {
+  static const double kWeakenMinLimits[] = {
+      0.0, -1073741824.0, -2147483648.0, -4294967296.0, -8589934592.0,
+      -17179869184.0, -34359738368.0, -68719476736.0, -137438953472.0,
+      -274877906944.0, -549755813888.0, -1099511627776.0, -2199023255552.0,
+      -4398046511104.0, -8796093022208.0, -17592186044416.0, -35184372088832.0,
+      -70368744177664.0, -140737488355328.0, -281474976710656.0,
+      -562949953421312.0};
+  static const double kWeakenMaxLimits[] = {
+      0.0, 1073741823.0, 2147483647.0, 4294967295.0, 8589934591.0,
+      17179869183.0, 34359738367.0, 68719476735.0, 137438953471.0,
+      274877906943.0, 549755813887.0, 1099511627775.0, 2199023255551.0,
+      4398046511103.0, 8796093022207.0, 17592186044415.0, 35184372088831.0,
+      70368744177663.0, 140737488355327.0, 281474976710655.0,
+      562949953421311.0};
+  STATIC_ASSERT(arraysize(kWeakenMinLimits) == arraysize(kWeakenMaxLimits));
+
   // If the types have nothing to do with integers, return the types.
-  if (!current_type->Maybe(typer_->integer) ||
-      !previous_type->Maybe(typer_->integer)) {
+  if (!previous_type->Maybe(typer_->integer)) {
     return current_type;
   }
+  DCHECK(current_type->Maybe(typer_->integer));
 
-  Type* previous_number =
+  Type* current_integer =
+      Type::Intersect(current_type, typer_->integer, zone());
+  Type* previous_integer =
       Type::Intersect(previous_type, typer_->integer, zone());
-  Type* current_number = Type::Intersect(current_type, typer_->integer, zone());
-  if (!current_number->IsRange() || !previous_number->IsRange()) {
-    return current_type;
-  }
 
-  Type::RangeType* previous = previous_number->AsRange();
-  Type::RangeType* current = current_number->AsRange();
+  // Once we start weakening a node, we should always weaken.
+  if (!IsWeakened(node->id())) {
+    // Only weaken if there is range involved; we should converge quickly
+    // for all other types (the exception is a union of many constants,
+    // but we currently do not increase the number of constants in unions).
+    Type::RangeType* previous = previous_integer->GetRange();
+    Type::RangeType* current = current_integer->GetRange();
+    if (current == nullptr || previous == nullptr) {
+      return current_type;
+    }
+    // Range is involved => we are weakening.
+    SetWeakened(node->id());
+  }
 
-  double current_min = current->Min();
+  double current_min = current_integer->Min();
   double 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()) {
+  if (current_min != previous_integer->Min()) {
     new_min = typer_->integer->AsRange()->Min();
-    for (const auto val : typer_->weaken_min_limits_) {
-      if (val <= current_min) {
-        new_min = val;
+    for (double const min : kWeakenMinLimits) {
+      if (min <= current_min) {
+        new_min = min;
         break;
       }
     }
   }
 
-  double current_max = current->Max();
+  double current_max = current_integer->Max();
   double 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()) {
+  if (current_max != previous_integer->Max()) {
     new_max = typer_->integer->AsRange()->Max();
-    for (const auto val : typer_->weaken_max_limits_) {
-      if (val >= current_max) {
-        new_max = val;
+    for (double const max : kWeakenMaxLimits) {
+      if (max >= current_max) {
+        new_max = max;
         break;
       }
     }
@@ -1506,6 +1530,23 @@ Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) {
     case Runtime::kInlineIsFunction:
     case Runtime::kInlineIsRegExp:
       return Bounds(Type::None(zone()), Type::Boolean(zone()));
+    case Runtime::kInlineDoubleLo:
+    case Runtime::kInlineDoubleHi:
+      return Bounds(Type::None(zone()), Type::Signed32());
+    case Runtime::kInlineConstructDouble:
+    case Runtime::kInlineMathFloor:
+    case Runtime::kInlineMathSqrt:
+    case Runtime::kInlineMathAcos:
+    case Runtime::kInlineMathAsin:
+    case Runtime::kInlineMathAtan:
+    case Runtime::kInlineMathAtan2:
+      return Bounds(Type::None(zone()), Type::Number());
+    case Runtime::kInlineMathClz32:
+      return Bounds(Type::None(), Type::Range(0, 32, zone()));
+    case Runtime::kInlineStringGetLength:
+      // The string::length property is always an unsigned smi.
+      return Bounds(Type::None(), Type::Intersect(Type::UnsignedSmall(),
+                                                  Type::TaggedSigned()));
     default:
       break;
   }
@@ -1513,7 +1554,7 @@ Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) {
 }
 
 
-Bounds Typer::Visitor::TypeJSDebugger(Node* node) {
+Bounds Typer::Visitor::TypeJSStackCheck(Node* node) {
   return Bounds::Unbounded(zone());
 }
 
@@ -1521,11 +1562,6 @@ Bounds Typer::Visitor::TypeJSDebugger(Node* node) {
 // Simplified operators.
 
 
-Bounds Typer::Visitor::TypeAnyToBoolean(Node* node) {
-  return TypeUnaryOp(node, ToBoolean);
-}
-
-
 Bounds Typer::Visitor::TypeBooleanNot(Node* node) {
   return Bounds(Type::None(zone()), Type::Boolean(zone()));
 }
@@ -1616,16 +1652,15 @@ Bounds Typer::Visitor::TypeStringAdd(Node* node) {
 }
 
 
-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;
+namespace {
+
+Type* ChangeRepresentation(Type* type, Type* rep, Zone* zone) {
+  return Type::Union(Type::Semantic(type, zone),
+                     Type::Representation(rep, zone), zone);
 }
 
+}  // namespace
+
 
 Bounds Typer::Visitor::TypeChangeTaggedToInt32(Node* node) {
   Bounds arg = Operand(node, 0);
@@ -1657,9 +1692,12 @@ Bounds Typer::Visitor::TypeChangeTaggedToFloat64(Node* node) {
 Bounds Typer::Visitor::TypeChangeInt32ToTagged(Node* node) {
   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()));
+  Type* lower_rep = arg.lower->Is(Type::SignedSmall()) ? Type::TaggedSigned()
+                                                       : Type::Tagged();
+  Type* upper_rep = arg.upper->Is(Type::SignedSmall()) ? Type::TaggedSigned()
+                                                       : Type::Tagged();
+  return Bounds(ChangeRepresentation(arg.lower, lower_rep, zone()),
+                ChangeRepresentation(arg.upper, upper_rep, zone()));
 }
 
 
@@ -1804,6 +1842,11 @@ Bounds Typer::Visitor::TypeWord32Equal(Node* node) {
 }
 
 
+Bounds Typer::Visitor::TypeWord32Clz(Node* node) {
+  return Bounds(Type::Integral32());
+}
+
+
 Bounds Typer::Visitor::TypeWord64And(Node* node) {
   return Bounds(Type::Internal());
 }
@@ -2052,6 +2095,16 @@ Bounds Typer::Visitor::TypeFloat64Mod(Node* node) {
 }
 
 
+Bounds Typer::Visitor::TypeFloat64Max(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64Min(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
 Bounds Typer::Visitor::TypeFloat64Sqrt(Node* node) {
   return Bounds(Type::Number());
 }
@@ -2072,26 +2125,40 @@ Bounds Typer::Visitor::TypeFloat64LessThanOrEqual(Node* node) {
 }
 
 
-Bounds Typer::Visitor::TypeFloat64Floor(Node* node) {
+Bounds Typer::Visitor::TypeFloat64RoundDown(Node* node) {
   // TODO(sigurds): We could have a tighter bound here.
   return Bounds(Type::Number());
 }
 
 
-Bounds Typer::Visitor::TypeFloat64Ceil(Node* node) {
+Bounds Typer::Visitor::TypeFloat64RoundTruncate(Node* node) {
   // TODO(sigurds): We could have a tighter bound here.
   return Bounds(Type::Number());
 }
 
 
-Bounds Typer::Visitor::TypeFloat64RoundTruncate(Node* node) {
+Bounds Typer::Visitor::TypeFloat64RoundTiesAway(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.
+Bounds Typer::Visitor::TypeFloat64ExtractLowWord32(Node* node) {
+  return Bounds(Type::Signed32());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64ExtractHighWord32(Node* node) {
+  return Bounds(Type::Signed32());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64InsertLowWord32(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64InsertHighWord32(Node* node) {
   return Bounds(Type::Number());
 }
 
index a288d06..4c04ddb 100644 (file)
@@ -6,7 +6,6 @@
 #define V8_COMPILER_TYPER_H_
 
 #include "src/compiler/graph.h"
-#include "src/compiler/opcodes.h"
 #include "src/types.h"
 
 namespace v8 {
@@ -63,8 +62,6 @@ class Typer {
   Type* random_fun_;
   LazyTypeCache* cache_;
 
-  ZoneVector<double> weaken_min_limits_;
-  ZoneVector<double> weaken_max_limits_;
   DISALLOW_COPY_AND_ASSIGN(Typer);
 };
 
index 9480afb..0768ece 100644 (file)
@@ -125,8 +125,8 @@ void Verifier::Visitor::Check(Node* node) {
   CHECK_EQ(input_count, node->InputCount());
 
   // Verify that frame state has been inserted for the nodes that need it.
-  if (OperatorProperties::HasFrameStateInput(node->op())) {
-    Node* frame_state = NodeProperties::GetFrameStateInput(node);
+  for (int i = 0; i < frame_state_count; i++) {
+    Node* frame_state = NodeProperties::GetFrameStateInput(node, i);
     CHECK(frame_state->opcode() == IrOpcode::kFrameState ||
           // kFrameState uses undefined as a sentinel.
           (node->opcode() == IrOpcode::kFrameState &&
@@ -228,6 +228,15 @@ void Verifier::Visitor::Check(Node* node) {
       // Type is empty.
       CheckNotTyped(node);
       break;
+    case IrOpcode::kIfSuccess:
+    case IrOpcode::kIfException: {
+      // IfSuccess and IfException continuation only on throwing nodes.
+      Node* input = NodeProperties::GetControlInput(node, 0);
+      CHECK(!input->op()->HasProperty(Operator::kNoThrow));
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    }
     case IrOpcode::kSwitch: {
       // Switch uses are Case and Default.
       int count_case = 0, count_default = 0;
@@ -273,6 +282,10 @@ void Verifier::Visitor::Check(Node* node) {
       // Type is empty.
       CheckNotTyped(node);
       break;
+    case IrOpcode::kDeoptimize:
+      // TODO(rossberg): check successor is End
+      // Type is empty.
+      CheckNotTyped(node);
     case IrOpcode::kReturn:
       // TODO(rossberg): check successor is End
       // Type is empty.
@@ -414,6 +427,7 @@ void Verifier::Visitor::Check(Node* node) {
       // TODO(jarin): what are the constraints on these?
       break;
     case IrOpcode::kStateValues:
+    case IrOpcode::kTypedStateValues:
       // TODO(jarin): what are the constraints on these?
       break;
     case IrOpcode::kCall:
@@ -532,17 +546,17 @@ void Verifier::Visitor::Check(Node* node) {
     case IrOpcode::kJSCallFunction:
     case IrOpcode::kJSCallRuntime:
     case IrOpcode::kJSYield:
-    case IrOpcode::kJSDebugger:
       // Type can be anything.
       CheckUpperIs(node, Type::Any());
       break;
 
+    case IrOpcode::kJSStackCheck:
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+
     // Simplified operators
     // -------------------------------
-    case IrOpcode::kAnyToBoolean:
-      // Type is Boolean.
-      CheckUpperIs(node, Type::Boolean());
-      break;
     case IrOpcode::kBooleanNot:
       // Boolean -> Boolean
       CheckValueInputIs(node, 0, Type::Boolean());
@@ -604,10 +618,6 @@ void Verifier::Visitor::Check(Node* node) {
     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;
     }
@@ -736,6 +746,7 @@ void Verifier::Visitor::Check(Node* node) {
     case IrOpcode::kWord32Sar:
     case IrOpcode::kWord32Ror:
     case IrOpcode::kWord32Equal:
+    case IrOpcode::kWord32Clz:
     case IrOpcode::kWord64And:
     case IrOpcode::kWord64Or:
     case IrOpcode::kWord64Xor:
@@ -774,9 +785,10 @@ void Verifier::Visitor::Check(Node* node) {
     case IrOpcode::kFloat64Mul:
     case IrOpcode::kFloat64Div:
     case IrOpcode::kFloat64Mod:
+    case IrOpcode::kFloat64Max:
+    case IrOpcode::kFloat64Min:
     case IrOpcode::kFloat64Sqrt:
-    case IrOpcode::kFloat64Floor:
-    case IrOpcode::kFloat64Ceil:
+    case IrOpcode::kFloat64RoundDown:
     case IrOpcode::kFloat64RoundTruncate:
     case IrOpcode::kFloat64RoundTiesAway:
     case IrOpcode::kFloat64Equal:
@@ -792,13 +804,17 @@ void Verifier::Visitor::Check(Node* node) {
     case IrOpcode::kChangeFloat32ToFloat64:
     case IrOpcode::kChangeFloat64ToInt32:
     case IrOpcode::kChangeFloat64ToUint32:
+    case IrOpcode::kFloat64ExtractLowWord32:
+    case IrOpcode::kFloat64ExtractHighWord32:
+    case IrOpcode::kFloat64InsertLowWord32:
+    case IrOpcode::kFloat64InsertHighWord32:
     case IrOpcode::kLoadStackPointer:
     case IrOpcode::kCheckedLoad:
     case IrOpcode::kCheckedStore:
       // TODO(rossberg): Check.
       break;
   }
-}
+}  // NOLINT(readability/fn_size)
 
 
 void Verifier::Run(Graph* graph, Typing typing) {
@@ -806,7 +822,23 @@ void Verifier::Run(Graph* graph, Typing typing) {
   CHECK_NOT_NULL(graph->end());
   Zone zone;
   Visitor visitor(&zone, typing);
-  for (Node* node : AllNodes(&zone, graph).live) visitor.Check(node);
+  AllNodes all(&zone, graph);
+  for (Node* node : all.live) visitor.Check(node);
+
+  // Check the uniqueness of projections.
+  for (Node* proj : all.live) {
+    if (proj->opcode() != IrOpcode::kProjection) continue;
+    Node* node = proj->InputAt(0);
+    for (Node* other : node->uses()) {
+      if (all.IsLive(other) && other != proj &&
+          other->opcode() == IrOpcode::kProjection &&
+          ProjectionIndexOf(other->op()) == ProjectionIndexOf(proj->op())) {
+        V8_Fatal(__FILE__, __LINE__,
+                 "Node #%d:%s has duplicate projections #%d and #%d",
+                 node->id(), node->op()->mnemonic(), proj->id(), other->id());
+      }
+    }
+  }
 }
 
 
@@ -856,7 +888,7 @@ static void CheckInputsDominate(Schedule* schedule, BasicBlock* 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().ToInt(), j,
+               node->id(), node->op()->mnemonic(), block->rpo_number(), j,
                input->id(), input->op()->mnemonic());
     }
   }
@@ -869,8 +901,8 @@ static void CheckInputsDominate(Schedule* schedule, BasicBlock* block,
     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());
+               node->id(), node->op()->mnemonic(), block->rpo_number(),
+               ctl->id(), ctl->op()->mnemonic());
     }
   }
 }
@@ -964,7 +996,7 @@ void ScheduleVerifier::Run(Schedule* schedule) {
       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().ToInt(), idom->id().ToInt());
+                 block->rpo_number(), idom->rpo_number());
       }
       for (size_t s = 0; s < block->SuccessorCount(); s++) {
         BasicBlock* succ = block->SuccessorAt(s);
@@ -1002,7 +1034,7 @@ void ScheduleVerifier::Run(Schedule* schedule) {
             !dominators[idom->id().ToSize()]->Contains(dom->id().ToInt())) {
           V8_Fatal(__FILE__, __LINE__,
                    "Block B%d is not immediately dominated by B%d",
-                   block->id().ToInt(), idom->id().ToInt());
+                   block->rpo_number(), idom->rpo_number());
         }
       }
     }
index 973bbd1..3160734 100644 (file)
@@ -18,17 +18,22 @@ namespace compiler {
 #define __ masm()->
 
 
+#define kScratchDoubleReg xmm0
+
+
 // Adds X64 specific methods for decoding operands.
 class X64OperandConverter : public InstructionOperandConverter {
  public:
   X64OperandConverter(CodeGenerator* gen, Instruction* instr)
       : InstructionOperandConverter(gen, instr) {}
 
-  Immediate InputImmediate(int index) {
+  Immediate InputImmediate(size_t index) {
     return ToImmediate(instr_->InputAt(index));
   }
 
-  Operand InputOperand(int index) { return ToOperand(instr_->InputAt(index)); }
+  Operand InputOperand(size_t index, int extra = 0) {
+    return ToOperand(instr_->InputAt(index), extra);
+  }
 
   Operand OutputOperand() { return ToOperand(instr_->Output()); }
 
@@ -43,8 +48,8 @@ class X64OperandConverter : public InstructionOperandConverter {
     return Operand(offset.from_stack_pointer() ? rsp : rbp, offset.offset());
   }
 
-  static int NextOffset(int* offset) {
-    int i = *offset;
+  static size_t NextOffset(size_t* offset) {
+    size_t i = *offset;
     (*offset)++;
     return i;
   }
@@ -59,7 +64,7 @@ class X64OperandConverter : public InstructionOperandConverter {
     return static_cast<ScaleFactor>(scale);
   }
 
-  Operand MemoryOperand(int* offset) {
+  Operand MemoryOperand(size_t* offset) {
     AddressingMode mode = AddressingModeField::decode(instr_->opcode());
     switch (mode) {
       case kMode_MR: {
@@ -124,7 +129,7 @@ class X64OperandConverter : public InstructionOperandConverter {
     return Operand(no_reg, 0);
   }
 
-  Operand MemoryOperand(int first_input = 0) {
+  Operand MemoryOperand(size_t first_input = 0) {
     return MemoryOperand(&first_input);
   }
 };
@@ -132,7 +137,7 @@ class X64OperandConverter : public InstructionOperandConverter {
 
 namespace {
 
-bool HasImmediateInput(Instruction* instr, int index) {
+bool HasImmediateInput(Instruction* instr, size_t index) {
   return instr->InputAt(index)->IsImmediate();
 }
 
@@ -526,7 +531,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         int entry = Code::kHeaderSize - kHeapObjectTag;
         __ Call(Operand(reg, entry));
       }
-      AddSafepointAndDeopt(instr);
+      RecordCallPosition(instr);
       break;
     }
     case kArchCallJSFunction: {
@@ -538,7 +543,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         __ Assert(equal, kWrongFunctionContext);
       }
       __ Call(FieldOperand(func, JSFunction::kCodeEntryOffset));
-      AddSafepointAndDeopt(instr);
+      RecordCallPosition(instr);
       break;
     }
     case kArchJmp:
@@ -553,6 +558,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArchNop:
       // don't emit code for nops.
       break;
+    case kArchDeoptimize: {
+      int deopt_state_id =
+          BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
+      AssembleDeoptimizerCall(deopt_state_id, Deoptimizer::EAGER);
+      break;
+    }
     case kArchRet:
       AssembleReturn();
       break;
@@ -683,6 +694,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kX64Ror:
       ASSEMBLE_SHIFT(rorq, 6);
       break;
+    case kX64Lzcnt32:
+      if (instr->InputAt(0)->IsRegister()) {
+        __ Lzcntl(i.OutputRegister(), i.InputRegister(0));
+      } else {
+        __ Lzcntl(i.OutputRegister(), i.InputOperand(0));
+      }
+      break;
     case kSSEFloat64Cmp:
       ASSEMBLE_DOUBLE_BINOP(ucomisd);
       break;
@@ -730,6 +748,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ addq(rsp, Immediate(kDoubleSize));
       break;
     }
+    case kSSEFloat64Max:
+      ASSEMBLE_DOUBLE_BINOP(maxsd);
+      break;
+    case kSSEFloat64Min:
+      ASSEMBLE_DOUBLE_BINOP(minsd);
+      break;
     case kSSEFloat64Sqrt:
       if (instr->InputAt(0)->IsDoubleRegister()) {
         __ sqrtsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
@@ -737,22 +761,11 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0));
       }
       break;
-    case kSSEFloat64Floor: {
+    case kSSEFloat64Round: {
       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);
+      RoundingMode const mode =
+          static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
+      __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
       break;
     }
     case kSSECvtss2sd:
@@ -800,6 +813,41 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       }
       __ cvtqsi2sd(i.OutputDoubleRegister(), kScratchRegister);
       break;
+    case kSSEFloat64ExtractLowWord32:
+      if (instr->InputAt(0)->IsDoubleStackSlot()) {
+        __ movl(i.OutputRegister(), i.InputOperand(0));
+      } else {
+        __ movd(i.OutputRegister(), i.InputDoubleRegister(0));
+      }
+      break;
+    case kSSEFloat64ExtractHighWord32:
+      if (instr->InputAt(0)->IsDoubleStackSlot()) {
+        __ movl(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
+      } else {
+        __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1);
+      }
+      break;
+    case kSSEFloat64InsertLowWord32:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 0);
+      } else {
+        __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0);
+      }
+      break;
+    case kSSEFloat64InsertHighWord32:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 1);
+      } else {
+        __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1);
+      }
+      break;
+    case kSSEFloat64LoadLowWord32:
+      if (instr->InputAt(0)->IsRegister()) {
+        __ movd(i.OutputDoubleRegister(), i.InputRegister(0));
+      } else {
+        __ movd(i.OutputDoubleRegister(), i.InputOperand(0));
+      }
+      break;
     case kAVXFloat64Add:
       ASSEMBLE_AVX_DOUBLE_BINOP(vaddsd);
       break;
@@ -812,6 +860,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kAVXFloat64Div:
       ASSEMBLE_AVX_DOUBLE_BINOP(vdivsd);
       break;
+    case kAVXFloat64Max:
+      ASSEMBLE_AVX_DOUBLE_BINOP(vmaxsd);
+      break;
+    case kAVXFloat64Min:
+      ASSEMBLE_AVX_DOUBLE_BINOP(vminsd);
+      break;
     case kX64Movsxbl:
       ASSEMBLE_MOVX(movsxbl);
       __ AssertZeroExtended(i.OutputRegister());
@@ -821,7 +875,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ AssertZeroExtended(i.OutputRegister());
       break;
     case kX64Movb: {
-      int index = 0;
+      size_t index = 0;
       Operand operand = i.MemoryOperand(&index);
       if (HasImmediateInput(instr, index)) {
         __ movb(operand, Immediate(i.InputInt8(index)));
@@ -839,7 +893,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ AssertZeroExtended(i.OutputRegister());
       break;
     case kX64Movw: {
-      int index = 0;
+      size_t index = 0;
       Operand operand = i.MemoryOperand(&index);
       if (HasImmediateInput(instr, index)) {
         __ movw(operand, Immediate(i.InputInt16(index)));
@@ -861,7 +915,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         }
         __ AssertZeroExtended(i.OutputRegister());
       } else {
-        int index = 0;
+        size_t index = 0;
         Operand operand = i.MemoryOperand(&index);
         if (HasImmediateInput(instr, index)) {
           __ movl(operand, i.InputImmediate(index));
@@ -877,7 +931,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       if (instr->HasOutput()) {
         __ movq(i.OutputRegister(), i.MemoryOperand());
       } else {
-        int index = 0;
+        size_t index = 0;
         Operand operand = i.MemoryOperand(&index);
         if (HasImmediateInput(instr, index)) {
           __ movq(operand, i.InputImmediate(index));
@@ -890,7 +944,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       if (instr->HasOutput()) {
         __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
       } else {
-        int index = 0;
+        size_t index = 0;
         Operand operand = i.MemoryOperand(&index);
         __ movss(operand, i.InputDoubleRegister(index));
       }
@@ -899,7 +953,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       if (instr->HasOutput()) {
         __ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
       } else {
-        int index = 0;
+        size_t index = 0;
         Operand operand = i.MemoryOperand(&index);
         __ movsd(operand, i.InputDoubleRegister(index));
       }
@@ -1005,8 +1059,11 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kCheckedStoreFloat64:
       ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
       break;
+    case kX64StackCheck:
+      __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
+      break;
   }
-}
+}  // NOLINT(readability/fn_size)
 
 
 // Assembles branches after this instruction.
@@ -1064,7 +1121,7 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
 }
 
 
-void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+void CodeGenerator::AssembleArchJump(RpoNumber target) {
   if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
 }
 
@@ -1078,8 +1135,8 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
   // 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, static_cast<int>(instr->OutputCount()));
-  Register reg = i.OutputRegister(static_cast<int>(instr->OutputCount() - 1));
+  DCHECK_NE(0u, instr->OutputCount());
+  Register reg = i.OutputRegister(instr->OutputCount() - 1);
   Condition cc = no_condition;
   switch (condition) {
     case kUnorderedEqual:
@@ -1140,8 +1197,8 @@ void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
   X64OperandConverter i(this, instr);
   Register input = i.InputRegister(0);
   for (size_t index = 2; index < instr->InputCount(); index += 2) {
-    __ cmpl(input, Immediate(i.InputInt32(static_cast<int>(index + 0))));
-    __ j(equal, GetLabel(i.InputRpo(static_cast<int>(index + 1))));
+    __ cmpl(input, Immediate(i.InputInt32(index + 0)));
+    __ j(equal, GetLabel(i.InputRpo(index + 1)));
   }
   AssembleArchJump(i.InputRpo(1));
 }
@@ -1163,9 +1220,10 @@ void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
 }
 
 
-void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
+void CodeGenerator::AssembleDeoptimizerCall(
+    int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
-      isolate(), deoptimization_id, Deoptimizer::LAZY);
+      isolate(), deoptimization_id, bailout_type);
   __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
 }
 
@@ -1207,6 +1265,8 @@ void CodeGenerator::AssemblePrologue() {
     // remaining stack slots.
     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
     osr_pc_offset_ = __ pc_offset();
+    // TODO(titzer): cannot address target function == local #-1
+    __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
     DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
     stack_slots -= frame()->GetOsrStackSlotCount();
   }
@@ -1307,9 +1367,18 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
         case Constant::kExternalReference:
           __ Move(dst, src.ToExternalReference());
           break;
-        case Constant::kHeapObject:
-          __ Move(dst, src.ToHeapObject());
+        case Constant::kHeapObject: {
+          Handle<HeapObject> src_object = src.ToHeapObject();
+          if (info()->IsOptimizing() &&
+              src_object.is_identical_to(info()->context())) {
+            // Loading the context from the frame is way cheaper than
+            // materializing the actual context heap object address.
+            __ movp(dst, Operand(rbp, StandardFrameConstants::kContextOffset));
+          } else {
+            __ Move(dst, src_object);
+          }
           break;
+        }
         case Constant::kRpoNumber:
           UNREACHABLE();  // TODO(dcarney): load of labels on x64.
           break;
@@ -1342,7 +1411,7 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
     XMMRegister src = g.ToDoubleRegister(source);
     if (destination->IsDoubleRegister()) {
       XMMRegister dst = g.ToDoubleRegister(destination);
-      __ movsd(dst, src);
+      __ movaps(dst, src);
     } else {
       DCHECK(destination->IsDoubleStackSlot());
       Operand dst = g.ToOperand(destination);
@@ -1393,9 +1462,9 @@ void CodeGenerator::AssembleSwap(InstructionOperand* source,
     // available as a fixed scratch register.
     XMMRegister src = g.ToDoubleRegister(source);
     XMMRegister dst = g.ToDoubleRegister(destination);
-    __ movsd(xmm0, src);
-    __ movsd(src, dst);
-    __ movsd(dst, xmm0);
+    __ movaps(xmm0, src);
+    __ movaps(src, dst);
+    __ movaps(dst, xmm0);
   } else if (source->IsDoubleRegister() && destination->IsDoubleStackSlot()) {
     // XMM register-memory swap.  We rely on having xmm0
     // available as a fixed scratch register.
index 77e3e52..9416017 100644 (file)
@@ -46,6 +46,7 @@ namespace compiler {
   V(X64Sar32)                      \
   V(X64Ror)                        \
   V(X64Ror32)                      \
+  V(X64Lzcnt32)                    \
   V(SSEFloat64Cmp)                 \
   V(SSEFloat64Add)                 \
   V(SSEFloat64Sub)                 \
@@ -53,19 +54,26 @@ namespace compiler {
   V(SSEFloat64Div)                 \
   V(SSEFloat64Mod)                 \
   V(SSEFloat64Sqrt)                \
-  V(SSEFloat64Floor)               \
-  V(SSEFloat64Ceil)                \
-  V(SSEFloat64RoundTruncate)       \
+  V(SSEFloat64Round)               \
+  V(SSEFloat64Max)                 \
+  V(SSEFloat64Min)                 \
   V(SSECvtss2sd)                   \
   V(SSECvtsd2ss)                   \
   V(SSEFloat64ToInt32)             \
   V(SSEFloat64ToUint32)            \
   V(SSEInt32ToFloat64)             \
   V(SSEUint32ToFloat64)            \
+  V(SSEFloat64ExtractLowWord32)    \
+  V(SSEFloat64ExtractHighWord32)   \
+  V(SSEFloat64InsertLowWord32)     \
+  V(SSEFloat64InsertHighWord32)    \
+  V(SSEFloat64LoadLowWord32)       \
   V(AVXFloat64Add)                 \
   V(AVXFloat64Sub)                 \
   V(AVXFloat64Mul)                 \
   V(AVXFloat64Div)                 \
+  V(AVXFloat64Max)                 \
+  V(AVXFloat64Min)                 \
   V(X64Movsxbl)                    \
   V(X64Movzxbl)                    \
   V(X64Movb)                       \
@@ -82,7 +90,8 @@ namespace compiler {
   V(X64Dec32)                      \
   V(X64Inc32)                      \
   V(X64Push)                       \
-  V(X64StoreWriteBarrier)
+  V(X64StoreWriteBarrier)          \
+  V(X64StackCheck)
 
 
 // Addressing modes represent the "shape" of inputs to an instruction.
index db2d8cb..a948257 100644 (file)
@@ -346,14 +346,13 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
     outputs[output_count++] = g.DefineAsRegister(cont->result());
   }
 
-  DCHECK_NE(0, static_cast<int>(input_count));
-  DCHECK_NE(0, static_cast<int>(output_count));
+  DCHECK_NE(0u, input_count);
+  DCHECK_NE(0u, 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();
+  selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
+                 inputs);
 }
 
 
@@ -471,7 +470,7 @@ void EmitLea(InstructionSelector* selector, InstructionCode opcode,
   AddressingMode mode = g.GenerateMemoryOperandInputs(
       index, scale, base, displacement, inputs, &input_count);
 
-  DCHECK_NE(0, static_cast<int>(input_count));
+  DCHECK_NE(0u, input_count);
   DCHECK_GE(arraysize(inputs), input_count);
 
   InstructionOperand outputs[1];
@@ -555,6 +554,12 @@ void InstructionSelector::VisitWord64Ror(Node* node) {
 }
 
 
+void InstructionSelector::VisitWord32Clz(Node* node) {
+  X64OperandGenerator g(this);
+  Emit(kX64Lzcnt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitInt32Add(Node* node) {
   X64OperandGenerator g(this);
 
@@ -844,6 +849,19 @@ void InstructionSelector::VisitFloat64Add(Node* node) {
 
 void InstructionSelector::VisitFloat64Sub(Node* node) {
   X64OperandGenerator g(this);
+  Float64BinopMatcher m(node);
+  if (m.left().IsMinusZero() && m.right().IsFloat64RoundDown() &&
+      CanCover(m.node(), m.right().node())) {
+    if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
+        CanCover(m.right().node(), m.right().InputAt(0))) {
+      Float64BinopMatcher mright0(m.right().InputAt(0));
+      if (mright0.left().IsMinusZero()) {
+        Emit(kSSEFloat64Round | MiscField::encode(kRoundUp),
+             g.DefineAsRegister(node), g.UseRegister(mright0.right().node()));
+        return;
+      }
+    }
+  }
   if (IsSupported(AVX)) {
     Emit(kAVXFloat64Sub, g.DefineAsRegister(node),
          g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
@@ -887,6 +905,30 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64Max(Node* node) {
+  X64OperandGenerator g(this);
+  if (IsSupported(AVX)) {
+    Emit(kAVXFloat64Max, g.DefineAsRegister(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  } else {
+    Emit(kSSEFloat64Max, g.DefineSameAsFirst(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  }
+}
+
+
+void InstructionSelector::VisitFloat64Min(Node* node) {
+  X64OperandGenerator g(this);
+  if (IsSupported(AVX)) {
+    Emit(kAVXFloat64Min, g.DefineAsRegister(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  } else {
+    Emit(kSSEFloat64Min, g.DefineSameAsFirst(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  }
+}
+
+
 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
   X64OperandGenerator g(this);
   Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
@@ -895,7 +937,7 @@ void InstructionSelector::VisitFloat64Sqrt(Node* node) {
 
 namespace {
 
-void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
+void VisitRRFloat64(InstructionSelector* selector, InstructionCode opcode,
                     Node* node) {
   X64OperandGenerator g(selector);
   selector->Emit(opcode, g.DefineAsRegister(node),
@@ -905,21 +947,14 @@ void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
 }  // namespace
 
 
-void InstructionSelector::VisitFloat64Floor(Node* node) {
-  DCHECK(CpuFeatures::IsSupported(SSE4_1));
-  VisitRRFloat64(this, kSSEFloat64Floor, node);
-}
-
-
-void InstructionSelector::VisitFloat64Ceil(Node* node) {
-  DCHECK(CpuFeatures::IsSupported(SSE4_1));
-  VisitRRFloat64(this, kSSEFloat64Ceil, node);
+void InstructionSelector::VisitFloat64RoundDown(Node* node) {
+  VisitRRFloat64(this, kSSEFloat64Round | MiscField::encode(kRoundDown), node);
 }
 
 
 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
-  DCHECK(CpuFeatures::IsSupported(SSE4_1));
-  VisitRRFloat64(this, kSSEFloat64RoundTruncate, node);
+  VisitRRFloat64(this, kSSEFloat64Round | MiscField::encode(kRoundToZero),
+                 node);
 }
 
 
@@ -928,7 +963,7 @@ void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
 }
 
 
-void InstructionSelector::VisitCall(Node* node) {
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
   X64OperandGenerator g(this);
   const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
 
@@ -954,6 +989,13 @@ void InstructionSelector::VisitCall(Node* node) {
     Emit(kX64Push, g.NoOutput(), value);
   }
 
+  // Pass label of exception handler block.
+  CallDescriptor::Flags flags = descriptor->flags();
+  if (handler != nullptr) {
+    flags |= CallDescriptor::kHasExceptionHandler;
+    buffer.instruction_args.push_back(g.Label(handler));
+  }
+
   // Select the appropriate opcode based on the call type.
   InstructionCode opcode;
   switch (descriptor->kind()) {
@@ -968,7 +1010,7 @@ void InstructionSelector::VisitCall(Node* node) {
       UNREACHABLE();
       return;
   }
-  opcode |= MiscField::encode(descriptor->flags());
+  opcode |= MiscField::encode(flags);
 
   // Emit the call instruction.
   InstructionOperand* first_output =
@@ -980,16 +1022,17 @@ void InstructionSelector::VisitCall(Node* node) {
 }
 
 
+namespace {
+
 // Shared routine for multiple compare operations.
-static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
-                         InstructionOperand left, InstructionOperand right,
-                         FlagsContinuation* cont) {
+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, g.NoOutput(), left, right,
-                   g.Label(cont->true_block()),
-                   g.Label(cont->false_block()))->MarkAsControl();
+                   g.Label(cont->true_block()), g.Label(cont->false_block()));
   } else {
     DCHECK(cont->IsSet());
     selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
@@ -998,9 +1041,9 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
 
 
 // Shared routine for multiple compare operations.
-static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
-                         Node* left, Node* right, FlagsContinuation* cont,
-                         bool commutative) {
+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);
@@ -1010,8 +1053,8 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
 
 
 // Shared routine for multiple word compare operations.
-static void VisitWordCompare(InstructionSelector* selector, Node* node,
-                             InstructionCode opcode, FlagsContinuation* cont) {
+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);
@@ -1029,22 +1072,51 @@ static void VisitWordCompare(InstructionSelector* selector, Node* node,
 }
 
 
+// Shared routine for 64-bit word comparison operations.
+void VisitWord64Compare(InstructionSelector* selector, Node* node,
+                        FlagsContinuation* cont) {
+  X64OperandGenerator g(selector);
+  Int64BinopMatcher m(node);
+  if (m.left().IsLoad() && m.right().IsLoadStackPointer()) {
+    LoadMatcher<ExternalReferenceMatcher> mleft(m.left().node());
+    ExternalReference js_stack_limit =
+        ExternalReference::address_of_stack_limit(selector->isolate());
+    if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) {
+      // Compare(Load(js_stack_limit), LoadStackPointer)
+      if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
+      InstructionCode opcode = cont->Encode(kX64StackCheck);
+      if (cont->IsBranch()) {
+        selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()),
+                       g.Label(cont->false_block()));
+      } else {
+        DCHECK(cont->IsSet());
+        selector->Emit(opcode, g.DefineAsRegister(cont->result()));
+      }
+      return;
+    }
+  }
+  VisitWordCompare(selector, node, kX64Cmp, cont);
+}
+
+
 // Shared routine for comparison with zero.
-static void VisitCompareZero(InstructionSelector* selector, Node* node,
-                             InstructionCode opcode, FlagsContinuation* cont) {
+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 (inputs commuted).
-static void VisitFloat64Compare(InstructionSelector* selector, Node* node,
-                                FlagsContinuation* cont) {
+void VisitFloat64Compare(InstructionSelector* selector, Node* node,
+                         FlagsContinuation* cont) {
   Node* const left = node->InputAt(0);
   Node* const right = node->InputAt(1);
   VisitCompare(selector, kSSEFloat64Cmp, right, left, cont, false);
 }
 
+}  // namespace
+
 
 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
                                       BasicBlock* fbranch) {
@@ -1055,25 +1127,12 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
   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;
-      }
+  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;
     }
@@ -1099,16 +1158,16 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
         return VisitWordCompare(this, value, kX64Cmp32, &cont);
       case IrOpcode::kWord64Equal:
         cont.OverwriteAndNegateIfEqual(kEqual);
-        return VisitWordCompare(this, value, kX64Cmp, &cont);
+        return VisitWord64Compare(this, value, &cont);
       case IrOpcode::kInt64LessThan:
         cont.OverwriteAndNegateIfEqual(kSignedLessThan);
-        return VisitWordCompare(this, value, kX64Cmp, &cont);
+        return VisitWord64Compare(this, value, &cont);
       case IrOpcode::kInt64LessThanOrEqual:
         cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
-        return VisitWordCompare(this, value, kX64Cmp, &cont);
+        return VisitWord64Compare(this, value, &cont);
       case IrOpcode::kUint64LessThan:
         cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
-        return VisitWordCompare(this, value, kX64Cmp, &cont);
+        return VisitWord64Compare(this, value, &cont);
       case IrOpcode::kFloat64Equal:
         cont.OverwriteAndNegateIfEqual(kUnorderedEqual);
         return VisitFloat64Compare(this, value, &cont);
@@ -1146,7 +1205,7 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
       case IrOpcode::kInt32Sub:
         return VisitWordCompare(this, value, kX64Cmp32, &cont);
       case IrOpcode::kInt64Sub:
-        return VisitWordCompare(this, value, kX64Cmp, &cont);
+        return VisitWord64Compare(this, value, &cont);
       case IrOpcode::kWord32And:
         return VisitWordCompare(this, value, kX64Test32, &cont);
       case IrOpcode::kWord64And:
@@ -1161,67 +1220,34 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
 }
 
 
-void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
-                                      BasicBlock** case_branches,
-                                      int32_t* case_values, size_t case_count,
-                                      int32_t min_value, int32_t max_value) {
+void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
   X64OperandGenerator g(this);
   InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
-  InstructionOperand default_operand = g.Label(default_branch);
-
-  // Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value}
-  // is 2^31-1, so don't assume that it's non-zero below.
-  size_t value_range =
-      1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
 
-  // Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
-  // instruction.
-  size_t table_space_cost = 4 + value_range;
+  // Emit either ArchTableSwitch or ArchLookupSwitch.
+  size_t table_space_cost = 4 + sw.value_range;
   size_t table_time_cost = 3;
-  size_t lookup_space_cost = 3 + 2 * case_count;
-  size_t lookup_time_cost = case_count;
-  if (case_count > 4 &&
+  size_t lookup_space_cost = 3 + 2 * sw.case_count;
+  size_t lookup_time_cost = sw.case_count;
+  if (sw.case_count > 4 &&
       table_space_cost + 3 * table_time_cost <=
           lookup_space_cost + 3 * lookup_time_cost &&
-      min_value > std::numeric_limits<int32_t>::min()) {
+      sw.min_value > std::numeric_limits<int32_t>::min()) {
     InstructionOperand index_operand = g.TempRegister();
-    if (min_value) {
+    if (sw.min_value) {
       // The leal automatically zero extends, so result is a valid 64-bit index.
       Emit(kX64Lea32 | AddressingModeField::encode(kMode_MRI), index_operand,
-           value_operand, g.TempImmediate(-min_value));
+           value_operand, g.TempImmediate(-sw.min_value));
     } else {
       // Zero extend, because we use it as 64-bit index into the jump table.
       Emit(kX64Movl, index_operand, value_operand);
     }
-    size_t input_count = 2 + value_range;
-    auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
-    inputs[0] = index_operand;
-    std::fill(&inputs[1], &inputs[input_count], default_operand);
-    for (size_t index = 0; index < case_count; ++index) {
-      size_t value = case_values[index] - min_value;
-      BasicBlock* branch = case_branches[index];
-      DCHECK_LE(0u, value);
-      DCHECK_LT(value + 2, input_count);
-      inputs[value + 2] = g.Label(branch);
-    }
-    Emit(kArchTableSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
-        ->MarkAsControl();
-    return;
+    // Generate a table lookup.
+    return EmitTableSwitch(sw, index_operand);
   }
 
   // Generate a sequence of conditional jumps.
-  size_t input_count = 2 + case_count * 2;
-  auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
-  inputs[0] = value_operand;
-  inputs[1] = default_operand;
-  for (size_t index = 0; index < case_count; ++index) {
-    int32_t value = case_values[index];
-    BasicBlock* branch = case_branches[index];
-    inputs[index * 2 + 2 + 0] = g.TempImmediate(value);
-    inputs[index * 2 + 2 + 1] = g.Label(branch);
-  }
-  Emit(kArchLookupSwitch, 0, nullptr, input_count, inputs, 0, nullptr)
-      ->MarkAsControl();
+  return EmitLookupSwitch(sw, value_operand);
 }
 
 
@@ -1308,7 +1334,7 @@ void InstructionSelector::VisitWord64Equal(Node* const node) {
     if (CanCover(user, value)) {
       switch (value->opcode()) {
         case IrOpcode::kInt64Sub:
-          return VisitWordCompare(this, value, kX64Cmp, &cont);
+          return VisitWord64Compare(this, value, &cont);
         case IrOpcode::kWord64And:
           return VisitWordCompare(this, value, kX64Test, &cont);
         default:
@@ -1317,7 +1343,7 @@ void InstructionSelector::VisitWord64Equal(Node* const node) {
     }
     return VisitCompareZero(this, value, kX64Cmp, &cont);
   }
-  VisitWordCompare(this, node, kX64Cmp, &cont);
+  VisitWord64Compare(this, node, &cont);
 }
 
 
@@ -1343,19 +1369,19 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
 
 void InstructionSelector::VisitInt64LessThan(Node* node) {
   FlagsContinuation cont(kSignedLessThan, node);
-  VisitWordCompare(this, node, kX64Cmp, &cont);
+  VisitWord64Compare(this, node, &cont);
 }
 
 
 void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
   FlagsContinuation cont(kSignedLessThanOrEqual, node);
-  VisitWordCompare(this, node, kX64Cmp, &cont);
+  VisitWord64Compare(this, node, &cont);
 }
 
 
 void InstructionSelector::VisitUint64LessThan(Node* node) {
   FlagsContinuation cont(kUnsignedLessThan, node);
-  VisitWordCompare(this, node, kX64Cmp, &cont);
+  VisitWord64Compare(this, node, &cont);
 }
 
 
@@ -1377,16 +1403,55 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
+  X64OperandGenerator g(this);
+  Emit(kSSEFloat64ExtractLowWord32, g.DefineAsRegister(node),
+       g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
+  X64OperandGenerator g(this);
+  Emit(kSSEFloat64ExtractHighWord32, g.DefineAsRegister(node),
+       g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
+  X64OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Float64Matcher mleft(left);
+  if (mleft.HasValue() && (bit_cast<uint64_t>(mleft.Value()) >> 32) == 0u) {
+    Emit(kSSEFloat64LoadLowWord32, g.DefineAsRegister(node), g.Use(right));
+    return;
+  }
+  Emit(kSSEFloat64InsertLowWord32, g.DefineSameAsFirst(node),
+       g.UseRegister(left), g.Use(right));
+}
+
+
+void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
+  X64OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Emit(kSSEFloat64InsertHighWord32, g.DefineSameAsFirst(node),
+       g.UseRegister(left), g.Use(right));
+}
+
+
 // static
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
+  MachineOperatorBuilder::Flags flags =
+      MachineOperatorBuilder::kFloat64Max |
+      MachineOperatorBuilder::kFloat64Min |
+      MachineOperatorBuilder::kWord32ShiftIsSafe;
   if (CpuFeatures::IsSupported(SSE4_1)) {
-    return MachineOperatorBuilder::kFloat64Floor |
-           MachineOperatorBuilder::kFloat64Ceil |
-           MachineOperatorBuilder::kFloat64RoundTruncate |
-           MachineOperatorBuilder::kWord32ShiftIsSafe;
+    flags |= MachineOperatorBuilder::kFloat64RoundDown |
+             MachineOperatorBuilder::kFloat64RoundTruncate;
   }
-  return MachineOperatorBuilder::kNoFlags;
+  return flags;
 }
 
 }  // namespace compiler
index 802edf3..1b840a9 100644 (file)
@@ -65,9 +65,10 @@ CallDescriptor* Linkage::GetRuntimeCallDescriptor(
 CallDescriptor* Linkage::GetStubCallDescriptor(
     Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
     int stack_parameter_count, CallDescriptor::Flags flags,
-    Operator::Properties properties) {
+    Operator::Properties properties, MachineType return_type) {
   return LH::GetStubCallDescriptor(isolate, zone, descriptor,
-                                   stack_parameter_count, flags, properties);
+                                   stack_parameter_count, flags, properties,
+                                   return_type);
 }
 
 
index 6537e2c..6bd6764 100644 (file)
@@ -122,8 +122,8 @@ static Maybe<PropertyAttributes> UnscopableLookup(LookupIterator* it) {
   Isolate* isolate = it->isolate();
 
   Maybe<PropertyAttributes> attrs = JSReceiver::GetPropertyAttributes(it);
-  DCHECK(attrs.has_value || isolate->has_pending_exception());
-  if (!attrs.has_value || attrs.value == ABSENT) return attrs;
+  DCHECK(attrs.IsJust() || isolate->has_pending_exception());
+  if (!attrs.IsJust() || attrs.FromJust() == ABSENT) return attrs;
 
   Handle<Symbol> unscopables_symbol = isolate->factory()->unscopables_symbol();
   Handle<Object> receiver = it->GetReceiver();
@@ -131,7 +131,7 @@ static Maybe<PropertyAttributes> UnscopableLookup(LookupIterator* it) {
   MaybeHandle<Object> maybe_unscopables =
       Object::GetProperty(receiver, unscopables_symbol);
   if (!maybe_unscopables.ToHandle(&unscopables)) {
-    return Maybe<PropertyAttributes>();
+    return Nothing<PropertyAttributes>();
   }
   if (!unscopables->IsSpecObject()) return attrs;
   Handle<Object> blacklist;
@@ -139,10 +139,9 @@ static Maybe<PropertyAttributes> UnscopableLookup(LookupIterator* it) {
       Object::GetProperty(unscopables, it->name());
   if (!maybe_blacklist.ToHandle(&blacklist)) {
     DCHECK(isolate->has_pending_exception());
-    return Maybe<PropertyAttributes>();
+    return Nothing<PropertyAttributes>();
   }
-  if (!blacklist->IsUndefined()) return maybe(ABSENT);
-  return attrs;
+  return blacklist->IsUndefined() ? attrs : Just(ABSENT);
 }
 
 static void GetAttributesAndBindingFlags(VariableMode mode,
@@ -173,6 +172,10 @@ static void GetAttributesAndBindingFlags(VariableMode mode,
                            ? IMMUTABLE_CHECK_INITIALIZED_HARMONY
                            : IMMUTABLE_IS_INITIALIZED_HARMONY;
       break;
+    case IMPORT:
+      // TODO(ES6)
+      UNREACHABLE();
+      break;
     case DYNAMIC:
     case DYNAMIC_GLOBAL:
     case DYNAMIC_LOCAL:
@@ -250,7 +253,7 @@ Handle<Object> Context::Lookup(Handle<String> name,
       // 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.
-      Maybe<PropertyAttributes> maybe;
+      Maybe<PropertyAttributes> maybe = Nothing<PropertyAttributes>();
       if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
           object->IsJSContextExtensionObject()) {
         maybe = JSReceiver::GetOwnPropertyAttributes(object, name);
@@ -261,11 +264,11 @@ Handle<Object> Context::Lookup(Handle<String> name,
         maybe = JSReceiver::GetPropertyAttributes(object, name);
       }
 
-      if (!maybe.has_value) return Handle<Object>();
+      if (!maybe.IsJust()) return Handle<Object>();
       DCHECK(!isolate->has_pending_exception());
-      *attributes = maybe.value;
+      *attributes = maybe.FromJust();
 
-      if (maybe.value != ABSENT) {
+      if (maybe.FromJust() != ABSENT) {
         if (FLAG_trace_contexts) {
           PrintF("=> found property in context object %p\n",
                  reinterpret_cast<void*>(*object));
@@ -276,7 +279,7 @@ Handle<Object> Context::Lookup(Handle<String> name,
 
     // 2. Check the context proper if it has slots.
     if (context->IsFunctionContext() || context->IsBlockContext() ||
-        (FLAG_harmony_scoping && context->IsScriptContext())) {
+        context->IsScriptContext()) {
       // Use serialized scope information of functions and blocks to search
       // for the context index.
       Handle<ScopeInfo> scope_info;
index 3d34e0e..3b4b799 100644 (file)
@@ -125,10 +125,12 @@ enum BindingFlags {
   V(SLOPPY_FUNCTION_WITH_READONLY_PROTOTYPE_MAP_INDEX, Map,                    \
     sloppy_function_with_readonly_prototype_map)                               \
   V(STRICT_FUNCTION_MAP_INDEX, Map, strict_function_map)                       \
+  V(STRONG_FUNCTION_MAP_INDEX, Map, strong_function_map)                       \
   V(SLOPPY_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map,                          \
     sloppy_function_without_prototype_map)                                     \
   V(STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map,                          \
     strict_function_without_prototype_map)                                     \
+  V(STRONG_CONSTRUCTOR_MAP_INDEX, Map, strong_constructor_map)                 \
   V(BOUND_FUNCTION_MAP_INDEX, Map, bound_function_map)                         \
   V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map)                           \
   V(SLOPPY_ARGUMENTS_MAP_INDEX, Map, sloppy_arguments_map)                     \
@@ -153,7 +155,7 @@ enum BindingFlags {
   V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings)    \
   V(ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, Object,                     \
     error_message_for_code_gen_from_strings)                                   \
-  V(IS_PROMISE_INDEX, JSFunction, is_promise)                                  \
+  V(PROMISE_STATUS_INDEX, Symbol, promise_status)                              \
   V(PROMISE_CREATE_INDEX, JSFunction, promise_create)                          \
   V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve)                        \
   V(PROMISE_REJECT_INDEX, JSFunction, promise_reject)                          \
@@ -176,6 +178,7 @@ enum BindingFlags {
     native_object_notifier_perform_change)                                     \
   V(SLOPPY_GENERATOR_FUNCTION_MAP_INDEX, Map, sloppy_generator_function_map)   \
   V(STRICT_GENERATOR_FUNCTION_MAP_INDEX, Map, strict_generator_function_map)   \
+  V(STRONG_GENERATOR_FUNCTION_MAP_INDEX, Map, strong_generator_function_map)   \
   V(GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX, Map, generator_object_prototype_map) \
   V(ITERATOR_RESULT_MAP_INDEX, Map, iterator_result_map)                       \
   V(MAP_ITERATOR_MAP_INDEX, Map, map_iterator_map)                             \
@@ -319,8 +322,10 @@ class Context: public FixedArray {
     SLOPPY_FUNCTION_MAP_INDEX,
     SLOPPY_FUNCTION_WITH_READONLY_PROTOTYPE_MAP_INDEX,
     STRICT_FUNCTION_MAP_INDEX,
+    STRONG_FUNCTION_MAP_INDEX,
     SLOPPY_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
     STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
+    STRONG_CONSTRUCTOR_MAP_INDEX,
     BOUND_FUNCTION_MAP_INDEX,
     INITIAL_OBJECT_PROTOTYPE_INDEX,
     INITIAL_ARRAY_PROTOTYPE_INDEX,
@@ -385,7 +390,7 @@ class Context: public FixedArray {
     ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX,
     RUN_MICROTASKS_INDEX,
     ENQUEUE_MICROTASK_INDEX,
-    IS_PROMISE_INDEX,
+    PROMISE_STATUS_INDEX,
     PROMISE_CREATE_INDEX,
     PROMISE_RESOLVE_INDEX,
     PROMISE_REJECT_INDEX,
@@ -406,6 +411,7 @@ class Context: public FixedArray {
     NATIVE_OBJECT_NOTIFIER_PERFORM_CHANGE,
     SLOPPY_GENERATOR_FUNCTION_MAP_INDEX,
     STRICT_GENERATOR_FUNCTION_MAP_INDEX,
+    STRONG_GENERATOR_FUNCTION_MAP_INDEX,
     GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX,
     ITERATOR_RESULT_MAP_INDEX,
     MAP_ITERATOR_MAP_INDEX,
@@ -570,18 +576,27 @@ class Context: public FixedArray {
 
   static int FunctionMapIndex(LanguageMode language_mode, FunctionKind kind) {
     if (IsGeneratorFunction(kind)) {
-      return is_strict(language_mode) ? STRICT_GENERATOR_FUNCTION_MAP_INDEX
+      return is_strong(language_mode) ? STRONG_GENERATOR_FUNCTION_MAP_INDEX :
+             is_strict(language_mode) ? STRICT_GENERATOR_FUNCTION_MAP_INDEX
                                       : SLOPPY_GENERATOR_FUNCTION_MAP_INDEX;
     }
 
+    if (IsConstructor(kind)) {
+      return is_strong(language_mode) ? STRONG_CONSTRUCTOR_MAP_INDEX :
+             is_strict(language_mode) ? STRICT_FUNCTION_MAP_INDEX
+                                      : SLOPPY_FUNCTION_MAP_INDEX;
+    }
+
     if (IsArrowFunction(kind) || IsConciseMethod(kind) ||
         IsAccessorFunction(kind)) {
-      return is_strict(language_mode)
-                 ? STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX
-                 : SLOPPY_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX;
+      return is_strong(language_mode) ? STRONG_FUNCTION_MAP_INDEX :
+             is_strict(language_mode) ?
+                 STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX :
+                 SLOPPY_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX;
     }
 
-    return is_strict(language_mode) ? STRICT_FUNCTION_MAP_INDEX
+    return is_strong(language_mode) ? STRONG_FUNCTION_MAP_INDEX :
+           is_strict(language_mode) ? STRICT_FUNCTION_MAP_INDEX
                                     : SLOPPY_FUNCTION_MAP_INDEX;
   }
 
index 663f4e8..82a521b 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/v8.h"
 
 #include "src/assert-scope.h"
+#include "src/char-predicates-inl.h"
 #include "src/conversions-inl.h"
 #include "src/conversions.h"
 #include "src/dtoa.h"
@@ -502,4 +503,54 @@ double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
 }
 
 
+bool IsNonArrayIndexInteger(String* string) {
+  const int kBufferSize = 64;
+  const int kUint32MaxChars = 11;
+  uint16_t buffer[kBufferSize];
+  int offset = 0;
+  const int length = string->length();
+  if (length == 0) return false;
+  // First iteration, check for minus, 0 followed by anything else, etc.
+  int to = std::min(offset + kUint32MaxChars, length);
+  {
+    String::WriteToFlat(string, buffer, offset, to);
+    bool negative = false;
+    if (buffer[offset] == '-') {
+      negative = true;
+      ++offset;
+      if (offset == to) return false;  // Just '-' is bad.
+    }
+    if (buffer[offset] == '0') {
+      return to == 2 && negative;  // Match just '-0'.
+    }
+    // Process positive integers.
+    if (!negative) {
+      uint64_t acc = 0;
+      for (; offset < to; ++offset) {
+        uint64_t digit = buffer[offset] - '0';
+        if (digit > 9) return false;
+        acc = 10 * acc + digit;
+      }
+      // String is consumed.  Evaluate what we have.
+      if (offset == length) {
+        return acc >
+               static_cast<uint64_t>(std::numeric_limits<uint32_t>::max());
+      }
+    }
+  }
+  // Consume rest of string.  If we get here, we're way out of uint32_t bounds
+  // or negative.
+  int i = offset;
+  while (true) {
+    for (; offset < to; ++offset, ++i) {
+      if (!IsDecimalDigit(buffer[i])) return false;
+    }
+    if (offset == length) break;
+    // Read next chunk.
+    to = std::min(offset + kBufferSize, length);
+    String::WriteToFlat(string, buffer, offset, to);
+    i = 0;
+  }
+  return true;
+}
 } }  // namespace v8::internal
index 5afd4e1..1609395 100644 (file)
@@ -236,6 +236,8 @@ inline size_t NumberToSize(Isolate* isolate,
   return result;
 }
 
+
+bool IsNonArrayIndexInteger(String* string);
 } }  // namespace v8::internal
 
 #endif  // V8_CONVERSIONS_H_
index 539b182..af8e8b4 100644 (file)
@@ -396,44 +396,29 @@ class AggregatedHistogramTimerScope {
   AHT(compile_lazy, V8.CompileLazyMicroSeconds)
 
 
-#define HISTOGRAM_PERCENTAGE_LIST(HP)                                 \
-  /* Heap fragmentation. */                                           \
-  HP(external_fragmentation_total,                                    \
-     V8.MemoryExternalFragmentationTotal)                             \
-  HP(external_fragmentation_old_pointer_space,                        \
-     V8.MemoryExternalFragmentationOldPointerSpace)                   \
-  HP(external_fragmentation_old_data_space,                           \
-     V8.MemoryExternalFragmentationOldDataSpace)                      \
-  HP(external_fragmentation_code_space,                               \
-     V8.MemoryExternalFragmentationCodeSpace)                         \
-  HP(external_fragmentation_map_space,                                \
-     V8.MemoryExternalFragmentationMapSpace)                          \
-  HP(external_fragmentation_cell_space,                               \
-     V8.MemoryExternalFragmentationCellSpace)                         \
-  HP(external_fragmentation_property_cell_space,                      \
-     V8.MemoryExternalFragmentationPropertyCellSpace)                 \
-  HP(external_fragmentation_lo_space,                                 \
-     V8.MemoryExternalFragmentationLoSpace)                           \
-  /* Percentages of heap committed to each space. */                  \
-  HP(heap_fraction_new_space,                                         \
-     V8.MemoryHeapFractionNewSpace)                                   \
-  HP(heap_fraction_old_pointer_space,                                 \
-     V8.MemoryHeapFractionOldPointerSpace)                            \
-  HP(heap_fraction_old_data_space,                                    \
-     V8.MemoryHeapFractionOldDataSpace)                               \
-  HP(heap_fraction_code_space,                                        \
-     V8.MemoryHeapFractionCodeSpace)                                  \
-  HP(heap_fraction_map_space,                                         \
-     V8.MemoryHeapFractionMapSpace)                                   \
-  HP(heap_fraction_cell_space,                                        \
-     V8.MemoryHeapFractionCellSpace)                                  \
-  HP(heap_fraction_property_cell_space,                               \
-     V8.MemoryHeapFractionPropertyCellSpace)                          \
-  HP(heap_fraction_lo_space,                                          \
-     V8.MemoryHeapFractionLoSpace)                                    \
-  /* Percentage of crankshafted codegen. */                           \
-  HP(codegen_fraction_crankshaft,                                     \
-     V8.CodegenFractionCrankshaft)                                    \
+#define HISTOGRAM_PERCENTAGE_LIST(HP)                                          \
+  /* Heap fragmentation. */                                                    \
+  HP(external_fragmentation_total, V8.MemoryExternalFragmentationTotal)        \
+  HP(external_fragmentation_old_pointer_space,                                 \
+     V8.MemoryExternalFragmentationOldPointerSpace)                            \
+  HP(external_fragmentation_old_data_space,                                    \
+     V8.MemoryExternalFragmentationOldDataSpace)                               \
+  HP(external_fragmentation_code_space,                                        \
+     V8.MemoryExternalFragmentationCodeSpace)                                  \
+  HP(external_fragmentation_map_space, V8.MemoryExternalFragmentationMapSpace) \
+  HP(external_fragmentation_cell_space,                                        \
+     V8.MemoryExternalFragmentationCellSpace)                                  \
+  HP(external_fragmentation_lo_space, V8.MemoryExternalFragmentationLoSpace)   \
+  /* Percentages of heap committed to each space. */                           \
+  HP(heap_fraction_new_space, V8.MemoryHeapFractionNewSpace)                   \
+  HP(heap_fraction_old_pointer_space, V8.MemoryHeapFractionOldPointerSpace)    \
+  HP(heap_fraction_old_data_space, V8.MemoryHeapFractionOldDataSpace)          \
+  HP(heap_fraction_code_space, V8.MemoryHeapFractionCodeSpace)                 \
+  HP(heap_fraction_map_space, V8.MemoryHeapFractionMapSpace)                   \
+  HP(heap_fraction_cell_space, V8.MemoryHeapFractionCellSpace)                 \
+  HP(heap_fraction_lo_space, V8.MemoryHeapFractionLoSpace)                     \
+  /* Percentage of crankshafted codegen. */                                    \
+  HP(codegen_fraction_crankshaft, V8.CodegenFractionCrankshaft)
 
 
 #define HISTOGRAM_MEMORY_LIST(HM)                                     \
@@ -443,8 +428,6 @@ class AggregatedHistogramTimerScope {
      V8.MemoryHeapSampleMapSpaceCommitted)                            \
   HM(heap_sample_cell_space_committed,                                \
      V8.MemoryHeapSampleCellSpaceCommitted)                           \
-  HM(heap_sample_property_cell_space_committed,                       \
-     V8.MemoryHeapSamplePropertyCellSpaceCommitted)                   \
   HM(heap_sample_code_space_committed,                                \
      V8.MemoryHeapSampleCodeSpaceCommitted)                           \
   HM(heap_sample_maximum_committed,                                   \
@@ -587,6 +570,7 @@ class AggregatedHistogramTimerScope {
   SC(math_asin, V8.MathAsin)                                                   \
   SC(math_atan, V8.MathAtan)                                                   \
   SC(math_atan2, V8.MathAtan2)                                                 \
+  SC(math_clz32, V8.MathClz32)                                                 \
   SC(math_exp, V8.MathExp)                                                     \
   SC(math_floor, V8.MathFloor)                                                 \
   SC(math_log, V8.MathLog)                                                     \
@@ -623,11 +607,6 @@ class AggregatedHistogramTimerScope {
   SC(cell_space_bytes_available, V8.MemoryCellSpaceBytesAvailable)             \
   SC(cell_space_bytes_committed, V8.MemoryCellSpaceBytesCommitted)             \
   SC(cell_space_bytes_used, V8.MemoryCellSpaceBytesUsed)                       \
-  SC(property_cell_space_bytes_available,                                      \
-     V8.MemoryPropertyCellSpaceBytesAvailable)                                 \
-  SC(property_cell_space_bytes_committed,                                      \
-     V8.MemoryPropertyCellSpaceBytesCommitted)                                 \
-  SC(property_cell_space_bytes_used, V8.MemoryPropertyCellSpaceBytesUsed)      \
   SC(lo_space_bytes_available, V8.MemoryLoSpaceBytesAvailable)                 \
   SC(lo_space_bytes_committed, V8.MemoryLoSpaceBytesCommitted)                 \
   SC(lo_space_bytes_used, V8.MemoryLoSpaceBytesUsed)
index 0320ed5..075f285 100644 (file)
@@ -17,9 +17,6 @@ namespace internal {
 
 void CodeCreateEventRecord::UpdateCodeMap(CodeMap* code_map) {
   code_map->AddCode(start, entry, size);
-  if (shared != NULL) {
-    entry->set_shared_id(code_map->GetSharedId(shared));
-  }
 }
 
 
@@ -38,12 +35,7 @@ void CodeDisableOptEventRecord::UpdateCodeMap(CodeMap* code_map) {
 
 void CodeDeoptEventRecord::UpdateCodeMap(CodeMap* code_map) {
   CodeEntry* entry = code_map->FindEntry(start);
-  if (entry != NULL) entry->set_deopt_info(deopt_reason, raw_position);
-}
-
-
-void SharedFunctionInfoMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
-  code_map->MoveCode(from, to);
+  if (entry != NULL) entry->set_deopt_info(deopt_reason, position, pc_offset);
 }
 
 
index c276bb6..03d7052 100644 (file)
@@ -201,7 +201,6 @@ void CpuProfiler::CallbackEvent(Name* name, Address entry_point) {
       Logger::CALLBACK_TAG,
       profiles_->GetName(name));
   rec->size = 1;
-  rec->shared = NULL;
   processor_->Enqueue(evt_rec);
 }
 
@@ -218,7 +217,6 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
       CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
       CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
   rec->size = code->ExecutableSize();
-  rec->shared = NULL;
   processor_->Enqueue(evt_rec);
 }
 
@@ -235,7 +233,6 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
       CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
       CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
   rec->size = code->ExecutableSize();
-  rec->shared = NULL;
   processor_->Enqueue(evt_rec);
 }
 
@@ -254,16 +251,10 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, Code* code,
       NULL, code->instruction_start());
   if (info) {
     rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
+    rec->entry->set_inlined_function_infos(info->inlined_function_infos());
   }
-  if (shared->script()->IsScript()) {
-    DCHECK(Script::cast(shared->script()));
-    Script* script = Script::cast(shared->script());
-    rec->entry->set_script_id(script->id()->value());
-    rec->entry->set_bailout_reason(
-        GetBailoutReason(shared->disable_optimization_reason()));
-  }
+  rec->entry->FillFunctionInfo(shared);
   rec->size = code->ExecutableSize();
-  rec->shared = shared->address();
   processor_->Enqueue(evt_rec);
 }
 
@@ -298,12 +289,10 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, Code* code,
       column, line_table, code->instruction_start());
   if (info) {
     rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
+    rec->entry->set_inlined_function_infos(info->inlined_function_infos());
   }
-  rec->entry->set_script_id(script->id()->value());
+  rec->entry->FillFunctionInfo(shared);
   rec->size = code->ExecutableSize();
-  rec->shared = shared->address();
-  rec->entry->set_bailout_reason(
-      GetBailoutReason(shared->disable_optimization_reason()));
   processor_->Enqueue(evt_rec);
 }
 
@@ -320,7 +309,6 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
       CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
       CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
   rec->size = code->ExecutableSize();
-  rec->shared = NULL;
   processor_->Enqueue(evt_rec);
 }
 
@@ -343,14 +331,14 @@ void CpuProfiler::CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) {
 }
 
 
-void CpuProfiler::CodeDeoptEvent(Code* code, int bailout_id, Address pc,
-                                 int fp_to_sp_delta) {
+void CpuProfiler::CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) {
   CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT);
   CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
-  Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, bailout_id);
+  Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc);
   rec->start = code->address();
   rec->deopt_reason = Deoptimizer::GetDeoptReason(info.deopt_reason);
-  rec->raw_position = info.raw_position;
+  rec->position = info.position;
+  rec->pc_offset = pc - code->instruction_start();
   processor_->Enqueue(evt_rec);
   processor_->AddDeoptStack(isolate_, pc, fp_to_sp_delta);
 }
@@ -360,16 +348,6 @@ void CpuProfiler::CodeDeleteEvent(Address from) {
 }
 
 
-void CpuProfiler::SharedFunctionInfoMoveEvent(Address from, Address to) {
-  CodeEventsContainer evt_rec(CodeEventRecord::SHARED_FUNC_MOVE);
-  SharedFunctionInfoMoveEventRecord* rec =
-      &evt_rec.SharedFunctionInfoMoveEventRecord_;
-  rec->from = from;
-  rec->to = to;
-  processor_->Enqueue(evt_rec);
-}
-
-
 void CpuProfiler::GetterCallbackEvent(Name* name, Address entry_point) {
   if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return;
   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
@@ -380,7 +358,6 @@ void CpuProfiler::GetterCallbackEvent(Name* name, Address entry_point) {
       profiles_->GetName(name),
       "get ");
   rec->size = 1;
-  rec->shared = NULL;
   processor_->Enqueue(evt_rec);
 }
 
@@ -409,7 +386,6 @@ void CpuProfiler::SetterCallbackEvent(Name* name, Address entry_point) {
       profiles_->GetName(name),
       "set ");
   rec->size = 1;
-  rec->shared = NULL;
   processor_->Enqueue(evt_rec);
 }
 
index 140de3b..26ec7f9 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/base/atomicops.h"
 #include "src/base/platform/time.h"
 #include "src/circular-queue.h"
+#include "src/compiler.h"
 #include "src/sampler.h"
 #include "src/unbound-queue.h"
 
@@ -28,7 +29,6 @@ class ProfileGenerator;
   V(CODE_MOVE, CodeMoveEventRecord)                      \
   V(CODE_DISABLE_OPT, CodeDisableOptEventRecord)         \
   V(CODE_DEOPT, CodeDeoptEventRecord)                    \
-  V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord) \
   V(REPORT_BUILTIN, ReportBuiltinEventRecord)
 
 
@@ -52,7 +52,6 @@ class CodeCreateEventRecord : public CodeEventRecord {
   Address start;
   CodeEntry* entry;
   unsigned size;
-  Address shared;
 
   INLINE(void UpdateCodeMap(CodeMap* code_map));
 };
@@ -80,16 +79,8 @@ class CodeDeoptEventRecord : public CodeEventRecord {
  public:
   Address start;
   const char* deopt_reason;
-  int raw_position;
-
-  INLINE(void UpdateCodeMap(CodeMap* code_map));
-};
-
-
-class SharedFunctionInfoMoveEventRecord : public CodeEventRecord {
- public:
-  Address from;
-  Address to;
+  SourcePosition position;
+  size_t pc_offset;
 
   INLINE(void UpdateCodeMap(CodeMap* code_map));
 };
@@ -245,13 +236,12 @@ class CpuProfiler : public CodeEventListener {
   virtual void CodeMovingGCEvent() {}
   virtual void CodeMoveEvent(Address from, Address to);
   virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared);
-  virtual void CodeDeoptEvent(Code* code, int bailout_id, Address pc,
-                              int fp_to_sp_delta);
+  virtual void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta);
   virtual void CodeDeleteEvent(Address from);
   virtual void GetterCallbackEvent(Name* name, Address entry_point);
   virtual void RegExpCodeCreateEvent(Code* code, String* source);
   virtual void SetterCallbackEvent(Name* name, Address entry_point);
-  virtual void SharedFunctionInfoMoveEvent(Address from, Address to);
+  virtual void SharedFunctionInfoMoveEvent(Address from, Address to) {}
 
   INLINE(bool is_profiling() const) { return is_profiling_; }
   bool* is_profiling_address() {
index 7fa6f8c..38a4b8e 100644 (file)
@@ -45,7 +45,7 @@
 #include "src/basic-block-profiler.h"
 #include "src/d8-debug.h"
 #include "src/debug.h"
-#include "src/natives.h"
+#include "src/snapshot/natives.h"
 #include "src/v8.h"
 #endif  // !V8_SHARED
 
 
 namespace v8 {
 
+namespace {
+v8::Platform* g_platform = NULL;
+}  // namespace
+
 
 static Handle<Value> Throw(Isolate* isolate, const char* message) {
   return isolate->ThrowException(String::NewFromUtf8(isolate, message));
@@ -963,15 +967,9 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
 
 void Shell::Initialize(Isolate* isolate) {
 #ifndef V8_SHARED
-  Shell::counter_map_ = new CounterMap();
   // Set up counters
   if (i::StrLength(i::FLAG_map_counters) != 0)
     MapCounters(isolate, i::FLAG_map_counters);
-  if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) {
-    isolate->SetCounterFunction(LookupCounter);
-    isolate->SetCreateHistogramFunction(CreateHistogram);
-    isolate->SetAddHistogramSampleFunction(AddHistogramSample);
-  }
 #endif  // !V8_SHARED
 }
 
@@ -1295,9 +1293,11 @@ void SourceGroup::ExecuteInThread() {
         }
       }
       if (Shell::options.send_idle_notification) {
-        const int kLongIdlePauseInMs = 1000;
+        const double kLongIdlePauseInSeconds = 1.0;
         isolate->ContextDisposedNotification();
-        isolate->IdleNotification(kLongIdlePauseInMs);
+        isolate->IdleNotificationDeadline(
+            g_platform->MonotonicallyIncreasingTime() +
+            kLongIdlePauseInSeconds);
       }
       if (Shell::options.invoke_weak_callbacks) {
         // By sending a low memory notifications, we will try hard to collect
@@ -1493,9 +1493,10 @@ int Shell::RunMain(Isolate* isolate, int argc, char* argv[]) {
     }
   }
   if (options.send_idle_notification) {
-    const int kLongIdlePauseInMs = 1000;
+    const double kLongIdlePauseInSeconds = 1.0;
     isolate->ContextDisposedNotification();
-    isolate->IdleNotification(kLongIdlePauseInMs);
+    isolate->IdleNotificationDeadline(
+        g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds);
   }
   if (options.invoke_weak_callbacks) {
     // By sending a low memory notifications, we will try hard to collect all
@@ -1607,8 +1608,8 @@ int Shell::Main(int argc, char* argv[]) {
 #endif  // defined(_WIN32) || defined(_WIN64)
   if (!SetOptions(argc, argv)) return 1;
   v8::V8::InitializeICU(options.icu_data_file);
-  v8::Platform* platform = v8::platform::CreateDefaultPlatform();
-  v8::V8::InitializePlatform(platform);
+  g_platform = v8::platform::CreateDefaultPlatform();
+  v8::V8::InitializePlatform(g_platform);
   v8::V8::Initialize();
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
   v8::StartupDataHandler startup_data(argv[0], options.natives_blob,
@@ -1639,6 +1640,13 @@ int Shell::Main(int argc, char* argv[]) {
       base::SysInfo::AmountOfPhysicalMemory(),
       base::SysInfo::AmountOfVirtualMemory(),
       base::SysInfo::NumberOfProcessors());
+
+  Shell::counter_map_ = new CounterMap();
+  if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) {
+    create_params.counter_lookup_callback = LookupCounter;
+    create_params.create_histogram_callback = CreateHistogram;
+    create_params.add_histogram_sample_callback = AddHistogramSample;
+  }
 #endif
   Isolate* isolate = Isolate::New(create_params);
   DumbLineEditor dumb_line_editor(isolate);
@@ -1704,7 +1712,7 @@ int Shell::Main(int argc, char* argv[]) {
   isolate->Dispose();
   V8::Dispose();
   V8::ShutdownPlatform();
-  delete platform;
+  delete g_platform;
 
   return result;
 }
index 40ab1d2..eafe798 100644 (file)
@@ -2,16 +2,22 @@
 // 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 declarations have been made
 // in v8natives.js:
 // var $isFinite = GlobalIsFinite;
 
-var $Date = global.Date;
+var $createDate;
 
 // -------------------------------------------------------------------
 
+(function() {
+
+"use strict";
+
+%CheckIsBootstrapping();
+
+var GlobalDate = global.Date;
+
 // This file contains date support implemented in JavaScript.
 
 // Helper function to throw error.
@@ -19,7 +25,6 @@ function ThrowDateTypeError() {
   throw new $TypeError('this is not a Date object.');
 }
 
-
 var timezone_cache_time = NAN;
 var timezone_cache_timezone;
 
@@ -121,7 +126,7 @@ var Date_cache = {
 function DateConstructor(year, month, date, hours, minutes, seconds, ms) {
   if (!%_IsConstructCall()) {
     // ECMA 262 - 15.9.2
-    return (new $Date()).toString();
+    return (new GlobalDate()).toString();
   }
 
   // ECMA 262 - 15.9.3
@@ -230,8 +235,8 @@ function LocalTimezoneString(date) {
 
   var timezoneOffset = -TIMEZONE_OFFSET(date);
   var sign = (timezoneOffset >= 0) ? 1 : -1;
-  var hours = FLOOR((sign * timezoneOffset)/60);
-  var min   = FLOOR((sign * timezoneOffset)%60);
+  var hours = $floor((sign * timezoneOffset)/60);
+  var min   = $floor((sign * timezoneOffset)%60);
   var gmt = ' GMT' + ((sign == 1) ? '+' : '-') +
       TwoDigitString(hours) + TwoDigitString(min);
   return gmt + ' (' +  timezone + ')';
@@ -684,7 +689,7 @@ function DateToGMTString() {
 
 function PadInt(n, digits) {
   if (digits == 1) return n;
-  return n < MathPow(10, digits - 1) ? '0' + PadInt(n, digits - 1) : n;
+  return n < %_MathPow(10, digits - 1) ? '0' + PadInt(n, digits - 1) : n;
 }
 
 
@@ -731,6 +736,7 @@ var date_cache_version = NAN;
 function CheckDateCacheCurrent() {
   if (!date_cache_version_holder) {
     date_cache_version_holder = %DateCacheVersion();
+    if (!date_cache_version_holder) return;
   }
   if (date_cache_version_holder[0] == date_cache_version) {
     return;
@@ -748,79 +754,78 @@ function CheckDateCacheCurrent() {
 
 
 function CreateDate(time) {
-  var date = new $Date();
+  var date = new GlobalDate();
   date.setTime(time);
   return date;
 }
 
 // -------------------------------------------------------------------
 
-function SetUpDate() {
-  %CheckIsBootstrapping();
-
-  %SetCode($Date, DateConstructor);
-  %FunctionSetPrototype($Date, new $Date(NAN));
-
-  // Set up non-enumerable properties of the Date object itself.
-  InstallFunctions($Date, DONT_ENUM, $Array(
-    "UTC", DateUTC,
-    "parse", DateParse,
-    "now", DateNow
-  ));
-
-  // Set up non-enumerable constructor property of the Date prototype object.
-  %AddNamedProperty($Date.prototype, "constructor", $Date, DONT_ENUM);
-
-  // Set up non-enumerable functions of the Date prototype object and
-  // set their names.
-  InstallFunctions($Date.prototype, DONT_ENUM, $Array(
-    "toString", DateToString,
-    "toDateString", DateToDateString,
-    "toTimeString", DateToTimeString,
-    "toLocaleString", DateToLocaleString,
-    "toLocaleDateString", DateToLocaleDateString,
-    "toLocaleTimeString", DateToLocaleTimeString,
-    "valueOf", DateValueOf,
-    "getTime", DateGetTime,
-    "getFullYear", DateGetFullYear,
-    "getUTCFullYear", DateGetUTCFullYear,
-    "getMonth", DateGetMonth,
-    "getUTCMonth", DateGetUTCMonth,
-    "getDate", DateGetDate,
-    "getUTCDate", DateGetUTCDate,
-    "getDay", DateGetDay,
-    "getUTCDay", DateGetUTCDay,
-    "getHours", DateGetHours,
-    "getUTCHours", DateGetUTCHours,
-    "getMinutes", DateGetMinutes,
-    "getUTCMinutes", DateGetUTCMinutes,
-    "getSeconds", DateGetSeconds,
-    "getUTCSeconds", DateGetUTCSeconds,
-    "getMilliseconds", DateGetMilliseconds,
-    "getUTCMilliseconds", DateGetUTCMilliseconds,
-    "getTimezoneOffset", DateGetTimezoneOffset,
-    "setTime", DateSetTime,
-    "setMilliseconds", DateSetMilliseconds,
-    "setUTCMilliseconds", DateSetUTCMilliseconds,
-    "setSeconds", DateSetSeconds,
-    "setUTCSeconds", DateSetUTCSeconds,
-    "setMinutes", DateSetMinutes,
-    "setUTCMinutes", DateSetUTCMinutes,
-    "setHours", DateSetHours,
-    "setUTCHours", DateSetUTCHours,
-    "setDate", DateSetDate,
-    "setUTCDate", DateSetUTCDate,
-    "setMonth", DateSetMonth,
-    "setUTCMonth", DateSetUTCMonth,
-    "setFullYear", DateSetFullYear,
-    "setUTCFullYear", DateSetUTCFullYear,
-    "toGMTString", DateToGMTString,
-    "toUTCString", DateToUTCString,
-    "getYear", DateGetYear,
-    "setYear", DateSetYear,
-    "toISOString", DateToISOString,
-    "toJSON", DateToJSON
-  ));
-}
-
-SetUpDate();
+%SetCode(GlobalDate, DateConstructor);
+%FunctionSetPrototype(GlobalDate, new GlobalDate(NAN));
+
+// Set up non-enumerable properties of the Date object itself.
+InstallFunctions(GlobalDate, DONT_ENUM, $Array(
+  "UTC", DateUTC,
+  "parse", DateParse,
+  "now", DateNow
+));
+
+// Set up non-enumerable constructor property of the Date prototype object.
+%AddNamedProperty(GlobalDate.prototype, "constructor", GlobalDate, DONT_ENUM);
+
+// Set up non-enumerable functions of the Date prototype object and
+// set their names.
+InstallFunctions(GlobalDate.prototype, DONT_ENUM, $Array(
+  "toString", DateToString,
+  "toDateString", DateToDateString,
+  "toTimeString", DateToTimeString,
+  "toLocaleString", DateToLocaleString,
+  "toLocaleDateString", DateToLocaleDateString,
+  "toLocaleTimeString", DateToLocaleTimeString,
+  "valueOf", DateValueOf,
+  "getTime", DateGetTime,
+  "getFullYear", DateGetFullYear,
+  "getUTCFullYear", DateGetUTCFullYear,
+  "getMonth", DateGetMonth,
+  "getUTCMonth", DateGetUTCMonth,
+  "getDate", DateGetDate,
+  "getUTCDate", DateGetUTCDate,
+  "getDay", DateGetDay,
+  "getUTCDay", DateGetUTCDay,
+  "getHours", DateGetHours,
+  "getUTCHours", DateGetUTCHours,
+  "getMinutes", DateGetMinutes,
+  "getUTCMinutes", DateGetUTCMinutes,
+  "getSeconds", DateGetSeconds,
+  "getUTCSeconds", DateGetUTCSeconds,
+  "getMilliseconds", DateGetMilliseconds,
+  "getUTCMilliseconds", DateGetUTCMilliseconds,
+  "getTimezoneOffset", DateGetTimezoneOffset,
+  "setTime", DateSetTime,
+  "setMilliseconds", DateSetMilliseconds,
+  "setUTCMilliseconds", DateSetUTCMilliseconds,
+  "setSeconds", DateSetSeconds,
+  "setUTCSeconds", DateSetUTCSeconds,
+  "setMinutes", DateSetMinutes,
+  "setUTCMinutes", DateSetUTCMinutes,
+  "setHours", DateSetHours,
+  "setUTCHours", DateSetUTCHours,
+  "setDate", DateSetDate,
+  "setUTCDate", DateSetUTCDate,
+  "setMonth", DateSetMonth,
+  "setUTCMonth", DateSetUTCMonth,
+  "setFullYear", DateSetFullYear,
+  "setUTCFullYear", DateSetUTCFullYear,
+  "toGMTString", DateToGMTString,
+  "toUTCString", DateToUTCString,
+  "getYear", DateGetYear,
+  "setYear", DateSetYear,
+  "toISOString", DateToISOString,
+  "toJSON", DateToJSON
+));
+
+// Expose to the global scope.
+$createDate = CreateDate;
+
+})();
index c24b478..76b5fe1 100644 (file)
@@ -264,7 +264,7 @@ function ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
 }
 
 
-//Creates a clone of script breakpoint that is linked to another script.
+// Creates a clone of script breakpoint that is linked to another script.
 ScriptBreakPoint.prototype.cloneForOtherScript = function (other_script) {
   var copy = new ScriptBreakPoint(Debug.ScriptBreakPointType.ScriptId,
       other_script.id, this.line_, this.column_, this.groupId_,
@@ -499,10 +499,6 @@ Debug.setListener = function(listener, opt_data) {
 };
 
 
-Debug.breakExecution = function(f) {
-  %Break();
-};
-
 Debug.breakLocations = function(f, opt_position_aligment) {
   if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
   var position_aligment = IS_UNDEFINED(opt_position_aligment)
@@ -552,25 +548,12 @@ Debug.scriptSource = function(func_or_script_name) {
   return this.findScript(func_or_script_name).source;
 };
 
+
 Debug.source = function(f) {
   if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
   return %FunctionGetSourceCode(f);
 };
 
-Debug.disassemble = function(f) {
-  if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
-  return %DebugDisassembleFunction(f);
-};
-
-Debug.disassembleConstructor = function(f) {
-  if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
-  return %DebugDisassembleConstructor(f);
-};
-
-Debug.ExecuteInDebugContext = function(f, without_debugger) {
-  if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
-  return %ExecuteInDebugContext(f, !!without_debugger);
-};
 
 Debug.sourcePosition = function(f) {
   if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
@@ -2584,7 +2567,3 @@ function ValueToProtocolValue_(value, mirror_serializer) {
   }
   return json;
 }
-
-Debug.TestApi = {
-  CommandProcessorResolveValue: DebugCommandProcessor.resolveValue_
-};
index a7bf765..2796d2d 100644 (file)
@@ -20,7 +20,7 @@
 #include "src/list.h"
 #include "src/log.h"
 #include "src/messages.h"
-#include "src/natives.h"
+#include "src/snapshot/natives.h"
 
 #include "include/v8-debug.h"
 
@@ -60,47 +60,29 @@ static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) {
 }
 
 
-BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
-                                             BreakLocatorType type) {
-  debug_info_ = debug_info;
-  type_ = type;
-  reloc_iterator_ = NULL;
-  reloc_iterator_original_ = NULL;
-  Reset();  // Initialize the rest of the member variables.
-}
-
-
-BreakLocationIterator::~BreakLocationIterator() {
-  DCHECK(reloc_iterator_ != NULL);
-  DCHECK(reloc_iterator_original_ != NULL);
-  delete reloc_iterator_;
-  delete reloc_iterator_original_;
-}
-
-
-// Check whether a code stub with the specified major key is a possible break
-// point location when looking for source break locations.
-static bool IsSourceBreakStub(Code* code) {
-  CodeStub::Major major_key = CodeStub::GetMajorKey(code);
-  return major_key == CodeStub::CallFunction;
-}
-
-
-// Check whether a code stub with the specified major key is a possible break
-// location.
-static bool IsBreakStub(Code* code) {
-  CodeStub::Major major_key = CodeStub::GetMajorKey(code);
-  return major_key == CodeStub::CallFunction;
+BreakLocation::Iterator::Iterator(Handle<DebugInfo> debug_info,
+                                  BreakLocatorType type)
+    : debug_info_(debug_info),
+      type_(type),
+      reloc_iterator_(debug_info->code(),
+                      ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)),
+      reloc_iterator_original_(
+          debug_info->original_code(),
+          ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)),
+      break_index_(-1),
+      position_(1),
+      statement_position_(1) {
+  Next();
 }
 
 
-void BreakLocationIterator::Next() {
+void BreakLocation::Iterator::Next() {
   DisallowHeapAllocation no_gc;
   DCHECK(!RinfoDone());
 
   // Iterate through reloc info for code and original code stopping at each
   // breakable code target.
-  bool first = break_point_ == -1;
+  bool first = break_index_ == -1;
   while (!RinfoDone()) {
     if (!first) RinfoNext();
     first = false;
@@ -115,8 +97,8 @@ void BreakLocationIterator::Next() {
       }
       // Always update the position as we don't want that to be before the
       // statement position.
-      position_ = static_cast<int>(
-          rinfo()->data() - debug_info_->shared()->start_position());
+      position_ = static_cast<int>(rinfo()->data() -
+                                   debug_info_->shared()->start_position());
       DCHECK(position_ >= 0);
       DCHECK(statement_position_ >= 0);
     }
@@ -131,7 +113,7 @@ void BreakLocationIterator::Next() {
         position_ = 0;
       }
       statement_position_ = position_;
-      break_point_++;
+      break_index_++;
       return;
     }
 
@@ -143,7 +125,7 @@ void BreakLocationIterator::Next() {
       Code* code = Code::GetCodeFromTargetAddress(target);
 
       if (RelocInfo::IsConstructCall(rmode()) || code->is_call_stub()) {
-        break_point_++;
+        break_index_++;
         return;
       }
 
@@ -152,144 +134,117 @@ void BreakLocationIterator::Next() {
 
       if ((code->is_inline_cache_stub() && !code->is_binary_op_stub() &&
            !code->is_compare_ic_stub() && !code->is_to_boolean_ic_stub())) {
-        break_point_++;
+        break_index_++;
         return;
       }
       if (code->kind() == Code::STUB) {
-        if (IsDebuggerStatement()) {
-          break_point_++;
+        if (RelocInfo::IsDebuggerStatement(rmode())) {
+          break_index_++;
+          return;
+        } else if (CodeStub::GetMajorKey(code) == CodeStub::CallFunction) {
+          break_index_++;
           return;
-        } else if (type_ == ALL_BREAK_LOCATIONS) {
-          if (IsBreakStub(code)) {
-            break_point_++;
-            return;
-          }
-        } else {
-          DCHECK(type_ == SOURCE_BREAK_LOCATIONS);
-          if (IsSourceBreakStub(code)) {
-            break_point_++;
-            return;
-          }
         }
       }
     }
 
-    if (IsDebugBreakSlot() && type_ != CALLS_AND_RETURNS) {
+    if (RelocInfo::IsDebugBreakSlot(rmode()) && type_ != CALLS_AND_RETURNS) {
       // There is always a possible break point at a debug break slot.
-      break_point_++;
+      break_index_++;
       return;
     }
   }
 }
 
 
-void BreakLocationIterator::Next(int count) {
-  while (count > 0) {
-    Next();
-    count--;
-  }
+// Find the break point at the supplied address, or the closest one before
+// the address.
+BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info,
+                                         BreakLocatorType type, Address pc) {
+  Iterator it(debug_info, type);
+  it.SkipTo(BreakIndexFromAddress(debug_info, type, pc));
+  return it.GetBreakLocation();
 }
 
 
 // Find the break point at the supplied address, or the closest one before
 // the address.
-void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
+void BreakLocation::FromAddressSameStatement(Handle<DebugInfo> debug_info,
+                                             BreakLocatorType type, Address pc,
+                                             List<BreakLocation>* result_out) {
+  int break_index = BreakIndexFromAddress(debug_info, type, pc);
+  Iterator it(debug_info, type);
+  it.SkipTo(break_index);
+  int statement_position = it.statement_position();
+  while (!it.Done() && it.statement_position() == statement_position) {
+    result_out->Add(it.GetBreakLocation());
+    it.Next();
+  }
+}
+
+
+int BreakLocation::BreakIndexFromAddress(Handle<DebugInfo> debug_info,
+                                         BreakLocatorType type, Address pc) {
   // Run through all break points to locate the one closest to the address.
-  int closest_break_point = 0;
+  int closest_break = 0;
   int distance = kMaxInt;
-  while (!Done()) {
+  for (Iterator it(debug_info, type); !it.Done(); it.Next()) {
     // Check if this break point is closer that what was previously found.
-    if (this->pc() <= pc && pc - this->pc() < distance) {
-      closest_break_point = break_point();
-      distance = static_cast<int>(pc - this->pc());
+    if (it.pc() <= pc && pc - it.pc() < distance) {
+      closest_break = it.break_index();
+      distance = static_cast<int>(pc - it.pc());
       // Check whether we can't get any closer.
       if (distance == 0) break;
     }
-    Next();
   }
-
-  // Move to the break point found.
-  Reset();
-  Next(closest_break_point);
+  return closest_break;
 }
 
 
-// Find the break point closest to the supplied source position.
-void BreakLocationIterator::FindBreakLocationFromPosition(int position,
-    BreakPositionAlignment alignment) {
+BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info,
+                                          BreakLocatorType type, int position,
+                                          BreakPositionAlignment alignment) {
   // Run through all break points to locate the one closest to the source
   // position.
-  int closest_break_point = 0;
+  int closest_break = 0;
   int distance = kMaxInt;
 
-  while (!Done()) {
+  for (Iterator it(debug_info, type); !it.Done(); it.Next()) {
     int next_position;
-    switch (alignment) {
-    case STATEMENT_ALIGNED:
-      next_position = this->statement_position();
-      break;
-    case BREAK_POSITION_ALIGNED:
-      next_position = this->position();
-      break;
-    default:
-      UNREACHABLE();
-      next_position = this->statement_position();
+    if (alignment == STATEMENT_ALIGNED) {
+      next_position = it.statement_position();
+    } else {
+      DCHECK(alignment == BREAK_POSITION_ALIGNED);
+      next_position = it.position();
     }
-    // Check if this break point is closer that what was previously found.
     if (position <= next_position && next_position - position < distance) {
-      closest_break_point = break_point();
+      closest_break = it.break_index();
       distance = next_position - position;
       // Check whether we can't get any closer.
       if (distance == 0) break;
     }
-    Next();
   }
 
-  // Move to the break point found.
-  Reset();
-  Next(closest_break_point);
-}
-
-
-void BreakLocationIterator::Reset() {
-  // Create relocation iterators for the two code objects.
-  if (reloc_iterator_ != NULL) delete reloc_iterator_;
-  if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_;
-  reloc_iterator_ = new RelocIterator(
-      debug_info_->code(),
-      ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE));
-  reloc_iterator_original_ = new RelocIterator(
-      debug_info_->original_code(),
-      ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE));
-
-  // Position at the first break point.
-  break_point_ = -1;
-  position_ = 1;
-  statement_position_ = 1;
-  Next();
-}
-
-
-bool BreakLocationIterator::Done() const {
-  return RinfoDone();
+  Iterator it(debug_info, type);
+  it.SkipTo(closest_break);
+  return it.GetBreakLocation();
 }
 
 
-void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) {
+void BreakLocation::SetBreakPoint(Handle<Object> break_point_object) {
   // If there is not already a real break point here patch code with debug
   // break.
   if (!HasBreakPoint()) SetDebugBreak();
   DCHECK(IsDebugBreak() || IsDebuggerStatement());
   // Set the break point information.
-  DebugInfo::SetBreakPoint(debug_info_, code_position(),
-                           position(), statement_position(),
-                           break_point_object);
+  DebugInfo::SetBreakPoint(debug_info_, pc_offset_, position_,
+                           statement_position_, break_point_object);
 }
 
 
-void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
+void BreakLocation::ClearBreakPoint(Handle<Object> break_point_object) {
   // Clear the break point information.
-  DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object);
+  DebugInfo::ClearBreakPoint(debug_info_, pc_offset_, break_point_object);
   // If there are no more break points here remove the debug break.
   if (!HasBreakPoint()) {
     ClearDebugBreak();
@@ -298,7 +253,7 @@ void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
 }
 
 
-void BreakLocationIterator::SetOneShot() {
+void BreakLocation::SetOneShot() {
   // Debugger statement always calls debugger. No need to modify it.
   if (IsDebuggerStatement()) return;
 
@@ -313,7 +268,7 @@ void BreakLocationIterator::SetOneShot() {
 }
 
 
-void BreakLocationIterator::ClearOneShot() {
+void BreakLocation::ClearOneShot() {
   // Debugger statement always calls debugger. No need to modify it.
   if (IsDebuggerStatement()) return;
 
@@ -329,7 +284,7 @@ void BreakLocationIterator::ClearOneShot() {
 }
 
 
-void BreakLocationIterator::SetDebugBreak() {
+void BreakLocation::SetDebugBreak() {
   // Debugger statement always calls debugger. No need to modify it.
   if (IsDebuggerStatement()) return;
 
@@ -339,7 +294,7 @@ void BreakLocationIterator::SetDebugBreak() {
   // handler as the handler and the function is the same.
   if (IsDebugBreak()) return;
 
-  if (RelocInfo::IsJSReturn(rmode())) {
+  if (IsExit()) {
     // Patch the frame exit code with a break point.
     SetDebugBreakAtReturn();
   } else if (IsDebugBreakSlot()) {
@@ -353,93 +308,52 @@ void BreakLocationIterator::SetDebugBreak() {
 }
 
 
-void BreakLocationIterator::ClearDebugBreak() {
+void BreakLocation::ClearDebugBreak() {
   // Debugger statement always calls debugger. No need to modify it.
   if (IsDebuggerStatement()) return;
 
-  if (RelocInfo::IsJSReturn(rmode())) {
-    // Restore the frame exit code.
-    ClearDebugBreakAtReturn();
+  if (IsExit()) {
+    // Restore the frame exit code with a break point.
+    RestoreFromOriginal(Assembler::kJSReturnSequenceLength);
   } else if (IsDebugBreakSlot()) {
     // Restore the code in the break slot.
-    ClearDebugBreakAtSlot();
+    RestoreFromOriginal(Assembler::kDebugBreakSlotLength);
   } else {
-    // Patch the IC call.
-    ClearDebugBreakAtIC();
+    // Restore the IC call.
+    rinfo().set_target_address(original_rinfo().target_address());
+    // Some ICs store data in the feedback vector. Clear this to ensure we
+    // won't miss future stepping requirements.
+    SharedFunctionInfo* shared = debug_info_->shared();
+    shared->feedback_vector()->ClearICSlots(shared);
   }
   DCHECK(!IsDebugBreak());
 }
 
 
-bool BreakLocationIterator::IsStepInLocation(Isolate* isolate) {
-  if (RelocInfo::IsConstructCall(original_rmode())) {
-    return true;
-  } else if (RelocInfo::IsCodeTarget(rmode())) {
+void BreakLocation::RestoreFromOriginal(int length_in_bytes) {
+  memcpy(pc(), original_pc(), length_in_bytes);
+  CpuFeatures::FlushICache(pc(), length_in_bytes);
+}
+
+
+bool BreakLocation::IsStepInLocation() const {
+  if (IsConstructCall()) return true;
+  if (RelocInfo::IsCodeTarget(rmode())) {
     HandleScope scope(debug_info_->GetIsolate());
-    Address target = original_rinfo()->target_address();
-    Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
-    if (target_code->kind() == Code::STUB) {
-      return CodeStub::GetMajorKey(*target_code) == CodeStub::CallFunction;
-    }
+    Handle<Code> target_code = CodeTarget();
     return target_code->is_call_stub();
   }
   return false;
 }
 
 
-void BreakLocationIterator::PrepareStepIn(Isolate* isolate) {
-#ifdef DEBUG
-  HandleScope scope(isolate);
-  // Step in can only be prepared if currently positioned on an IC call,
-  // construct call or CallFunction stub call.
-  Address target = rinfo()->target_address();
-  Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
-  // All the following stuff is needed only for assertion checks so the code
-  // is wrapped in ifdef.
-  Handle<Code> maybe_call_function_stub = target_code;
-  if (IsDebugBreak()) {
-    Address original_target = original_rinfo()->target_address();
-    maybe_call_function_stub =
-        Handle<Code>(Code::GetCodeFromTargetAddress(original_target));
-  }
-  bool is_call_function_stub =
-      (maybe_call_function_stub->kind() == Code::STUB &&
-       CodeStub::GetMajorKey(*maybe_call_function_stub) ==
-           CodeStub::CallFunction);
-
-  // Step in through construct call requires no changes to the running code.
-  // Step in through getters/setters should already be prepared as well
-  // because caller of this function (Debug::PrepareStep) is expected to
-  // flood the top frame's function with one shot breakpoints.
-  // Step in through CallFunction stub should also be prepared by caller of
-  // this function (Debug::PrepareStep) which should flood target function
-  // with breakpoints.
-  DCHECK(RelocInfo::IsConstructCall(rmode()) ||
-         target_code->is_inline_cache_stub() ||
-         is_call_function_stub);
-#endif
-}
-
-
-// Check whether the break point is at a position which will exit the function.
-bool BreakLocationIterator::IsExit() const {
-  return (RelocInfo::IsJSReturn(rmode()));
-}
-
-
-bool BreakLocationIterator::HasBreakPoint() {
-  return debug_info_->HasBreakPoint(code_position());
-}
-
-
-// Check whether there is a debug break at the current position.
-bool BreakLocationIterator::IsDebugBreak() {
-  if (RelocInfo::IsJSReturn(rmode())) {
-    return IsDebugBreakAtReturn();
+bool BreakLocation::IsDebugBreak() const {
+  if (IsExit()) {
+    return rinfo().IsPatchedReturnSequence();
   } else if (IsDebugBreakSlot()) {
-    return IsDebugBreakAtSlot();
+    return rinfo().IsPatchedDebugBreakSlotSequence();
   } else {
-    return Debug::IsDebugBreak(rinfo()->target_address());
+    return Debug::IsDebugBreak(rinfo().target_address());
   }
 }
 
@@ -491,70 +405,53 @@ static Handle<Code> DebugBreakForIC(Handle<Code> code, RelocInfo::Mode mode) {
 }
 
 
-void BreakLocationIterator::SetDebugBreakAtIC() {
+void BreakLocation::SetDebugBreakAtIC() {
   // Patch the original code with the current address as the current address
   // might have changed by the inline caching since the code was copied.
-  original_rinfo()->set_target_address(rinfo()->target_address());
+  original_rinfo().set_target_address(rinfo().target_address());
 
-  RelocInfo::Mode mode = rmode();
-  if (RelocInfo::IsCodeTarget(mode)) {
-    Address target = rinfo()->target_address();
-    Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
+  if (RelocInfo::IsCodeTarget(rmode_)) {
+    Handle<Code> target_code = CodeTarget();
 
     // Patch the code to invoke the builtin debug break function matching the
     // calling convention used by the call site.
-    Handle<Code> dbgbrk_code = DebugBreakForIC(target_code, mode);
-    rinfo()->set_target_address(dbgbrk_code->entry());
+    Handle<Code> debug_break_code = DebugBreakForIC(target_code, rmode_);
+    rinfo().set_target_address(debug_break_code->entry());
   }
 }
 
 
-void BreakLocationIterator::ClearDebugBreakAtIC() {
-  // Patch the code to the original invoke.
-  rinfo()->set_target_address(original_rinfo()->target_address());
-}
-
-
-bool BreakLocationIterator::IsDebuggerStatement() {
-  return RelocInfo::DEBUG_BREAK == rmode();
-}
-
-
-bool BreakLocationIterator::IsDebugBreakSlot() {
-  return RelocInfo::DEBUG_BREAK_SLOT == rmode();
+Handle<Object> BreakLocation::BreakPointObjects() const {
+  return debug_info_->GetBreakPointObjects(pc_offset_);
 }
 
 
-Object* BreakLocationIterator::BreakPointObjects() {
-  return debug_info_->GetBreakPointObjects(code_position());
+Handle<Code> BreakLocation::CodeTarget() const {
+  DCHECK(IsCodeTarget());
+  Address target = rinfo().target_address();
+  return Handle<Code>(Code::GetCodeFromTargetAddress(target));
 }
 
 
-// Clear out all the debug break code. This is ONLY supposed to be used when
-// shutting down the debugger as it will leave the break point information in
-// DebugInfo even though the code is patched back to the non break point state.
-void BreakLocationIterator::ClearAllDebugBreak() {
-  while (!Done()) {
-    ClearDebugBreak();
-    Next();
-  }
+Handle<Code> BreakLocation::OriginalCodeTarget() const {
+  DCHECK(IsCodeTarget());
+  Address target = original_rinfo().target_address();
+  return Handle<Code>(Code::GetCodeFromTargetAddress(target));
 }
 
 
-bool BreakLocationIterator::RinfoDone() const {
-  DCHECK(reloc_iterator_->done() == reloc_iterator_original_->done());
-  return reloc_iterator_->done();
+bool BreakLocation::Iterator::RinfoDone() const {
+  DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done());
+  return reloc_iterator_.done();
 }
 
 
-void BreakLocationIterator::RinfoNext() {
-  reloc_iterator_->next();
-  reloc_iterator_original_->next();
+void BreakLocation::Iterator::RinfoNext() {
+  reloc_iterator_.next();
+  reloc_iterator_original_.next();
 #ifdef DEBUG
-  DCHECK(reloc_iterator_->done() == reloc_iterator_original_->done());
-  if (!reloc_iterator_->done()) {
-    DCHECK(rmode() == original_rmode());
-  }
+  DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done());
+  DCHECK(reloc_iterator_.done() || rmode() == original_rmode());
 #endif
 }
 
@@ -696,9 +593,10 @@ void ScriptCache::HandleWeakScript(
 
 
 void Debug::HandlePhantomDebugInfo(
-    const v8::PhantomCallbackData<DebugInfoListNode>& data) {
-  Debug* debug = reinterpret_cast<Isolate*>(data.GetIsolate())->debug();
+    const v8::WeakCallbackInfo<DebugInfoListNode>& data) {
   DebugInfoListNode* node = data.GetParameter();
+  node->ClearInfo();
+  Debug* debug = reinterpret_cast<Isolate*>(data.GetIsolate())->debug();
   debug->RemoveDebugInfo(node);
 #ifdef DEBUG
   for (DebugInfoListNode* n = debug->debug_info_list_;
@@ -713,16 +611,20 @@ void Debug::HandlePhantomDebugInfo(
 DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
   // 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));
-  typedef PhantomCallbackData<void>::Callback Callback;
-  GlobalHandles::MakePhantom(
-      reinterpret_cast<Object**>(debug_info_.location()), this, 0,
-      reinterpret_cast<Callback>(Debug::HandlePhantomDebugInfo));
+  debug_info_ =
+      Handle<DebugInfo>::cast(global_handles->Create(debug_info)).location();
+  typedef WeakCallbackInfo<void>::Callback Callback;
+  GlobalHandles::MakeWeak(
+      reinterpret_cast<Object**>(debug_info_), this,
+      reinterpret_cast<Callback>(Debug::HandlePhantomDebugInfo),
+      v8::WeakCallbackType::kParameter);
 }
 
 
-DebugInfoListNode::~DebugInfoListNode() {
-  GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location()));
+void DebugInfoListNode::ClearInfo() {
+  if (debug_info_ == nullptr) return;
+  GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_));
+  debug_info_ = nullptr;
 }
 
 
@@ -744,8 +646,8 @@ bool Debug::CompileDebuggerScript(Isolate* isolate, int index) {
   // Compile the script.
   Handle<SharedFunctionInfo> function_info;
   function_info = Compiler::CompileScript(
-      source_code, script_name, 0, 0, false, false, context, NULL, NULL,
-      ScriptCompiler::kNoCompileOptions, NATIVES_CODE, false);
+      source_code, script_name, 0, 0, false, false, Handle<Object>(), context,
+      NULL, NULL, ScriptCompiler::kNoCompileOptions, NATIVES_CODE, false);
 
   // Silently ignore stack overflows during compilation.
   if (function_info.is_null()) {
@@ -888,14 +790,14 @@ void Debug::Break(Arguments args, JavaScriptFrame* frame) {
   Handle<DebugInfo> debug_info = GetDebugInfo(shared);
 
   // 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
+  // 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);
+  Address call_pc = frame->pc() - 1;
+  BreakLocation break_location =
+      BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc);
 
   // Check whether step next reached a new statement.
-  if (!StepNextContinue(&break_location_iterator, frame)) {
+  if (!StepNextContinue(&break_location, frame)) {
     // Decrease steps left if performing multiple steps.
     if (thread_local_.step_count_ > 0) {
       thread_local_.step_count_--;
@@ -905,9 +807,8 @@ void Debug::Break(Arguments args, JavaScriptFrame* frame) {
   // If there is one or more real break points check whether any of these are
   // triggered.
   Handle<Object> break_points_hit(heap->undefined_value(), isolate_);
-  if (break_location_iterator.HasBreakPoint()) {
-    Handle<Object> break_point_objects =
-        Handle<Object>(break_location_iterator.BreakPointObjects(), isolate_);
+  if (break_location.HasBreakPoint()) {
+    Handle<Object> break_point_objects = break_location.BreakPointObjects();
     break_points_hit = CheckBreakPoints(break_point_objects);
   }
 
@@ -1092,11 +993,10 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function,
   DCHECK(*source_position >= 0);
 
   // Find the break point and change it.
-  BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
-  it.FindBreakLocationFromPosition(*source_position, STATEMENT_ALIGNED);
-  it.SetBreakPoint(break_point_object);
-
-  *source_position = it.statement_position();
+  BreakLocation location = BreakLocation::FromPosition(
+      debug_info, SOURCE_BREAK_LOCATIONS, *source_position, STATEMENT_ALIGNED);
+  *source_position = location.statement_position();
+  location.SetBreakPoint(break_point_object);
 
   // At least one active break point now.
   return debug_info->GetBreakPointCount() > 0;
@@ -1112,11 +1012,12 @@ bool Debug::SetBreakPointForScript(Handle<Script> script,
   PrepareForBreakPoints();
 
   // Obtain shared function info for the function.
-  Object* result = FindSharedFunctionInfoInScript(script, *source_position);
+  Handle<Object> result =
+      FindSharedFunctionInfoInScript(script, *source_position);
   if (result->IsUndefined()) return false;
 
   // Make sure the function has set up the debug info.
-  Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
+  Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result);
   if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) {
     // Return if retrieving debug info failed.
     return false;
@@ -1136,12 +1037,12 @@ bool Debug::SetBreakPointForScript(Handle<Script> script,
   DCHECK(position >= 0);
 
   // Find the break point and change it.
-  BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
-  it.FindBreakLocationFromPosition(position, alignment);
-  it.SetBreakPoint(break_point_object);
+  BreakLocation location = BreakLocation::FromPosition(
+      debug_info, SOURCE_BREAK_LOCATIONS, position, alignment);
+  location.SetBreakPoint(break_point_object);
 
-  position = (alignment == STATEMENT_ALIGNED) ? it.statement_position()
-                                              : it.position();
+  position = (alignment == STATEMENT_ALIGNED) ? location.statement_position()
+                                              : location.position();
 
   *source_position = position + shared->start_position();
 
@@ -1156,18 +1057,21 @@ void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
 
   DebugInfoListNode* node = debug_info_list_;
   while (node != NULL) {
-    Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
-                                                   break_point_object);
+    Handle<Object> result =
+        DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object);
     if (!result->IsUndefined()) {
       // Get information in the break point.
-      BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
+      Handle<BreakPointInfo> break_point_info =
+          Handle<BreakPointInfo>::cast(result);
       Handle<DebugInfo> debug_info = node->debug_info();
 
       // Find the break point and clear it.
-      BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
-      it.FindBreakLocationFromAddress(debug_info->code()->entry() +
-          break_point_info->code_position()->value());
-      it.ClearBreakPoint(break_point_object);
+      Address pc = debug_info->code()->entry() +
+                   break_point_info->code_position()->value();
+
+      BreakLocation location =
+          BreakLocation::FromAddress(debug_info, SOURCE_BREAK_LOCATIONS, pc);
+      location.ClearBreakPoint(break_point_object);
 
       // If there are no more break points left remove the debug info for this
       // function.
@@ -1182,15 +1086,17 @@ void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
 }
 
 
+// Clear out all the debug break code. This is ONLY supposed to be used when
+// shutting down the debugger as it will leave the break point information in
+// DebugInfo even though the code is patched back to the non break point state.
 void Debug::ClearAllBreakPoints() {
-  DebugInfoListNode* node = debug_info_list_;
-  while (node != NULL) {
-    // Remove all debug break code.
-    BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
-    it.ClearAllDebugBreak();
-    node = node->next();
+  for (DebugInfoListNode* node = debug_info_list_; node != NULL;
+       node = node->next()) {
+    for (BreakLocation::Iterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
+         !it.Done(); it.Next()) {
+      it.GetBreakLocation().ClearDebugBreak();
+    }
   }
-
   // Remove all debug info.
   while (debug_info_list_ != NULL) {
     RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info());
@@ -1213,10 +1119,9 @@ void Debug::FloodWithOneShot(Handle<JSFunction> function,
   }
 
   // Flood the function with break points.
-  BreakLocationIterator it(GetDebugInfo(shared), type);
-  while (!it.Done()) {
-    it.SetOneShot();
-    it.Next();
+  for (BreakLocation::Iterator it(GetDebugInfo(shared), type); !it.Done();
+       it.Next()) {
+    it.GetBreakLocation().SetOneShot();
   }
 }
 
@@ -1284,8 +1189,9 @@ void Debug::FloodHandlerWithOneShot() {
   }
   for (JavaScriptFrameIterator it(isolate_, id); !it.done(); it.Advance()) {
     JavaScriptFrame* frame = it.frame();
-    if (frame->HasHandler()) {
-      // Flood the function with the catch block with break points
+    int stack_slots = 0;  // The computed stack slot count is not used.
+    if (frame->LookupExceptionHandlerInTable(&stack_slots) > 0) {
+      // Flood the function with the catch/finally block with break points.
       FloodWithOneShot(Handle<JSFunction>(frame->function()));
       return;
     }
@@ -1362,8 +1268,12 @@ void Debug::PrepareStep(StepAction step_action,
     return;
   }
 
+  List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
+  frames_it.frame()->Summarize(&frames);
+  FrameSummary summary = frames.first();
+
   // Get the debug info (create it if it does not exist).
-  Handle<JSFunction> function(frame->function());
+  Handle<JSFunction> function(summary.function());
   Handle<SharedFunctionInfo> shared(function->shared());
   if (!EnsureDebugInfo(shared, function)) {
     // Return if ensuring debug info failed.
@@ -1371,47 +1281,38 @@ void Debug::PrepareStep(StepAction step_action,
   }
   Handle<DebugInfo> debug_info = GetDebugInfo(shared);
 
-  // Find the break location where execution has stopped.
-  BreakLocationIterator it(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.
-  it.FindBreakLocationFromAddress(frame->pc() - 1);
-
   // Compute whether or not the target is a call target.
   bool is_load_or_store = false;
   bool is_inline_cache_stub = false;
   bool is_at_restarted_function = false;
   Handle<Code> call_function_stub;
 
+  // PC points to the instruction after the current one, possibly a break
+  // location as well. So the "- 1" to exclude it from the search.
+  Address call_pc = summary.pc() - 1;
+  BreakLocation location =
+      BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc);
+
   if (thread_local_.restarter_frame_function_pointer_ == NULL) {
-    if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
-      bool is_call_target = false;
-      Address target = it.rinfo()->target_address();
-      Code* code = Code::GetCodeFromTargetAddress(target);
-      if (code->is_call_stub()) {
-        is_call_target = true;
-      }
-      if (code->is_inline_cache_stub()) {
-        is_inline_cache_stub = true;
-        is_load_or_store = !is_call_target;
-      }
+    if (location.IsCodeTarget()) {
+      Handle<Code> target_code = location.CodeTarget();
+      is_inline_cache_stub = target_code->is_inline_cache_stub();
+      is_load_or_store = is_inline_cache_stub && !target_code->is_call_stub();
 
       // Check if target code is CallFunction stub.
-      Code* maybe_call_function_stub = code;
+      Handle<Code> maybe_call_function_stub = target_code;
       // If there is a breakpoint at this line look at the original code to
       // check if it is a CallFunction stub.
-      if (it.IsDebugBreak()) {
-        Address original_target = it.original_rinfo()->target_address();
-        maybe_call_function_stub =
-            Code::GetCodeFromTargetAddress(original_target);
+      if (location.IsDebugBreak()) {
+        maybe_call_function_stub = location.OriginalCodeTarget();
       }
       if ((maybe_call_function_stub->kind() == Code::STUB &&
-           CodeStub::GetMajorKey(maybe_call_function_stub) ==
+           CodeStub::GetMajorKey(*maybe_call_function_stub) ==
                CodeStub::CallFunction) ||
           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);
+        call_function_stub = maybe_call_function_stub;
       }
     }
   } else {
@@ -1419,14 +1320,14 @@ void Debug::PrepareStep(StepAction step_action,
   }
 
   // If this is the last break code target step out is the only possibility.
-  if (it.IsExit() || step_action == StepOut) {
+  if (location.IsExit() || step_action == StepOut) {
     if (step_action == StepOut) {
       // Skip step_count frames starting with the current one.
       while (step_count-- > 0 && !frames_it.done()) {
         frames_it.Advance();
       }
     } else {
-      DCHECK(it.IsExit());
+      DCHECK(location.IsExit());
       frames_it.Advance();
     }
     // Skip builtin functions on the stack.
@@ -1443,9 +1344,9 @@ void Debug::PrepareStep(StepAction step_action,
       // Set target frame pointer.
       ActivateStepOut(frames_it.frame());
     }
-  } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) ||
-               !call_function_stub.is_null() || is_at_restarted_function)
-             || step_action == StepNext || step_action == StepMin) {
+  } else if (!(is_inline_cache_stub || location.IsConstructCall() ||
+               !call_function_stub.is_null() || is_at_restarted_function) ||
+             step_action == StepNext || step_action == StepMin) {
     // Step next or step min.
 
     // Fill the current function with one-shot break points.
@@ -1455,7 +1356,7 @@ void Debug::PrepareStep(StepAction step_action,
 
     // Remember source position and frame to handle step next.
     thread_local_.last_statement_position_ =
-        debug_info->code()->SourceStatementPosition(frame->pc());
+        debug_info->code()->SourceStatementPosition(summary.pc());
     thread_local_.last_fp_ = frame->UnpaddedFP();
   } else {
     // If there's restarter frame on top of the stack, just get the pointer
@@ -1527,12 +1428,20 @@ void Debug::PrepareStep(StepAction step_action,
       // Object::Get/SetPropertyWithAccessor, otherwise the step action will be
       // propagated on the next Debug::Break.
       thread_local_.last_statement_position_ =
-          debug_info->code()->SourceStatementPosition(frame->pc());
+          debug_info->code()->SourceStatementPosition(summary.pc());
       thread_local_.last_fp_ = frame->UnpaddedFP();
     }
 
     // Step in or Step in min
-    it.PrepareStepIn(isolate_);
+    // Step in through construct call requires no changes to the running code.
+    // Step in through getters/setters should already be prepared as well
+    // because caller of this function (Debug::PrepareStep) is expected to
+    // flood the top frame's function with one shot breakpoints.
+    // Step in through CallFunction stub should also be prepared by caller of
+    // this function (Debug::PrepareStep) which should flood target function
+    // with breakpoints.
+    DCHECK(location.IsConstructCall() || is_inline_cache_stub ||
+           !call_function_stub.is_null() || is_at_restarted_function);
     ActivateStepIn(frame);
   }
 }
@@ -1544,7 +1453,7 @@ void Debug::PrepareStep(StepAction step_action,
 // there will be several break points in the same statement when the code is
 // flooded with one-shot break points. This function helps to perform several
 // steps before reporting break back to the debugger.
-bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
+bool Debug::StepNextContinue(BreakLocation* break_location,
                              JavaScriptFrame* frame) {
   // StepNext and StepOut shouldn't bring us deeper in code, so last frame
   // shouldn't be a parent of current frame.
@@ -1563,11 +1472,11 @@ bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
   // statement is hit.
   if (step_action == StepNext || step_action == StepIn) {
     // Never continue if returning from function.
-    if (break_location_iterator->IsExit()) return false;
+    if (break_location->IsExit()) return false;
 
     // Continue if we are still on the same frame and in the same statement.
     int current_statement_position =
-        break_location_iterator->code()->SourceStatementPosition(frame->pc());
+        break_location->code()->SourceStatementPosition(frame->pc());
     return thread_local_.last_fp_ == frame->UnpaddedFP() &&
         thread_local_.last_statement_position_ == current_statement_position;
   }
@@ -1585,9 +1494,6 @@ bool Debug::IsDebugBreak(Address addr) {
 }
 
 
-
-
-
 // Simple function for returning the source positions for active break points.
 Handle<Object> Debug::GetSourceBreakLocations(
     Handle<SharedFunctionInfo> shared,
@@ -1674,15 +1580,12 @@ void Debug::ClearOneShot() {
   // The current implementation just runs through all the breakpoints. When the
   // last break point for a function is removed that function is automatically
   // removed from the list.
-
-  DebugInfoListNode* node = debug_info_list_;
-  while (node != NULL) {
-    BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
-    while (!it.Done()) {
-      it.ClearOneShot();
-      it.Next();
+  for (DebugInfoListNode* node = debug_info_list_; node != NULL;
+       node = node->next()) {
+    for (BreakLocation::Iterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
+         !it.Done(); it.Next()) {
+      it.GetBreakLocation().ClearOneShot();
     }
-    node = node->next();
   }
 }
 
@@ -2098,8 +2001,8 @@ void Debug::PrepareForBreakPoints() {
 }
 
 
-Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
-                                              int position) {
+Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
+                                                     int position) {
   // Iterate the heap looking for SharedFunctionInfo generated from the
   // script. The inner most SharedFunctionInfo containing the source position
   // for the requested break point is found.
@@ -2182,7 +2085,7 @@ Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
       }  // End for loop.
     }  // End no-allocation scope.
 
-    if (target.is_null()) return heap->undefined_value();
+    if (target.is_null()) return isolate_->factory()->undefined_value();
 
     // There will be at least one break point when we are done.
     has_break_points_ = true;
@@ -2198,7 +2101,7 @@ Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
       MaybeHandle<Code> maybe_result = target_function.is_null()
           ? Compiler::GetUnoptimizedCode(target)
           : Compiler::GetUnoptimizedCode(target_function);
-      if (maybe_result.is_null()) return isolate_->heap()->undefined_value();
+      if (maybe_result.is_null()) return isolate_->factory()->undefined_value();
     }
   }  // End while loop.
 
@@ -2217,7 +2120,7 @@ Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
     }
   }
 
-  return *target;
+  return target;
 }
 
 
@@ -2241,6 +2144,10 @@ bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared,
     return false;
   }
 
+  // Make sure IC state is clean.
+  shared->code()->ClearInlineCaches();
+  shared->feedback_vector()->ClearICSlots(*shared);
+
   // Create the debug info object.
   Handle<DebugInfo> debug_info = isolate->factory()->NewDebugInfo(shared);
 
@@ -2579,7 +2486,7 @@ MaybeHandle<Object> Debug::MakeAsyncTaskEvent(Handle<JSObject> task_event) {
 }
 
 
-void Debug::OnThrow(Handle<Object> exception, bool uncaught) {
+void Debug::OnThrow(Handle<Object> exception) {
   if (in_debug_scope() || ignore_events()) return;
   // Temporarily clear any scheduled_exception to allow evaluating
   // JavaScript from the debug event handler.
@@ -2589,7 +2496,7 @@ void Debug::OnThrow(Handle<Object> exception, bool uncaught) {
     scheduled_exception = handle(isolate_->scheduled_exception(), isolate_);
     isolate_->clear_scheduled_exception();
   }
-  OnException(exception, uncaught, isolate_->GetPromiseOnStackOnThrow());
+  OnException(exception, isolate_->GetPromiseOnStackOnThrow());
   if (!scheduled_exception.is_null()) {
     isolate_->thread_local_top()->scheduled_exception_ = *scheduled_exception;
   }
@@ -2602,7 +2509,7 @@ void Debug::OnPromiseReject(Handle<JSObject> promise, Handle<Object> value) {
   // 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);
+    OnException(value, promise);
   }
 }
 
@@ -2617,9 +2524,10 @@ MaybeHandle<Object> Debug::PromiseHasUserDefinedRejectHandler(
 }
 
 
-void Debug::OnException(Handle<Object> exception, bool uncaught,
-                        Handle<Object> promise) {
-  if (!uncaught && promise->IsJSObject()) {
+void Debug::OnException(Handle<Object> exception, Handle<Object> promise) {
+  Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher();
+  bool uncaught = (catch_type == Isolate::NOT_CAUGHT);
+  if (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();
@@ -3181,8 +3089,19 @@ void Debug::HandleDebugBreak() {
   bool debug_command_only = isolate_->stack_guard()->CheckDebugCommand() &&
                             !isolate_->stack_guard()->CheckDebugBreak();
 
+  bool is_debugger_statement = !isolate_->stack_guard()->CheckDebugCommand() &&
+                               !isolate_->stack_guard()->CheckDebugBreak();
+
   isolate_->stack_guard()->ClearDebugBreak();
 
+  if (is_debugger_statement) {
+    // If we have been called via 'debugger' Javascript statement,
+    // we might not be prepared for breakpoints.
+    // TODO(dslomov,yangguo): CheckDebugBreak may race with RequestDebugBreak.
+    // Revisit this to clean-up.
+    HandleScope handle_scope(isolate_);
+    PrepareForBreakPoints();
+  }
   ProcessDebugMessages(debug_command_only);
 }
 
index 0ec9024..3a9f823 100644 (file)
@@ -66,84 +66,161 @@ enum BreakPositionAlignment {
 };
 
 
-// Class for iterating through the break points in a function and changing
-// them.
-class BreakLocationIterator {
+class BreakLocation {
  public:
-  explicit BreakLocationIterator(Handle<DebugInfo> debug_info,
-                                 BreakLocatorType type);
-  virtual ~BreakLocationIterator();
-
-  void Next();
-  void Next(int count);
-  void FindBreakLocationFromAddress(Address pc);
-  void FindBreakLocationFromPosition(int position,
-      BreakPositionAlignment alignment);
-  void Reset();
-  bool Done() const;
+  // Find the break point at the supplied address, or the closest one before
+  // the address.
+  static BreakLocation FromAddress(Handle<DebugInfo> debug_info,
+                                   BreakLocatorType type, Address pc);
+
+  static void FromAddressSameStatement(Handle<DebugInfo> debug_info,
+                                       BreakLocatorType type, Address pc,
+                                       List<BreakLocation>* result_out);
+
+  static BreakLocation FromPosition(Handle<DebugInfo> debug_info,
+                                    BreakLocatorType type, int position,
+                                    BreakPositionAlignment alignment);
+
+  bool IsDebugBreak() const;
+  inline bool IsExit() const { return RelocInfo::IsJSReturn(rmode_); }
+  inline bool IsConstructCall() const {
+    return RelocInfo::IsConstructCall(rmode_);
+  }
+  inline bool IsCodeTarget() const { return RelocInfo::IsCodeTarget(rmode_); }
+
+  Handle<Code> CodeTarget() const;
+  Handle<Code> OriginalCodeTarget() const;
+
+  bool IsStepInLocation() const;
+  inline bool HasBreakPoint() const {
+    return debug_info_->HasBreakPoint(pc_offset_);
+  }
+
+  Handle<Object> BreakPointObjects() const;
+
   void SetBreakPoint(Handle<Object> break_point_object);
   void ClearBreakPoint(Handle<Object> break_point_object);
+
   void SetOneShot();
   void ClearOneShot();
-  bool IsStepInLocation(Isolate* isolate);
-  void PrepareStepIn(Isolate* isolate);
-  bool IsExit() const;
-  bool HasBreakPoint();
-  bool IsDebugBreak();
-  Object* BreakPointObjects();
-  void ClearAllDebugBreak();
-
 
-  inline int code_position() {
-    return static_cast<int>(pc() - debug_info_->code()->entry());
-  }
-  inline int break_point() { return break_point_; }
-  inline int position() { return position_; }
-  inline int statement_position() { return statement_position_; }
-  inline Address pc() { return reloc_iterator_->rinfo()->pc(); }
-  inline Code* code() { return debug_info_->code(); }
-  inline RelocInfo* rinfo() { return reloc_iterator_->rinfo(); }
-  inline RelocInfo::Mode rmode() const {
-    return reloc_iterator_->rinfo()->rmode();
+  inline RelocInfo rinfo() const {
+    return RelocInfo(pc(), rmode(), data_, code());
   }
-  inline RelocInfo* original_rinfo() {
-    return reloc_iterator_original_->rinfo();
-  }
-  inline RelocInfo::Mode original_rmode() const {
-    return reloc_iterator_original_->rinfo()->rmode();
+
+  inline RelocInfo original_rinfo() const {
+    return RelocInfo(original_pc(), original_rmode(), original_data_,
+                     original_code());
   }
 
-  bool IsDebuggerStatement();
+  inline int position() const { return position_; }
+  inline int statement_position() const { return statement_position_; }
+
+  inline Address pc() const { return code()->entry() + pc_offset_; }
+  inline Address original_pc() const {
+    return original_code()->entry() + original_pc_offset_;
+  }
 
- protected:
-  bool RinfoDone() const;
-  void RinfoNext();
+  inline RelocInfo::Mode rmode() const { return rmode_; }
+  inline RelocInfo::Mode original_rmode() const { return original_rmode_; }
 
-  BreakLocatorType type_;
-  int break_point_;
-  int position_;
-  int statement_position_;
-  Handle<DebugInfo> debug_info_;
-  RelocIterator* reloc_iterator_;
-  RelocIterator* reloc_iterator_original_;
+  inline Code* code() const { return debug_info_->code(); }
+  inline Code* original_code() const { return debug_info_->original_code(); }
 
  private:
-  void SetDebugBreak();
-  void ClearDebugBreak();
+  BreakLocation(Handle<DebugInfo> debug_info, RelocInfo* rinfo,
+                RelocInfo* original_rinfo, int position, int statement_position)
+      : debug_info_(debug_info),
+        pc_offset_(static_cast<int>(rinfo->pc() - debug_info->code()->entry())),
+        original_pc_offset_(static_cast<int>(
+            original_rinfo->pc() - debug_info->original_code()->entry())),
+        rmode_(rinfo->rmode()),
+        original_rmode_(original_rinfo->rmode()),
+        data_(rinfo->data()),
+        original_data_(original_rinfo->data()),
+        position_(position),
+        statement_position_(statement_position) {}
+
+  class Iterator {
+   public:
+    Iterator(Handle<DebugInfo> debug_info, BreakLocatorType type);
 
-  void SetDebugBreakAtIC();
-  void ClearDebugBreakAtIC();
+    BreakLocation GetBreakLocation() {
+      return BreakLocation(debug_info_, rinfo(), original_rinfo(), position(),
+                           statement_position());
+    }
 
-  bool IsDebugBreakAtReturn();
-  void SetDebugBreakAtReturn();
-  void ClearDebugBreakAtReturn();
+    inline bool Done() const { return RinfoDone(); }
+    void Next();
+
+    void SkipTo(int count) {
+      while (count-- > 0) Next();
+    }
+
+    inline RelocInfo::Mode rmode() { return reloc_iterator_.rinfo()->rmode(); }
+    inline RelocInfo::Mode original_rmode() {
+      return reloc_iterator_.rinfo()->rmode();
+    }
+
+    inline RelocInfo* rinfo() { return reloc_iterator_.rinfo(); }
+    inline RelocInfo* original_rinfo() {
+      return reloc_iterator_original_.rinfo();
+    }
 
-  bool IsDebugBreakSlot();
-  bool IsDebugBreakAtSlot();
+    inline Address pc() { return rinfo()->pc(); }
+    inline Address original_pc() { return original_rinfo()->pc(); }
+
+    int break_index() const { return break_index_; }
+
+    inline int position() const { return position_; }
+    inline int statement_position() const { return statement_position_; }
+
+   private:
+    bool RinfoDone() const;
+    void RinfoNext();
+
+    Handle<DebugInfo> debug_info_;
+    BreakLocatorType type_;
+    RelocIterator reloc_iterator_;
+    RelocIterator reloc_iterator_original_;
+    int break_index_;
+    int position_;
+    int statement_position_;
+
+    DisallowHeapAllocation no_gc_;
+
+    DISALLOW_COPY_AND_ASSIGN(Iterator);
+  };
+
+  friend class Debug;
+
+  static int BreakIndexFromAddress(Handle<DebugInfo> debug_info,
+                                   BreakLocatorType type, Address pc);
+
+  void ClearDebugBreak();
+  void RestoreFromOriginal(int length_in_bytes);
+
+  void SetDebugBreak();
+  void SetDebugBreakAtReturn();
   void SetDebugBreakAtSlot();
-  void ClearDebugBreakAtSlot();
+  void SetDebugBreakAtIC();
+
+  inline bool IsDebuggerStatement() const {
+    return RelocInfo::IsDebuggerStatement(rmode_);
+  }
+  inline bool IsDebugBreakSlot() const {
+    return RelocInfo::IsDebugBreakSlot(rmode_);
+  }
 
-  DISALLOW_COPY_AND_ASSIGN(BreakLocationIterator);
+  Handle<DebugInfo> debug_info_;
+  int pc_offset_;
+  int original_pc_offset_;
+  RelocInfo::Mode rmode_;
+  RelocInfo::Mode original_rmode_;
+  intptr_t data_;
+  intptr_t original_data_;
+  int position_;
+  int statement_position_;
 };
 
 
@@ -184,15 +261,17 @@ class ScriptCache : private HashMap {
 class DebugInfoListNode {
  public:
   explicit DebugInfoListNode(DebugInfo* debug_info);
-  virtual ~DebugInfoListNode();
+  virtual ~DebugInfoListNode() { ClearInfo(); }
 
   DebugInfoListNode* next() { return next_; }
   void set_next(DebugInfoListNode* next) { next_ = next; }
-  Handle<DebugInfo> debug_info() { return debug_info_; }
+  Handle<DebugInfo> debug_info() { return Handle<DebugInfo>(debug_info_); }
+
+  void ClearInfo();
 
  private:
   // Global (weak) handle to the debug info object.
-  Handle<DebugInfo> debug_info_;
+  DebugInfo** debug_info_;
 
   // Next pointer for linked list.
   DebugInfoListNode* next_;
@@ -348,7 +427,7 @@ class Debug {
   // Debug event triggers.
   void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue);
 
-  void OnThrow(Handle<Object> exception, bool uncaught);
+  void OnThrow(Handle<Object> exception);
   void OnPromiseReject(Handle<JSObject> promise, Handle<Object> value);
   void OnCompileError(Handle<Script> script);
   void OnBeforeCompile(Handle<Script> script);
@@ -404,8 +483,7 @@ class Debug {
   void ClearStepping();
   void ClearStepOut();
   bool IsStepping() { return thread_local_.step_count_ > 0; }
-  bool StepNextContinue(BreakLocationIterator* break_location_iterator,
-                        JavaScriptFrame* frame);
+  bool StepNextContinue(BreakLocation* location, JavaScriptFrame* frame);
   bool StepInActive() { return thread_local_.step_into_fp_ != 0; }
   void HandleStepIn(Handle<Object> function_obj, Handle<Object> holder,
                     Address fp, bool is_constructor);
@@ -423,13 +501,11 @@ class Debug {
   static bool HasDebugInfo(Handle<SharedFunctionInfo> shared);
 
   // This function is used in FunctionNameUsing* tests.
-  Object* FindSharedFunctionInfoInScript(Handle<Script> script, int position);
+  Handle<Object> FindSharedFunctionInfoInScript(Handle<Script> script,
+                                                int position);
 
   // Returns true if the current stub call is patched to call the debugger.
   static bool IsDebugBreak(Address addr);
-  // Returns true if the current return statement has been patched to be
-  // a debugger breakpoint.
-  static bool IsDebugBreakAtReturn(RelocInfo* rinfo);
 
   static Handle<Object> GetSourceBreakLocations(
       Handle<SharedFunctionInfo> shared,
@@ -521,8 +597,7 @@ class Debug {
     return break_disabled_ || in_debug_event_listener_;
   }
 
-  void OnException(Handle<Object> exception, bool uncaught,
-                   Handle<Object> promise);
+  void OnException(Handle<Object> exception, Handle<Object> promise);
 
   // Constructors for debug event objects.
   MUST_USE_RESULT MaybeHandle<Object> MakeJSObject(
index 665279a..a8de06e 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "src/accessors.h"
 #include "src/codegen.h"
+#include "src/cpu-profiler.h"
 #include "src/deoptimizer.h"
 #include "src/disasm.h"
 #include "src/full-codegen.h"
@@ -609,8 +610,7 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
   disallow_heap_allocation_ = new DisallowHeapAllocation();
 #endif  // DEBUG
   if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
-    PROFILE(isolate_, CodeDeoptEvent(compiled_code_, bailout_id_, from_,
-                                     fp_to_sp_delta_));
+    PROFILE(isolate_, CodeDeoptEvent(compiled_code_, from_, fp_to_sp_delta_));
   }
   unsigned size = ComputeInputFrameSize();
   input_ = new(size) FrameDescription(size, function);
@@ -769,7 +769,7 @@ void Deoptimizer::DoComputeOutputFrames() {
            fp_to_sp_delta_);
     if (bailout_type_ == EAGER || bailout_type_ == SOFT ||
         (compiled_code_->is_hydrogen_stub())) {
-      compiled_code_->PrintDeoptLocation(trace_scope_->file(), bailout_id_);
+      compiled_code_->PrintDeoptLocation(trace_scope_->file(), from_);
     }
   }
 
@@ -3648,34 +3648,22 @@ const char* Deoptimizer::GetDeoptReason(DeoptReason deopt_reason) {
 }
 
 
-Deoptimizer::DeoptInfo Deoptimizer::GetDeoptInfo(Code* code, int bailout_id) {
-  int last_position = 0;
-  Isolate* isolate = code->GetIsolate();
+Deoptimizer::DeoptInfo Deoptimizer::GetDeoptInfo(Code* code, Address pc) {
+  SourcePosition last_position = SourcePosition::Unknown();
   Deoptimizer::DeoptReason last_reason = Deoptimizer::kNoReason;
   int mask = RelocInfo::ModeMask(RelocInfo::DEOPT_REASON) |
-             RelocInfo::ModeMask(RelocInfo::POSITION) |
-             RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
+             RelocInfo::ModeMask(RelocInfo::POSITION);
   for (RelocIterator it(code, mask); !it.done(); it.next()) {
     RelocInfo* info = it.rinfo();
+    if (info->pc() >= pc) return DeoptInfo(last_position, NULL, last_reason);
     if (info->rmode() == RelocInfo::POSITION) {
-      last_position = static_cast<int>(info->data());
+      int raw_position = static_cast<int>(info->data());
+      last_position = raw_position ? SourcePosition::FromRaw(raw_position)
+                                   : SourcePosition::Unknown();
     } else if (info->rmode() == RelocInfo::DEOPT_REASON) {
       last_reason = static_cast<Deoptimizer::DeoptReason>(info->data());
-    } else if (last_reason != Deoptimizer::kNoReason) {
-      if ((bailout_id ==
-           Deoptimizer::GetDeoptimizationId(isolate, info->target_address(),
-                                            Deoptimizer::EAGER)) ||
-          (bailout_id ==
-           Deoptimizer::GetDeoptimizationId(isolate, info->target_address(),
-                                            Deoptimizer::SOFT)) ||
-          (bailout_id ==
-           Deoptimizer::GetDeoptimizationId(isolate, info->target_address(),
-                                            Deoptimizer::LAZY))) {
-        CHECK(RelocInfo::IsRuntimeEntry(info->rmode()));
-        return DeoptInfo(last_position, NULL, last_reason);
-      }
     }
   }
-  return DeoptInfo(0, NULL, Deoptimizer::kNoReason);
+  return DeoptInfo(SourcePosition::Unknown(), NULL, Deoptimizer::kNoReason);
 }
 } }  // namespace v8::internal
index 471a05d..fd65e83 100644 (file)
@@ -132,7 +132,6 @@ class OptimizedFunctionVisitor BASE_EMBEDDED {
   V(kNotAHeapNumberUndefined, "not a heap number/undefined")                   \
   V(kNotAJavaScriptObject, "not a JavaScript object")                          \
   V(kNotASmi, "not a Smi")                                                     \
-  V(kNotHeapNumber, "not heap number")                                         \
   V(kNull, "null")                                                             \
   V(kOutOfBounds, "out of bounds")                                             \
   V(kOutsideOfRange, "Outside of range")                                       \
@@ -184,15 +183,16 @@ class Deoptimizer : public Malloced {
   static const char* GetDeoptReason(DeoptReason deopt_reason);
 
   struct DeoptInfo {
-    DeoptInfo(int r, const char* m, DeoptReason d)
-        : raw_position(r), mnemonic(m), deopt_reason(d) {}
+    DeoptInfo(SourcePosition position, const char* m, DeoptReason d)
+        : position(position), mnemonic(m), deopt_reason(d), inlining_id(0) {}
 
-    int raw_position;
+    SourcePosition position;
     const char* mnemonic;
     DeoptReason deopt_reason;
+    int inlining_id;
   };
 
-  static DeoptInfo GetDeoptInfo(Code* code, int bailout_id);
+  static DeoptInfo GetDeoptInfo(Code* code, byte* from);
 
   struct JumpTableEntry : public ZoneObject {
     inline JumpTableEntry(Address entry, const DeoptInfo& deopt_info,
@@ -322,11 +322,10 @@ class Deoptimizer : public Malloced {
   static const int kNotDeoptimizationEntry = -1;
 
   // Generators for the deoptimization entry code.
-  class EntryGenerator BASE_EMBEDDED {
+  class TableEntryGenerator BASE_EMBEDDED {
    public:
-    EntryGenerator(MacroAssembler* masm, BailoutType type)
-        : masm_(masm), type_(type) { }
-    virtual ~EntryGenerator() { }
+    TableEntryGenerator(MacroAssembler* masm, BailoutType type, int count)
+        : masm_(masm), type_(type), count_(count) {}
 
     void Generate();
 
@@ -335,24 +334,13 @@ class Deoptimizer : public Malloced {
     BailoutType type() const { return type_; }
     Isolate* isolate() const { return masm_->isolate(); }
 
-    virtual void GeneratePrologue() { }
-
-   private:
-    MacroAssembler* masm_;
-    Deoptimizer::BailoutType type_;
-  };
-
-  class TableEntryGenerator : public EntryGenerator {
-   public:
-    TableEntryGenerator(MacroAssembler* masm, BailoutType type,  int count)
-        : EntryGenerator(masm, type), count_(count) { }
-
-   protected:
-    virtual void GeneratePrologue();
+    void GeneratePrologue();
 
    private:
     int count() const { return count_; }
 
+    MacroAssembler* masm_;
+    Deoptimizer::BailoutType type_;
     int count_;
   };
 
index e031644..fbdda54 100644 (file)
@@ -11,7 +11,7 @@
 #include "src/disasm.h"
 #include "src/disassembler.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
+#include "src/snapshot/serialize.h"
 #include "src/string-stream.h"
 
 namespace v8 {
@@ -85,14 +85,11 @@ static int DecodeIt(Isolate* isolate, std::ostream* os,
   } else {
     // No relocation information when printing code stubs.
   }
-#if !V8_TARGET_ARCH_PPC
   int constants = -1;  // no constants being decoded at the start
-#endif
 
   while (pc < end) {
     // First decode instruction so that we know its length.
     byte* prev_pc = pc;
-#if !V8_TARGET_ARCH_PPC
     if (constants > 0) {
       SNPrintF(decode_buffer,
                "%08x       constant",
@@ -121,25 +118,6 @@ static int DecodeIt(Isolate* isolate, std::ostream* os,
         pc += d.InstructionDecode(decode_buffer, pc);
       }
     }
-#else  // !V8_TARGET_ARCH_PPC
-#if ABI_USES_FUNCTION_DESCRIPTORS || V8_OOL_CONSTANT_POOL
-    // Function descriptors are specially decoded and skipped.
-    // Other internal references (load of ool constant pool pointer)
-    // are not since they are a encoded as a regular mov sequence.
-    int skip;
-    if (it != NULL && !it->done() && it->rinfo()->pc() == pc &&
-        it->rinfo()->rmode() == RelocInfo::INTERNAL_REFERENCE &&
-        (skip = Assembler::DecodeInternalReference(decode_buffer, pc))) {
-      pc += skip;
-    } else {
-      decode_buffer[0] = '\0';
-      pc += d.InstructionDecode(decode_buffer, pc);
-    }
-#else
-    decode_buffer[0] = '\0';
-    pc += d.InstructionDecode(decode_buffer, pc);
-#endif  // ABI_USES_FUNCTION_DESCRIPTORS || V8_OOL_CONSTANT_POOL
-#endif  // !V8_TARGET_ARCH_PPC
 
     // Collect RelocInfo for this instruction (prev_pc .. pc-1)
     List<const char*> comments(4);
@@ -207,8 +185,8 @@ static int DecodeIt(Isolate* isolate, std::ostream* os,
         SmartArrayPointer<const char> obj_name = accumulator.ToCString();
         out.AddFormatted("    ;; object: %s", obj_name.get());
       } else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
-        const char* reference_name =
-            ref_encoder.NameOfAddress(relocinfo.target_reference());
+        const char* reference_name = ref_encoder.NameOfAddress(
+            isolate, relocinfo.target_external_reference());
         out.AddFormatted("    ;; external reference (%s)", reference_name);
       } else if (RelocInfo::IsCodeTarget(rmode)) {
         out.AddFormatted("    ;; code:");
index cd7ba98..c523818 100644 (file)
@@ -991,10 +991,10 @@ class FastElementsAccessor
            (IsFastDoubleElementsKind(KindTraits::Kind) ==
             ((map == isolate->heap()->fixed_array_map() && length == 0) ||
              map == isolate->heap()->fixed_double_array_map())));
+    if (length == 0) return;  // nothing to do!
     DisallowHeapAllocation no_gc;
+    Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
     for (int i = 0; i < length; i++) {
-      HandleScope scope(isolate);
-      Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
       DCHECK((!IsFastSmiElementsKind(KindTraits::Kind) ||
               BackingStore::get(backing_store, i)->IsSmi()) ||
              (IsFastHoleyElementsKind(KindTraits::Kind) ==
index 9dfef37..7ae6741 100644 (file)
@@ -210,11 +210,11 @@ MaybeHandle<Object> Execution::TryCall(Handle<JSFunction> func,
       DCHECK(catcher.HasCaught());
       DCHECK(isolate->has_pending_exception());
       DCHECK(isolate->external_caught_exception());
-      if (exception_out != NULL) {
-        if (isolate->pending_exception() ==
-            isolate->heap()->termination_exception()) {
-          is_termination = true;
-        } else {
+      if (isolate->pending_exception() ==
+          isolate->heap()->termination_exception()) {
+        is_termination = true;
+      } else {
+        if (exception_out != NULL) {
           *exception_out = v8::Utils::OpenHandle(*catcher.Exception());
         }
       }
@@ -222,9 +222,11 @@ MaybeHandle<Object> Execution::TryCall(Handle<JSFunction> func,
     }
 
     DCHECK(!isolate->has_pending_exception());
-    DCHECK(!isolate->external_caught_exception());
   }
-  if (is_termination) isolate->TerminateExecution();
+
+  // Re-request terminate execution interrupt to trigger later.
+  if (is_termination) isolate->stack_guard()->RequestTerminateExecution();
+
   return maybe_result;
 }
 
@@ -649,6 +651,13 @@ Handle<String> Execution::GetStackTraceLine(Handle<Object> recv,
 }
 
 
+void StackGuard::CheckAndHandleGCInterrupt() {
+  if (CheckAndClearInterrupt(GC_REQUEST)) {
+    isolate_->heap()->HandleGCRequest();
+  }
+}
+
+
 Object* StackGuard::HandleInterrupts() {
   if (CheckAndClearInterrupt(GC_REQUEST)) {
     isolate_->heap()->HandleGCRequest();
index 47cbb08..870bb91 100644 (file)
@@ -197,6 +197,10 @@ class StackGuard FINAL {
   // stack overflow, then handle the interruption accordingly.
   Object* HandleInterrupts();
 
+  bool InterruptRequested() { return GetCurrentStackPosition() < climit(); }
+
+  void CheckAndHandleGCInterrupt();
+
  private:
   StackGuard();
 
index 2c1f91d..58f808b 100644 (file)
@@ -123,11 +123,6 @@ void StatisticsExtension::GetCounters(
       {heap->cell_space()->Size(), "cell_space_live_bytes"},
       {heap->cell_space()->Available(), "cell_space_available_bytes"},
       {heap->cell_space()->CommittedMemory(), "cell_space_commited_bytes"},
-      {heap->property_cell_space()->Size(), "property_cell_space_live_bytes"},
-      {heap->property_cell_space()->Available(),
-       "property_cell_space_available_bytes"},
-      {heap->property_cell_space()->CommittedMemory(),
-       "property_cell_space_commited_bytes"},
       {heap->lo_space()->Size(), "lo_space_live_bytes"},
       {heap->lo_space()->Available(), "lo_space_available_bytes"},
       {heap->lo_space()->CommittedMemory(), "lo_space_commited_bytes"},
index 95590ad..1cdce60 100644 (file)
@@ -538,10 +538,30 @@ MaybeHandle<String> Factory::NewConsString(Handle<String> left,
             NewRawTwoByteString(length).ToHandleChecked(), left, right);
   }
 
-  Handle<Map> map = (is_one_byte || is_one_byte_data_in_two_byte_string)
-                        ? cons_one_byte_string_map()
-                        : cons_string_map();
-  Handle<ConsString> result =  New<ConsString>(map, NEW_SPACE);
+  return (is_one_byte || is_one_byte_data_in_two_byte_string)
+             ? NewOneByteConsString(length, left, right)
+             : NewTwoByteConsString(length, left, right);
+}
+
+
+MaybeHandle<String> Factory::NewOneByteConsString(int length,
+                                                  Handle<String> left,
+                                                  Handle<String> right) {
+  return NewRawConsString(cons_one_byte_string_map(), length, left, right);
+}
+
+
+MaybeHandle<String> Factory::NewTwoByteConsString(int length,
+                                                  Handle<String> left,
+                                                  Handle<String> right) {
+  return NewRawConsString(cons_string_map(), length, left, right);
+}
+
+
+MaybeHandle<String> Factory::NewRawConsString(Handle<Map> map, int length,
+                                              Handle<String> left,
+                                              Handle<String> right) {
+  Handle<ConsString> result = New<ConsString>(map, NEW_SPACE);
 
   DisallowHeapAllocation no_gc;
   WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
@@ -802,7 +822,6 @@ Handle<CodeCache> Factory::NewCodeCache() {
       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;
 }
 
@@ -905,7 +924,7 @@ Handle<Cell> Factory::NewCell(Handle<Object> value) {
 }
 
 
-Handle<PropertyCell> Factory::NewPropertyCellWithHole() {
+Handle<PropertyCell> Factory::NewPropertyCell() {
   CALL_HEAP_FUNCTION(
       isolate(),
       isolate()->heap()->AllocatePropertyCell(),
@@ -913,14 +932,6 @@ Handle<PropertyCell> Factory::NewPropertyCellWithHole() {
 }
 
 
-Handle<PropertyCell> Factory::NewPropertyCell(Handle<Object> value) {
-  AllowDeferredHandleDereference convert_to_cell;
-  Handle<PropertyCell> cell = NewPropertyCellWithHole();
-  PropertyCell::SetValueInferType(cell, value);
-  return cell;
-}
-
-
 Handle<WeakCell> Factory::NewWeakCell(Handle<HeapObject> value) {
   AllowDeferredHandleDereference convert_to_cell;
   CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->AllocateWeakCell(*value),
@@ -1053,58 +1064,58 @@ Handle<HeapNumber> Factory::NewHeapNumber(double value,
 }
 
 
-MaybeHandle<Object> Factory::NewTypeError(const char* message,
-                                          Vector<Handle<Object> > args) {
+Handle<Object> Factory::NewTypeError(const char* message,
+                                     Vector<Handle<Object> > args) {
   return NewError("MakeTypeError", message, args);
 }
 
 
-MaybeHandle<Object> Factory::NewTypeError(Handle<String> message) {
+Handle<Object> Factory::NewTypeError(Handle<String> message) {
   return NewError("$TypeError", message);
 }
 
 
-MaybeHandle<Object> Factory::NewRangeError(const char* message,
-                                           Vector<Handle<Object> > args) {
+Handle<Object> Factory::NewRangeError(const char* message,
+                                      Vector<Handle<Object> > args) {
   return NewError("MakeRangeError", message, args);
 }
 
 
-MaybeHandle<Object> Factory::NewRangeError(Handle<String> message) {
+Handle<Object> Factory::NewRangeError(Handle<String> message) {
   return NewError("$RangeError", message);
 }
 
 
-MaybeHandle<Object> Factory::NewSyntaxError(const char* message,
-                                            Handle<JSArray> args) {
+Handle<Object> Factory::NewSyntaxError(const char* message,
+                                       Handle<JSArray> args) {
   return NewError("MakeSyntaxError", message, args);
 }
 
 
-MaybeHandle<Object> Factory::NewSyntaxError(Handle<String> message) {
+Handle<Object> Factory::NewSyntaxError(Handle<String> message) {
   return NewError("$SyntaxError", message);
 }
 
 
-MaybeHandle<Object> Factory::NewReferenceError(const char* message,
-                                               Vector<Handle<Object> > args) {
+Handle<Object> Factory::NewReferenceError(const char* message,
+                                          Vector<Handle<Object> > args) {
   return NewError("MakeReferenceError", message, args);
 }
 
 
-MaybeHandle<Object> Factory::NewReferenceError(const char* message,
-                                               Handle<JSArray> args) {
+Handle<Object> Factory::NewReferenceError(const char* message,
+                                          Handle<JSArray> args) {
   return NewError("MakeReferenceError", message, args);
 }
 
 
-MaybeHandle<Object> Factory::NewReferenceError(Handle<String> message) {
+Handle<Object> Factory::NewReferenceError(Handle<String> message) {
   return NewError("$ReferenceError", message);
 }
 
 
-MaybeHandle<Object> Factory::NewError(const char* maker, const char* message,
-                                      Vector<Handle<Object> > args) {
+Handle<Object> Factory::NewError(const char* maker, const char* message,
+                                 Vector<Handle<Object> > args) {
   // Instantiate a closeable HandleScope for EscapeFrom.
   v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate()));
   Handle<FixedArray> array = NewFixedArray(args.length());
@@ -1112,21 +1123,19 @@ MaybeHandle<Object> Factory::NewError(const char* maker, const char* message,
     array->set(i, *args[i]);
   }
   Handle<JSArray> object = NewJSArrayWithElements(array);
-  Handle<Object> result;
-  ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
-                             NewError(maker, message, object), Object);
+  Handle<Object> result = NewError(maker, message, object);
   return result.EscapeFrom(&scope);
 }
 
 
-MaybeHandle<Object> Factory::NewEvalError(const char* message,
-                                          Vector<Handle<Object> > args) {
+Handle<Object> Factory::NewEvalError(const char* message,
+                                     Vector<Handle<Object> > args) {
   return NewError("MakeEvalError", message, args);
 }
 
 
-MaybeHandle<Object> Factory::NewError(const char* message,
-                                      Vector<Handle<Object> > args) {
+Handle<Object> Factory::NewError(const char* message,
+                                 Vector<Handle<Object> > args) {
   return NewError("MakeError", message, args);
 }
 
@@ -1167,8 +1176,8 @@ Handle<String> Factory::EmergencyNewError(const char* message,
 }
 
 
-MaybeHandle<Object> Factory::NewError(const char* maker, const char* message,
-                                      Handle<JSArray> args) {
+Handle<Object> Factory::NewError(const char* maker, const char* message,
+                                 Handle<JSArray> args) {
   Handle<String> make_str = InternalizeUtf8String(maker);
   Handle<Object> fun_obj = Object::GetProperty(
       isolate()->js_builtins_object(), make_str).ToHandleChecked();
@@ -1190,19 +1199,21 @@ MaybeHandle<Object> Factory::NewError(const char* maker, const char* message,
                           arraysize(argv),
                           argv,
                           &exception).ToHandle(&result)) {
-    return exception;
+    Handle<Object> exception_obj;
+    if (exception.ToHandle(&exception_obj)) return exception_obj;
+    return undefined_value();
   }
   return result;
 }
 
 
-MaybeHandle<Object> Factory::NewError(Handle<String> message) {
+Handle<Object> Factory::NewError(Handle<String> message) {
   return NewError("$Error", message);
 }
 
 
-MaybeHandle<Object> Factory::NewError(const char* constructor,
-                                      Handle<String> message) {
+Handle<Object> Factory::NewError(const char* constructor,
+                                 Handle<String> message) {
   Handle<String> constr = InternalizeUtf8String(constructor);
   Handle<JSFunction> fun = Handle<JSFunction>::cast(Object::GetProperty(
       isolate()->js_builtins_object(), constr).ToHandleChecked());
@@ -1217,7 +1228,9 @@ MaybeHandle<Object> Factory::NewError(const char* constructor,
                           arraysize(argv),
                           argv,
                           &exception).ToHandle(&result)) {
-    return exception;
+    Handle<Object> exception_obj;
+    if (exception.ToHandle(&exception_obj)) return exception_obj;
+    return undefined_value();
   }
   return result;
 }
@@ -1353,10 +1366,8 @@ Handle<JSObject> Factory::NewFunctionPrototype(Handle<JSFunction> function) {
 }
 
 
-static bool ShouldOptimizeNewClosure(Isolate* isolate,
-                                     Handle<SharedFunctionInfo> info) {
-  return isolate->use_crankshaft() && !info->is_toplevel() &&
-         info->is_compiled() && info->allows_lazy_compilation();
+static bool ShouldOptimizeNewClosure(Handle<SharedFunctionInfo> info) {
+  return !info->is_toplevel() && info->allows_lazy_compilation();
 }
 
 
@@ -1378,13 +1389,6 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
   if (!info->bound() && index < 0) {
     int number_of_literals = info->num_literals();
     Handle<FixedArray> literals = NewFixedArray(number_of_literals, pretenure);
-    if (number_of_literals > 0) {
-      // Store the native context in the literals array prefix. This
-      // context will be used when creating object, regexp and array
-      // literals in this function.
-      literals->set(JSFunction::kLiteralNativeContextIndex,
-                    context->native_context());
-    }
     result->set_literals(*literals);
   }
 
@@ -1398,7 +1402,7 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
     return result;
   }
 
-  if (FLAG_always_opt && ShouldOptimizeNewClosure(isolate(), info)) {
+  if (FLAG_always_opt && ShouldOptimizeNewClosure(info)) {
     result->MarkForOptimization();
   }
   return result;
@@ -1573,10 +1577,11 @@ Handle<GlobalObject> Factory::NewGlobalObject(Handle<JSFunction> constructor) {
     PropertyDetails details = descs->GetDetails(i);
     // Only accessors are expected.
     DCHECK_EQ(ACCESSOR_CONSTANT, details.type());
-    PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1);
+    PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
+                      PropertyCellType::kMutable);
     Handle<Name> name(descs->GetKey(i));
-    Handle<Object> value(descs->GetCallbacksObject(i), isolate());
-    Handle<PropertyCell> cell = NewPropertyCell(value);
+    Handle<PropertyCell> cell = NewPropertyCell();
+    cell->set_value(descs->GetCallbacksObject(i));
     // |dictionary| already contains enough space for all properties.
     USE(NameDictionary::Add(dictionary, name, cell, d));
   }
@@ -1791,8 +1796,14 @@ void SetupArrayBufferView(i::Isolate* isolate,
 
   obj->set_buffer(*buffer);
 
-  obj->set_weak_next(buffer->weak_first_view());
-  buffer->set_weak_first_view(*obj);
+  Heap* heap = isolate->heap();
+  if (heap->InNewSpace(*obj)) {
+    obj->set_weak_next(heap->new_array_buffer_views_list());
+    heap->set_new_array_buffer_views_list(*obj);
+  } else {
+    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);
@@ -1949,7 +1960,7 @@ void Factory::ReinitializeJSProxy(Handle<JSProxy> proxy, InstanceType type,
     InitializeFunction(js_function, shared.ToHandleChecked(), context);
   } else {
     // Provide JSObjects with a constructor.
-    map->set_constructor(context->object_function());
+    map->SetConstructor(context->object_function());
   }
 }
 
@@ -2009,9 +2020,14 @@ void Factory::BecomeJSFunction(Handle<JSProxy> proxy) {
 }
 
 
-Handle<TypeFeedbackVector> Factory::NewTypeFeedbackVector(
-    const FeedbackVectorSpec& spec) {
-  return TypeFeedbackVector::Allocate(isolate(), spec);
+template Handle<TypeFeedbackVector> Factory::NewTypeFeedbackVector(
+    const ZoneFeedbackVectorSpec* spec);
+template Handle<TypeFeedbackVector> Factory::NewTypeFeedbackVector(
+    const FeedbackVectorSpec* spec);
+
+template <typename Spec>
+Handle<TypeFeedbackVector> Factory::NewTypeFeedbackVector(const Spec* spec) {
+  return TypeFeedbackVector::Allocate<Spec>(isolate(), spec);
 }
 
 
@@ -2024,14 +2040,7 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
   shared->set_scope_info(*scope_info);
   shared->set_feedback_vector(*feedback_vector);
   shared->set_kind(kind);
-  int literals_array_size = number_of_literals;
-  // If the function contains object, regexp or array literals,
-  // allocate extra space for a literals array prefix containing the
-  // context.
-  if (number_of_literals > 0) {
-    literals_array_size += JSFunction::kLiteralsPrefixSize;
-  }
-  shared->set_num_literals(literals_array_size);
+  shared->set_num_literals(number_of_literals);
   if (IsGeneratorFunction(kind)) {
     shared->set_instance_class_name(isolate()->heap()->Generator_string());
     shared->DisableOptimization(kGenerator);
@@ -2066,8 +2075,8 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
     Handle<String> name,
     MaybeHandle<Code> maybe_code) {
   Handle<Map> map = shared_function_info_map();
-  Handle<SharedFunctionInfo> share = New<SharedFunctionInfo>(map,
-                                                             OLD_POINTER_SPACE);
+  Handle<SharedFunctionInfo> share =
+      New<SharedFunctionInfo>(map, OLD_POINTER_SPACE);
 
   // Set pointer fields.
   share->set_name(*name);
@@ -2086,9 +2095,9 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
   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);
-  FeedbackVectorSpec empty_spec;
+  FeedbackVectorSpec empty_spec(0);
   Handle<TypeFeedbackVector> feedback_vector =
-      NewTypeFeedbackVector(empty_spec);
+      NewTypeFeedbackVector(&empty_spec);
   share->set_feedback_vector(*feedback_vector, SKIP_WRITE_BARRIER);
 #if TRACE_MAPS
   share->set_unique_id(isolate()->GetNextUniqueSharedFunctionInfoId());
index 4dfd98c..0bb883d 100644 (file)
@@ -196,6 +196,14 @@ class Factory FINAL {
   // Create a new cons string object which consists of a pair of strings.
   MUST_USE_RESULT MaybeHandle<String> NewConsString(Handle<String> left,
                                                     Handle<String> right);
+  MUST_USE_RESULT MaybeHandle<String> NewOneByteConsString(
+      int length, Handle<String> left, Handle<String> right);
+  MUST_USE_RESULT MaybeHandle<String> NewTwoByteConsString(
+      int length, Handle<String> left, Handle<String> right);
+  MUST_USE_RESULT MaybeHandle<String> NewRawConsString(Handle<Map> map,
+                                                       int length,
+                                                       Handle<String> left,
+                                                       Handle<String> right);
 
   // Create a new string object which holds a proper substring of a string.
   Handle<String> NewProperSubString(Handle<String> str,
@@ -292,9 +300,7 @@ class Factory FINAL {
 
   Handle<Cell> NewCell(Handle<Object> value);
 
-  Handle<PropertyCell> NewPropertyCellWithHole();
-
-  Handle<PropertyCell> NewPropertyCell(Handle<Object> value);
+  Handle<PropertyCell> NewPropertyCell();
 
   Handle<WeakCell> NewWeakCell(Handle<HeapObject> value);
 
@@ -519,40 +525,38 @@ class Factory FINAL {
 
   // Interface for creating error objects.
 
-  MaybeHandle<Object> NewError(const char* maker, const char* message,
-                               Handle<JSArray> args);
+  Handle<Object> NewError(const char* maker, const char* message,
+                          Handle<JSArray> args);
   Handle<String> EmergencyNewError(const char* message, Handle<JSArray> args);
-  MaybeHandle<Object> NewError(const char* maker, const char* message,
-                               Vector<Handle<Object> > args);
-  MaybeHandle<Object> NewError(const char* message,
-                               Vector<Handle<Object> > args);
-  MaybeHandle<Object> NewError(Handle<String> message);
-  MaybeHandle<Object> NewError(const char* constructor, Handle<String> message);
+  Handle<Object> NewError(const char* maker, const char* message,
+                          Vector<Handle<Object> > args);
+  Handle<Object> NewError(const char* message, Vector<Handle<Object> > args);
+  Handle<Object> NewError(Handle<String> message);
+  Handle<Object> NewError(const char* constructor, Handle<String> message);
 
-  MaybeHandle<Object> NewTypeError(const char* message,
-                                   Vector<Handle<Object> > args);
-  MaybeHandle<Object> NewTypeError(Handle<String> message);
+  Handle<Object> NewTypeError(const char* message,
+                              Vector<Handle<Object> > args);
+  Handle<Object> NewTypeError(Handle<String> message);
 
-  MaybeHandle<Object> NewRangeError(const char* message,
-                                    Vector<Handle<Object> > args);
-  MaybeHandle<Object> NewRangeError(Handle<String> message);
+  Handle<Object> NewRangeError(const char* message,
+                               Vector<Handle<Object> > args);
+  Handle<Object> NewRangeError(Handle<String> message);
 
-  MaybeHandle<Object> NewInvalidStringLengthError() {
+  Handle<Object> NewInvalidStringLengthError() {
     return NewRangeError("invalid_string_length",
                          HandleVector<Object>(NULL, 0));
   }
 
-  MaybeHandle<Object> NewSyntaxError(const char* message, Handle<JSArray> args);
-  MaybeHandle<Object> NewSyntaxError(Handle<String> message);
-
-  MaybeHandle<Object> NewReferenceError(const char* message,
-                                        Vector<Handle<Object> > args);
-  MaybeHandle<Object> NewReferenceError(const char* message,
-                                        Handle<JSArray> args);
-  MaybeHandle<Object> NewReferenceError(Handle<String> message);
+  Handle<Object> NewSyntaxError(const char* message, Handle<JSArray> args);
+  Handle<Object> NewSyntaxError(Handle<String> message);
 
-  MaybeHandle<Object> NewEvalError(const char* message,
+  Handle<Object> NewReferenceError(const char* message,
                                    Vector<Handle<Object> > args);
+  Handle<Object> NewReferenceError(const char* message, Handle<JSArray> args);
+  Handle<Object> NewReferenceError(Handle<String> message);
+
+  Handle<Object> NewEvalError(const char* message,
+                              Vector<Handle<Object> > args);
 
   Handle<String> NumberToString(Handle<Object> number,
                                 bool check_number_string_cache = true);
@@ -620,8 +624,8 @@ class Factory FINAL {
                                                    MaybeHandle<Code> code);
 
   // Allocate a new type feedback vector
-  Handle<TypeFeedbackVector> NewTypeFeedbackVector(
-      const FeedbackVectorSpec& spec);
+  template <typename Spec>
+  Handle<TypeFeedbackVector> NewTypeFeedbackVector(const Spec* spec);
 
   // Allocates a new JSMessageObject object.
   Handle<JSMessageObject> NewJSMessageObject(
index 46d8aa9..f1bdc0c 100644 (file)
@@ -182,32 +182,29 @@ DEFINE_IMPLICATION(harmony, es_staging)
 DEFINE_IMPLICATION(es_staging, harmony)
 
 // 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")                         \
-  V(harmony_unicode_regexps, "harmony unicode regexps")                 \
-  V(harmony_computed_property_names, "harmony computed property names") \
-  V(harmony_rest_parameters, "harmony rest parameters")                 \
+#define HARMONY_INPROGRESS(V)                                   \
+  V(harmony_modules, "harmony modules")                         \
+  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")                 \
+  V(harmony_unicode_regexps, "harmony unicode regexps")         \
+  V(harmony_rest_parameters, "harmony rest parameters")         \
+  V(harmony_reflect, "harmony Reflect API")
 
 // Features that are complete (but still behind --harmony/es-staging flag).
-#define HARMONY_STAGED(V)                                                 \
-  V(harmony_tostring, "harmony toString")                                 \
+#define HARMONY_STAGED(V)                                               \
+  V(harmony_computed_property_names, "harmony computed property names") \
+  V(harmony_tostring, "harmony toString")
 
 // 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")                       \
-  V(harmony_classes,                                                      \
-    "harmony classes (implies block scoping & object literal extension)") \
-  V(harmony_object_literals, "harmony object literal extensions")         \
+#define HARMONY_SHIPPING(V)                                                \
+  V(harmony_numeric_literals, "harmony numeric literals")                  \
+  V(harmony_classes, "harmony classes (implies object literal extension)") \
+  V(harmony_object_literals, "harmony object literal extensions")
 
 // 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,
@@ -234,8 +231,6 @@ HARMONY_SHIPPING(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_unicode_regexps, harmony_unicode)
 
@@ -301,6 +296,8 @@ DEFINE_BOOL(collect_megamorphic_maps_from_stub_cache, true,
             "crankshaft harvests type feedback from stub cache")
 DEFINE_BOOL(hydrogen_stats, false, "print statistics for hydrogen")
 DEFINE_BOOL(trace_check_elimination, false, "trace check elimination phase")
+DEFINE_BOOL(trace_environment_liveness, false,
+            "trace liveness of local variable slots")
 DEFINE_BOOL(trace_hydrogen, false, "trace generated hydrogen to file")
 DEFINE_STRING(trace_hydrogen_filter, "*", "hydrogen tracing filter")
 DEFINE_BOOL(trace_hydrogen_stubs, false, "trace generated hydrogen for stubs")
@@ -367,10 +364,9 @@ DEFINE_BOOL(optimize_for_in, true, "optimize functions containing for-in loops")
 
 DEFINE_BOOL(concurrent_recompilation, true,
             "optimizing hot functions asynchronously on a separate thread")
-DEFINE_BOOL(job_based_recompilation, false,
+DEFINE_BOOL(job_based_recompilation, true,
             "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,
@@ -402,6 +398,7 @@ DEFINE_BOOL(turbo_verify, DEBUG_BOOL, "verify TurboFan graphs at each phase")
 DEFINE_BOOL(turbo_stats, false, "print TurboFan statistics")
 DEFINE_BOOL(turbo_splitting, true, "split nodes during scheduling in TurboFan")
 DEFINE_BOOL(turbo_types, true, "use typed lowering in TurboFan")
+DEFINE_BOOL(turbo_type_feedback, false, "use type feedback in TurboFan")
 DEFINE_BOOL(turbo_source_positions, false,
             "track source code positions when building TurboFan IR")
 DEFINE_IMPLICATION(trace_turbo, turbo_source_positions)
@@ -409,9 +406,9 @@ 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_builtin_inlining, true, "enable builtin inlining 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, turbo_types)
 DEFINE_BOOL(turbo_profiling, false, "enable profiling in TurboFan")
 // TODO(dcarney): this is just for experimentation, remove when default.
 DEFINE_BOOL(turbo_delay_ssa_decon, false,
@@ -420,11 +417,11 @@ DEFINE_BOOL(turbo_verify_allocation, DEBUG_BOOL,
             "verify register allocation in TurboFan")
 DEFINE_BOOL(turbo_move_optimization, true, "optimize gap moves in TurboFan")
 DEFINE_BOOL(turbo_jt, true, "enable jump threading in TurboFan")
-DEFINE_BOOL(turbo_osr, false, "enable OSR in TurboFan")
+DEFINE_BOOL(turbo_osr, true, "enable OSR in TurboFan")
 DEFINE_BOOL(turbo_exceptions, false, "enable exception handling in TurboFan")
 DEFINE_BOOL(turbo_stress_loop_peeling, false,
             "stress loop peeling optimization")
-DEFINE_BOOL(turbo_switch, true, "optimize switches in TurboFan")
+DEFINE_BOOL(turbo_cf_optimization, true, "optimize control flow in TurboFan")
 
 DEFINE_INT(typed_array_max_size_in_heap, 64,
            "threshold for in-heap typed array")
@@ -578,6 +575,8 @@ 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")
+DEFINE_INT(retain_maps_for_n_gc, 2,
+           "keeps maps alive for <n> old space garbage collections")
 DEFINE_BOOL(trace_gc, false,
             "print one trace line following each garbage collection")
 DEFINE_BOOL(trace_gc_nvp, false,
@@ -596,8 +595,9 @@ DEFINE_BOOL(print_max_heap_committed, false,
             "in name=value format on exit")
 DEFINE_BOOL(trace_gc_verbose, false,
             "print more details following each garbage collection")
-DEFINE_BOOL(trace_fragmentation, false,
-            "report fragmentation for old pointer and data pages")
+DEFINE_BOOL(trace_fragmentation, false, "report fragmentation for old space")
+DEFINE_BOOL(trace_fragmentation_verbose, false,
+            "report fragmentation for old space (detailed)")
 DEFINE_BOOL(collect_maps, true,
             "garbage collect maps from which no objects can be reached")
 DEFINE_BOOL(weak_embedded_maps_in_optimized_code, true,
@@ -614,8 +614,13 @@ DEFINE_BOOL(age_code, true,
             "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(overapproximate_weak_closure, false,
+DEFINE_BOOL(overapproximate_weak_closure, true,
             "overapproximate weak closer to reduce atomic pause time")
+DEFINE_INT(min_progress_during_object_groups_marking, 128,
+           "keep overapproximating the weak closure as long as we discover at "
+           "least this many unmarked objects")
+DEFINE_INT(max_object_groups_marking_rounds, 3,
+           "at most try this many times to over approximate the weak closure")
 DEFINE_BOOL(concurrent_sweeping, true, "use concurrent sweeping")
 DEFINE_BOOL(trace_incremental_marking, false,
             "trace progress of the incremental marking")
@@ -753,6 +758,19 @@ DEFINE_NEG_IMPLICATION(predictable, concurrent_recompilation)
 DEFINE_NEG_IMPLICATION(predictable, concurrent_osr)
 DEFINE_NEG_IMPLICATION(predictable, concurrent_sweeping)
 
+// mark-compact.cc
+DEFINE_BOOL(force_marking_deque_overflows, false,
+            "force overflows of marking deque by reducing it's size "
+            "to 64 words")
+
+DEFINE_BOOL(stress_compaction, false,
+            "stress the GC compactor to flush out bugs (implies "
+            "--force_marking_deque_overflows)")
+
+DEFINE_BOOL(manual_evacuation_candidates_selection, false,
+            "Test mode only flag. It allows an unit test to select evacuation "
+            "candidates pages (requires --stress_compaction).")
+
 
 //
 // Dev shell flags
@@ -770,21 +788,24 @@ DEFINE_ARGS(js_arguments,
 //
 // GDB JIT integration flags.
 //
+#undef FLAG
+#ifdef ENABLE_GDB_JIT_INTERFACE
+#define FLAG FLAG_FULL
+#else
+#define FLAG FLAG_READONLY
+#endif
 
-DEFINE_BOOL(gdbjit, false, "enable GDBJIT interface (disables compacting GC)")
+DEFINE_BOOL(gdbjit, false, "enable GDBJIT interface")
 DEFINE_BOOL(gdbjit_full, false, "enable GDBJIT interface for all code objects")
 DEFINE_BOOL(gdbjit_dump, false, "dump elf objects with debug info to disk")
 DEFINE_STRING(gdbjit_dump_filter, "",
               "dump only objects containing this substring")
 
-// mark-compact.cc
-DEFINE_BOOL(force_marking_deque_overflows, false,
-            "force overflows of marking deque by reducing it's size "
-            "to 64 words")
-
-DEFINE_BOOL(stress_compaction, false,
-            "stress the GC compactor to flush out bugs (implies "
-            "--force_marking_deque_overflows)")
+#ifdef ENABLE_GDB_JIT_INTERFACE
+DEFINE_IMPLICATION(gdbjit_full, gdbjit)
+DEFINE_IMPLICATION(gdbjit_dump, gdbjit)
+#endif
+DEFINE_NEG_IMPLICATION(gdbjit, compact_code_space)
 
 //
 // Debug only flags
index d498c28..7386238 100644 (file)
@@ -543,15 +543,10 @@ void FlagList::PrintHelp() {
 }
 
 
-// static
-void FlagList::EnforceFlagImplications() {
-#define FLAG_MODE_DEFINE_IMPLICATIONS
-#include "src/flag-definitions.h"
-#undef FLAG_MODE_DEFINE_IMPLICATIONS
-}
+static uint32_t flag_hash = 0;
 
 
-uint32_t FlagList::Hash() {
+void ComputeFlagListHash() {
   std::ostringstream modified_args_as_string;
 #ifdef DEBUG
   modified_args_as_string << "debug";
@@ -564,7 +559,19 @@ uint32_t FlagList::Hash() {
     }
   }
   std::string args(modified_args_as_string.str());
-  return static_cast<uint32_t>(
+  flag_hash = static_cast<uint32_t>(
       base::hash_range(args.c_str(), args.c_str() + args.length()));
 }
+
+
+// static
+void FlagList::EnforceFlagImplications() {
+#define FLAG_MODE_DEFINE_IMPLICATIONS
+#include "src/flag-definitions.h"
+#undef FLAG_MODE_DEFINE_IMPLICATIONS
+  ComputeFlagListHash();
+}
+
+
+uint32_t FlagList::Hash() { return flag_hash; }
 } }  // namespace v8::internal
index 9ec5d30..545c172 100644 (file)
@@ -58,7 +58,8 @@ class FlagList {
   // Set flags as consequence of being implied by another flag.
   static void EnforceFlagImplications();
 
-  // Hash of current flags (to quickly determine flag changes).
+  // Hash of flags (to quickly determine mismatching flag expectations).
+  // This hash is calculated during V8::Initialize and cached.
   static uint32_t Hash();
 };
 
index 824c1a7..650d6f9 100644 (file)
@@ -44,63 +44,11 @@ inline StackHandler* StackHandler::next() const {
 }
 
 
-inline bool StackHandler::includes(Address address) const {
-  Address start = this->address();
-  Address end = start + StackHandlerConstants::kSize;
-  return start <= address && address <= end;
-}
-
-
-inline void StackHandler::Iterate(ObjectVisitor* v, Code* holder) const {
-  v->VisitPointer(context_address());
-  v->VisitPointer(code_address());
-}
-
-
 inline StackHandler* StackHandler::FromAddress(Address address) {
   return reinterpret_cast<StackHandler*>(address);
 }
 
 
-inline bool StackHandler::is_js_entry() const {
-  return kind() == JS_ENTRY;
-}
-
-
-inline bool StackHandler::is_catch() const {
-  return kind() == CATCH;
-}
-
-
-inline bool StackHandler::is_finally() const {
-  return kind() == FINALLY;
-}
-
-
-inline StackHandler::Kind StackHandler::kind() const {
-  const int offset = StackHandlerConstants::kStateIntOffset;
-  return KindField::decode(Memory::unsigned_at(address() + offset));
-}
-
-
-inline unsigned StackHandler::index() const {
-  const int offset = StackHandlerConstants::kStateIntOffset;
-  return IndexField::decode(Memory::unsigned_at(address() + offset));
-}
-
-
-inline Object** StackHandler::context_address() const {
-  const int offset = StackHandlerConstants::kContextOffset;
-  return reinterpret_cast<Object**>(address() + offset);
-}
-
-
-inline Object** StackHandler::code_address() const {
-  const int offset = StackHandlerConstants::kCodeOffset;
-  return reinterpret_cast<Object**>(address() + offset);
-}
-
-
 inline StackFrame::StackFrame(StackFrameIteratorBase* iterator)
     : iterator_(iterator), isolate_(iterator_->isolate()) {
 }
index b7fba65..f52b3ce 100644 (file)
@@ -380,12 +380,6 @@ Code* StackFrame::GetSafepointData(Isolate* isolate,
 }
 
 
-bool StackFrame::HasHandler() const {
-  StackHandlerIterator it(this, top_handler());
-  return !it.done();
-}
-
-
 #ifdef DEBUG
 static bool GcSafeCodeContains(HeapObject* object, Address addr);
 #endif
@@ -608,15 +602,6 @@ void StandardFrame::SetCallerFp(Address caller_fp) {
 }
 
 
-bool StandardFrame::IsExpressionInsideHandler(int n) const {
-  Address address = GetExpressionAddress(n);
-  for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
-    if (it.handler()->includes(address)) return true;
-  }
-  return false;
-}
-
-
 void StandardFrame::IterateCompiledFrame(ObjectVisitor* v) const {
   // Make sure that we're not doing "safe" stack frame iteration. We cannot
   // possibly find pointers in optimized frames in that state.
@@ -710,12 +695,6 @@ int StubFrame::GetNumberOfIncomingArguments() const {
 
 
 void OptimizedFrame::Iterate(ObjectVisitor* v) const {
-#ifdef DEBUG
-  // Make sure that optimized frames do not contain any stack handlers.
-  StackHandlerIterator it(this, top_handler());
-  DCHECK(it.done());
-#endif
-
   IterateCompiledFrame(v);
 }
 
@@ -782,6 +761,15 @@ void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
 }
 
 
+int JavaScriptFrame::LookupExceptionHandlerInTable(int* stack_slots) {
+  Code* code = LookupCode();
+  DCHECK(!code->is_optimized_code());
+  HandlerTable* table = HandlerTable::cast(code->handler_table());
+  int pc_offset = static_cast<int>(pc() - code->entry());
+  return table->LookupRange(pc_offset, stack_slots);
+}
+
+
 void JavaScriptFrame::PrintFunctionAndOffset(JSFunction* function, Code* code,
                                              Address pc, FILE* file,
                                              bool print_line_number) {
@@ -843,66 +831,19 @@ void JavaScriptFrame::PrintTop(Isolate* isolate, FILE* file, bool print_args,
 }
 
 
-void JavaScriptFrame::SaveOperandStack(FixedArray* store,
-                                       int* stack_handler_index) const {
+void JavaScriptFrame::SaveOperandStack(FixedArray* store) const {
   int operands_count = store->length();
   DCHECK_LE(operands_count, ComputeOperandsCount());
-
-  // Visit the stack in LIFO order, saving operands and stack handlers into the
-  // array.  The saved stack handlers store a link to the next stack handler,
-  // which will allow RestoreOperandStack to rewind the handlers.
-  StackHandlerIterator it(this, top_handler());
-  int i = operands_count - 1;
-  *stack_handler_index = -1;
-  for (; !it.done(); it.Advance()) {
-    StackHandler* handler = it.handler();
-    // Save operands pushed after the handler was pushed.
-    for (; GetOperandSlot(i) < handler->address(); i--) {
-      store->set(i, GetOperand(i));
-    }
-    DCHECK_GE(i + 1, StackHandlerConstants::kSlotCount);
-    DCHECK_EQ(handler->address(), GetOperandSlot(i));
-    int next_stack_handler_index = i + 1 - StackHandlerConstants::kSlotCount;
-    handler->Unwind(isolate(), store, next_stack_handler_index,
-                    *stack_handler_index);
-    *stack_handler_index = next_stack_handler_index;
-    i -= StackHandlerConstants::kSlotCount;
-  }
-
-  // Save any remaining operands.
-  for (; i >= 0; i--) {
+  for (int i = 0; i < operands_count; i++) {
     store->set(i, GetOperand(i));
   }
 }
 
 
-void JavaScriptFrame::RestoreOperandStack(FixedArray* store,
-                                          int stack_handler_index) {
+void JavaScriptFrame::RestoreOperandStack(FixedArray* store) {
   int operands_count = store->length();
   DCHECK_LE(operands_count, ComputeOperandsCount());
-  int i = 0;
-  while (i <= stack_handler_index) {
-    if (i < stack_handler_index) {
-      // An operand.
-      DCHECK_EQ(GetOperand(i), isolate()->heap()->the_hole_value());
-      Memory::Object_at(GetOperandSlot(i)) = store->get(i);
-      i++;
-    } else {
-      // A stack handler.
-      DCHECK_EQ(i, stack_handler_index);
-      // The FixedArray store grows up.  The stack grows down.  So the operand
-      // slot for i actually points to the bottom of the top word in the
-      // handler.  The base of the StackHandler* is the address of the bottom
-      // word, which will be the last slot that is in the handler.
-      int handler_slot_index = i + StackHandlerConstants::kSlotCount - 1;
-      StackHandler *handler =
-          StackHandler::FromAddress(GetOperandSlot(handler_slot_index));
-      stack_handler_index = handler->Rewind(isolate(), store, i, fp());
-      i += StackHandlerConstants::kSlotCount;
-    }
-  }
-
-  for (; i < operands_count; i++) {
+  for (int i = 0; i < operands_count; i++) {
     DCHECK_EQ(GetOperand(i), isolate()->heap()->the_hole_value());
     Memory::Object_at(GetOperandSlot(i)) = store->get(i);
   }
@@ -1035,6 +976,16 @@ void OptimizedFrame::Summarize(List<FrameSummary>* frames) {
 }
 
 
+int OptimizedFrame::LookupExceptionHandlerInTable(int* stack_slots) {
+  Code* code = LookupCode();
+  DCHECK(code->is_optimized_code());
+  HandlerTable* table = HandlerTable::cast(code->handler_table());
+  int pc_offset = static_cast<int>(pc() - code->entry());
+  *stack_slots = code->stack_slots();
+  return table->LookupReturn(pc_offset);
+}
+
+
 DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
     int* deopt_index) {
   DCHECK(is_optimized());
@@ -1286,7 +1237,6 @@ void JavaScriptFrame::Print(StringStream* accumulator,
     accumulator->Add("  // expression stack (top to bottom)\n");
   }
   for (int i = expressions_count - 1; i >= expressions_start; i--) {
-    if (IsExpressionInsideHandler(i)) continue;
     accumulator->Add("  [%02d] : %o\n", i, GetExpression(i));
   }
 
@@ -1335,17 +1285,6 @@ void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
 
 
 void EntryFrame::Iterate(ObjectVisitor* v) const {
-  StackHandlerIterator it(this, top_handler());
-  DCHECK(!it.done());
-  StackHandler* handler = it.handler();
-  DCHECK(handler->is_js_entry());
-  handler->Iterate(v, LookupCode());
-#ifdef DEBUG
-  // Make sure that the entry frame does not contain more than one
-  // stack handler.
-  it.Advance();
-  DCHECK(it.done());
-#endif
   IteratePc(v, pc_address(), LookupCode());
 }
 
@@ -1354,17 +1293,6 @@ void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
   const int offset = StandardFrameConstants::kLastObjectOffset;
   Object** base = &Memory::Object_at(sp());
   Object** limit = &Memory::Object_at(fp() + offset) + 1;
-  for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
-    StackHandler* handler = it.handler();
-    // Traverse pointers down to - but not including - the next
-    // handler in the handler chain. Update the base to skip the
-    // handler and allow the handler to traverse its own pointers.
-    const Address address = handler->address();
-    v->VisitPointers(base, reinterpret_cast<Object**>(address));
-    base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
-    // Traverse the pointers in the handler itself.
-    handler->Iterate(v, LookupCode());
-  }
   v->VisitPointers(base, limit);
 }
 
@@ -1530,59 +1458,6 @@ InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
 // -------------------------------------------------------------------------
 
 
-void StackHandler::Unwind(Isolate* isolate,
-                          FixedArray* array,
-                          int offset,
-                          int previous_handler_offset) const {
-  STATIC_ASSERT(StackHandlerConstants::kSlotCount >= 5);
-  DCHECK_LE(0, offset);
-  DCHECK_GE(array->length(), offset + StackHandlerConstants::kSlotCount);
-  // Unwinding a stack handler into an array chains it in the opposite
-  // direction, re-using the "next" slot as a "previous" link, so that stack
-  // handlers can be later re-wound in the correct order.  Decode the "state"
-  // slot into "index" and "kind" and store them separately, using the fp slot.
-  array->set(offset, Smi::FromInt(previous_handler_offset));        // next
-  array->set(offset + 1, *code_address());                          // code
-  array->set(offset + 2, Smi::FromInt(static_cast<int>(index())));  // state
-  array->set(offset + 3, *context_address());                       // context
-  array->set(offset + 4, Smi::FromInt(static_cast<int>(kind())));   // fp
-
-  *isolate->handler_address() = next()->address();
-}
-
-
-int StackHandler::Rewind(Isolate* isolate,
-                         FixedArray* array,
-                         int offset,
-                         Address fp) {
-  STATIC_ASSERT(StackHandlerConstants::kSlotCount >= 5);
-  DCHECK_LE(0, offset);
-  DCHECK_GE(array->length(), offset + StackHandlerConstants::kSlotCount);
-  Smi* prev_handler_offset = Smi::cast(array->get(offset));
-  Code* code = Code::cast(array->get(offset + 1));
-  Smi* smi_index = Smi::cast(array->get(offset + 2));
-  Object* context = array->get(offset + 3);
-  Smi* smi_kind = Smi::cast(array->get(offset + 4));
-
-  unsigned state = KindField::encode(static_cast<Kind>(smi_kind->value())) |
-      IndexField::encode(static_cast<unsigned>(smi_index->value()));
-
-  Memory::Address_at(address() + StackHandlerConstants::kNextOffset) =
-      *isolate->handler_address();
-  Memory::Object_at(address() + StackHandlerConstants::kCodeOffset) = code;
-  Memory::uintptr_at(address() + StackHandlerConstants::kStateOffset) = state;
-  Memory::Object_at(address() + StackHandlerConstants::kContextOffset) =
-      context;
-  SetFp(address() + StackHandlerConstants::kFPOffset, fp);
-
-  *isolate->handler_address() = address();
-
-  return prev_handler_offset->value();
-}
-
-
-// -------------------------------------------------------------------------
-
 int NumRegs(RegList reglist) { return base::bits::CountPopulation32(reglist); }
 
 
index 03d53dd..397c7b5 100644 (file)
@@ -66,74 +66,34 @@ class InnerPointerToCodeCache {
 };
 
 
+// Every try-block pushes the context register.
+class TryBlockConstant : public AllStatic {
+ public:
+  static const int kElementCount = 1;
+};
+
+
 class StackHandlerConstants : public AllStatic {
  public:
-  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;
+  static const int kNextOffset = 0 * kPointerSize;
 
-  static const int kSize = kFPOffset + kFPOnStackSize;
+  static const int kSize = kNextOffset + kPointerSize;
   static const int kSlotCount = kSize >> kPointerSizeLog2;
 };
 
 
 class StackHandler BASE_EMBEDDED {
  public:
-  enum Kind {
-    JS_ENTRY,
-    CATCH,
-    FINALLY,
-    LAST_KIND = FINALLY
-  };
-
-  static const int kKindWidth = 2;
-  STATIC_ASSERT(LAST_KIND < (1 << kKindWidth));
-  static const int kIndexWidth = 32 - kKindWidth;
-  class KindField: public BitField<StackHandler::Kind, 0, kKindWidth> {};
-  class IndexField: public BitField<unsigned, kKindWidth, kIndexWidth> {};
-
   // Get the address of this stack handler.
   inline Address address() const;
 
   // Get the next stack handler in the chain.
   inline StackHandler* next() const;
 
-  // Tells whether the given address is inside this handler.
-  inline bool includes(Address address) const;
-
-  // Garbage collection support.
-  inline void Iterate(ObjectVisitor* v, Code* holder) const;
-
   // Conversion support.
   static inline StackHandler* FromAddress(Address address);
 
-  // Testers
-  inline bool is_js_entry() const;
-  inline bool is_catch() const;
-  inline bool is_finally() const;
-
-  // Generator support to preserve stack handlers.
-  void Unwind(Isolate* isolate, FixedArray* array, int offset,
-              int previous_handler_offset) const;
-  int Rewind(Isolate* isolate, FixedArray* array, int offset, Address fp);
-
  private:
-  // Accessors.
-  inline Kind kind() const;
-  inline unsigned index() const;
-
-  inline Object** constant_pool_address() const;
-  inline Object** context_address() const;
-  inline Object** code_address() const;
-  inline void SetFp(Address slot, Address fp);
-
   DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler);
 };
 
@@ -273,8 +233,8 @@ class StackFrame BASE_EMBEDDED {
   // Get the id of this stack frame.
   Id id() const { return static_cast<Id>(OffsetFrom(caller_sp())); }
 
-  // Checks if this frame includes any stack handlers.
-  bool HasHandler() const;
+  // Get the top handler from the current stack iterator.
+  inline StackHandler* top_handler() const;
 
   // Get the type of this frame.
   virtual Type type() const = 0;
@@ -309,7 +269,6 @@ class StackFrame BASE_EMBEDDED {
   // Resolves pc_address through the resolution address function if one is set.
   static inline Address* ResolveReturnAddressLocation(Address* pc_address);
 
-
   // Printing support.
   enum PrintMode { OVERVIEW, DETAILS };
   virtual void Print(StringStream* accumulator,
@@ -330,9 +289,6 @@ class StackFrame BASE_EMBEDDED {
                          PrintMode mode,
                          int index);
 
-  // Get the top handler from the current stack iterator.
-  inline StackHandler* top_handler() const;
-
   // Compute the stack frame type for the given state.
   static Type ComputeType(const StackFrameIteratorBase* iterator, State* state);
 
@@ -501,10 +457,6 @@ class StandardFrame: public StackFrame {
   Address GetExpressionAddress(int n) const;
   static Address GetExpressionAddress(Address fp, int n);
 
-  // Determines if the n'th expression stack element is in a stack
-  // handler or not. Requires traversing all handlers in this frame.
-  bool IsExpressionInsideHandler(int n) const;
-
   // Determines if the standard frame for the given frame pointer is
   // an arguments adaptor frame.
   static inline bool IsArgumentsAdaptorFrame(Address fp);
@@ -573,9 +525,9 @@ class JavaScriptFrame: public StandardFrame {
   inline Object* GetOperand(int index) const;
   inline int ComputeOperandsCount() const;
 
-  // Generator support to preserve operand stack and stack handlers.
-  void SaveOperandStack(FixedArray* store, int* stack_handler_index) const;
-  void RestoreOperandStack(FixedArray* store, int stack_handler_index);
+  // Generator support to preserve operand stack.
+  void SaveOperandStack(FixedArray* store) const;
+  void RestoreOperandStack(FixedArray* store);
 
   // Debugger access.
   void SetParameterValue(int index, Object* value) const;
@@ -609,6 +561,10 @@ class JavaScriptFrame: public StandardFrame {
   // Build a list with summaries for this frame including all inlined frames.
   virtual void Summarize(List<FrameSummary>* frames);
 
+  // Lookup exception handler for current {pc}, returns -1 if none found. Also
+  // returns the expected number of stack slots at the handler site.
+  virtual int LookupExceptionHandlerInTable(int* stack_slots);
+
   // Architecture-specific register description.
   static Register fp_register();
   static Register context_register();
@@ -681,6 +637,10 @@ class OptimizedFrame : public JavaScriptFrame {
 
   virtual void Summarize(List<FrameSummary>* frames);
 
+  // Lookup exception handler for current {pc}, returns -1 if none found. Also
+  // returns the expected number of stack slots at the handler site.
+  virtual int LookupExceptionHandlerInTable(int* stack_slots);
+
   DeoptimizationInputData* GetDeoptimizationData(int* deopt_index);
 
  protected:
index b0bf3b8..327230e 100644 (file)
@@ -16,7 +16,7 @@
 #include "src/prettyprinter.h"
 #include "src/scopeinfo.h"
 #include "src/scopes.h"
-#include "src/snapshot.h"
+#include "src/snapshot/snapshot.h"
 
 namespace v8 {
 namespace internal {
@@ -443,9 +443,8 @@ void FullCodeGenerator::Initialize() {
   // calculating PC offsets after generating a debug version of code.  Therefore
   // we disable the production of debug code in the full compiler if we are
   // either generating a snapshot or we booted from a snapshot.
-  generate_debug_code_ = FLAG_debug_code &&
-                         !masm_->serializer_enabled() &&
-                         !Snapshot::HaveASnapshotToStartFrom();
+  generate_debug_code_ = FLAG_debug_code && !masm_->serializer_enabled() &&
+                         !info_->isolate()->snapshot_available();
   masm_->set_emit_debug_code(generate_debug_code_);
   masm_->set_predictable_code_size(true);
 }
@@ -463,6 +462,17 @@ void FullCodeGenerator::CallLoadIC(ContextualMode contextual_mode,
 }
 
 
+void FullCodeGenerator::CallGlobalLoadIC(Handle<String> name) {
+  if (masm()->serializer_enabled() || FLAG_vector_ics) {
+    // Vector-ICs don't work with LoadGlobalIC.
+    return CallLoadIC(CONTEXTUAL);
+  }
+  Handle<Code> ic = CodeFactory::LoadGlobalIC(
+                        isolate(), isolate()->global_object(), name).code();
+  CallIC(ic, TypeFeedbackId::None());
+}
+
+
 void FullCodeGenerator::CallStoreIC(TypeFeedbackId id) {
   Handle<Code> ic = CodeFactory::StoreIC(isolate(), language_mode()).code();
   CallIC(ic, id);
@@ -860,22 +870,6 @@ void FullCodeGenerator::VisitSuperReference(SuperReference* super) {
 }
 
 
-bool FullCodeGenerator::ValidateSuperCall(Call* expr) {
-  Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
-  if (new_target_var == nullptr) {
-    // TODO(dslomov): this is not exactly correct, the spec requires us
-    // to execute the constructor and only fail when an assigment to 'this'
-    // is attempted. Will implement once we have general new.target support,
-    // but also filed spec bug 3843 to make it an early error.
-    __ CallRuntime(Runtime::kThrowUnsupportedSuperError, 0);
-    RecordJSReturnSite(expr);
-    context()->Plug(result_register());
-    return false;
-  }
-  return true;
-}
-
-
 void FullCodeGenerator::SetExpressionPosition(Expression* expr) {
   if (!info_->is_debug()) {
     CodeGenerator::RecordPositions(masm_, expr->position());
@@ -909,39 +903,6 @@ void FullCodeGenerator::SetSourcePosition(int pos) {
 }
 
 
-// Lookup table for code generators for  special runtime calls which are
-// generated inline.
-#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize)          \
-    &FullCodeGenerator::Emit##Name,
-
-const FullCodeGenerator::InlineFunctionGenerator
-  FullCodeGenerator::kInlineFunctionGenerators[] = {
-    INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
-  };
-#undef INLINE_FUNCTION_GENERATOR_ADDRESS
-
-
-FullCodeGenerator::InlineFunctionGenerator
-  FullCodeGenerator::FindInlineFunctionGenerator(Runtime::FunctionId id) {
-    int lookup_index =
-        static_cast<int>(id) - static_cast<int>(Runtime::kFirstInlineFunction);
-    DCHECK(lookup_index >= 0);
-    DCHECK(static_cast<size_t>(lookup_index) <
-           arraysize(kInlineFunctionGenerators));
-    return kInlineFunctionGenerators[lookup_index];
-}
-
-
-void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
-  const Runtime::Function* function = expr->function();
-  DCHECK(function != NULL);
-  DCHECK(function->intrinsic_type == Runtime::INLINE);
-  InlineFunctionGenerator generator =
-      FindInlineFunctionGenerator(function->function_id);
-  ((*this).*(generator))(expr);
-}
-
-
 void FullCodeGenerator::EmitGeneratorNext(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   DCHECK(args->length() == 2);
@@ -1440,7 +1401,6 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
   Label try_entry, handler_entry, exit;
   __ jmp(&try_entry);
   __ bind(&handler_entry);
-  handler_table()->set(stmt->index(), Smi::FromInt(handler_entry.pos()));
   // Exception handler code, the exception is in the result register.
   // Extend the context before executing the catch block.
   { Comment cmnt(masm_, "[ Extend catch context");
@@ -1466,11 +1426,11 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
 
   // Try block code. Sets up the exception handler chain.
   __ bind(&try_entry);
-  __ PushTryHandler(StackHandler::CATCH, stmt->index());
+  EnterTryBlock(stmt->index(), &handler_entry);
   { TryCatch try_body(this);
     Visit(stmt->try_block());
   }
-  __ PopTryHandler();
+  ExitTryBlock(stmt->index());
   __ bind(&exit);
 }
 
@@ -1504,7 +1464,6 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
   // Jump to try-handler setup and try-block code.
   __ jmp(&try_entry);
   __ bind(&handler_entry);
-  handler_table()->set(stmt->index(), Smi::FromInt(handler_entry.pos()));
   // Exception handler code.  This code is only executed when an exception
   // is thrown.  The exception is in the result register, and must be
   // preserved by the finally block.  Call the finally block and then
@@ -1523,11 +1482,11 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
 
   // Set up try handler.
   __ bind(&try_entry);
-  __ PushTryHandler(StackHandler::FINALLY, stmt->index());
+  EnterTryBlock(stmt->index(), &handler_entry);
   { TryFinally try_body(this, &finally_entry);
     Visit(stmt->try_block());
   }
-  __ PopTryHandler();
+  ExitTryBlock(stmt->index());
   // Execute the finally block on the way out.  Clobber the unpredictable
   // value in the result register with one that's safe for GC because the
   // finally block will unconditionally preserve the result register on the
@@ -1682,13 +1641,54 @@ void FullCodeGenerator::VisitThrow(Throw* expr) {
 }
 
 
-FullCodeGenerator::NestedStatement* FullCodeGenerator::TryCatch::Exit(
-    int* stack_depth,
-    int* context_length) {
+void FullCodeGenerator::EnterTryBlock(int index, Label* handler) {
+  handler_table()->SetRangeStart(index, masm()->pc_offset());
+  handler_table()->SetRangeHandler(index, handler->pos());
+
+  // Determine expression stack depth of try statement.
+  int stack_depth = info_->scope()->num_stack_slots();  // Include stack locals.
+  for (NestedStatement* current = nesting_stack_; current != NULL; /*nop*/) {
+    current = current->AccumulateDepth(&stack_depth);
+  }
+  handler_table()->SetRangeDepth(index, stack_depth);
+
+  // Push context onto operand stack.
+  STATIC_ASSERT(TryBlockConstant::kElementCount == 1);
+  __ Push(context_register());
+}
+
+
+void FullCodeGenerator::ExitTryBlock(int index) {
+  handler_table()->SetRangeEnd(index, masm()->pc_offset());
+
+  // Drop context from operand stack.
+  __ Drop(TryBlockConstant::kElementCount);
+}
+
+
+FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
+    int* stack_depth, int* context_length) {
   // The macros used here must preserve the result register.
-  __ Drop(*stack_depth);
-  __ PopTryHandler();
+
+  // 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.
+  if (*context_length > 0) {
+    __ Drop(*stack_depth);  // Down to the handler block.
+    // Restore the context to its dedicated register and the stack.
+    STATIC_ASSERT(TryFinally::kElementCount == 1);
+    __ Pop(codegen_->context_register());
+    codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset,
+                                codegen_->context_register());
+  } else {
+    // Down to the handler block and also drop context.
+    __ Drop(*stack_depth + kElementCount);
+  }
+  __ Call(finally_entry_);
+
   *stack_depth = 0;
+  *context_length = 0;
   return previous_;
 }
 
index 6e0ac62..19608a4 100644 (file)
@@ -156,6 +156,11 @@ class FullCodeGenerator: public AstVisitor {
       return previous_;
     }
 
+    // Like the Exit() method above, but limited to accumulating stack depth.
+    virtual NestedStatement* AccumulateDepth(int* stack_depth) {
+      return previous_;
+    }
+
    protected:
     MacroAssembler* masm() { return codegen_->masm(); }
 
@@ -225,22 +230,36 @@ class FullCodeGenerator: public AstVisitor {
   // The try block of a try/catch statement.
   class TryCatch : public NestedStatement {
    public:
-    explicit TryCatch(FullCodeGenerator* codegen) : NestedStatement(codegen) {
-    }
+    static const int kElementCount = TryBlockConstant::kElementCount;
+
+    explicit TryCatch(FullCodeGenerator* codegen) : NestedStatement(codegen) {}
     virtual ~TryCatch() {}
 
-    virtual NestedStatement* Exit(int* stack_depth, int* context_length);
+    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
+      *stack_depth += kElementCount;
+      return previous_;
+    }
+    virtual NestedStatement* AccumulateDepth(int* stack_depth) {
+      *stack_depth += kElementCount;
+      return previous_;
+    }
   };
 
   // The try block of a try/finally statement.
   class TryFinally : public NestedStatement {
    public:
+    static const int kElementCount = TryBlockConstant::kElementCount;
+
     TryFinally(FullCodeGenerator* codegen, Label* finally_entry)
         : NestedStatement(codegen), finally_entry_(finally_entry) {
     }
     virtual ~TryFinally() {}
 
     virtual NestedStatement* Exit(int* stack_depth, int* context_length);
+    virtual NestedStatement* AccumulateDepth(int* stack_depth) {
+      *stack_depth += kElementCount;
+      return previous_;
+    }
 
    private:
     Label* finally_entry_;
@@ -249,15 +268,19 @@ class FullCodeGenerator: public AstVisitor {
   // The finally block of a try/finally statement.
   class Finally : public NestedStatement {
    public:
-    static const int kElementCount = 5;
+    static const int kElementCount = 3;
 
-    explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { }
+    explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) {}
     virtual ~Finally() {}
 
     virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
       *stack_depth += kElementCount;
       return previous_;
     }
+    virtual NestedStatement* AccumulateDepth(int* stack_depth) {
+      *stack_depth += kElementCount;
+      return previous_;
+    }
   };
 
   // The body of a for/in loop.
@@ -274,6 +297,10 @@ class FullCodeGenerator: public AstVisitor {
       *stack_depth += kElementCount;
       return previous_;
     }
+    virtual NestedStatement* AccumulateDepth(int* stack_depth) {
+      *stack_depth += kElementCount;
+      return previous_;
+    }
   };
 
 
@@ -291,11 +318,6 @@ class FullCodeGenerator: public AstVisitor {
     }
   };
 
-  // Type of a member function that generates inline code for a native function.
-  typedef void (FullCodeGenerator::*InlineFunctionGenerator)(CallRuntime* expr);
-
-  static const InlineFunctionGenerator kInlineFunctionGenerators[];
-
   // A platform-specific utility to overwrite the accumulator register
   // with a GC-safe value.
   void ClearAccumulator();
@@ -495,15 +517,52 @@ class FullCodeGenerator: public AstVisitor {
   void EmitKeyedCallWithLoadIC(Call* expr, Expression* key);
   void EmitKeyedSuperCallWithLoadIC(Call* expr);
 
-  // Platform-specific code for inline runtime calls.
-  InlineFunctionGenerator FindInlineFunctionGenerator(Runtime::FunctionId id);
-
-  void EmitInlineRuntimeCall(CallRuntime* expr);
-
-#define EMIT_INLINE_RUNTIME_CALL(name, x, y) \
-  void Emit##name(CallRuntime* expr);
-  INLINE_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
-#undef EMIT_INLINE_RUNTIME_CALL
+#define FOR_EACH_FULL_CODE_INTRINSIC(F)   \
+  F(IsSmi)                                \
+  F(IsNonNegativeSmi)                     \
+  F(IsArray)                              \
+  F(IsRegExp)                             \
+  F(IsJSProxy)                            \
+  F(IsConstructCall)                      \
+  F(CallFunction)                         \
+  F(DefaultConstructorCallSuper)          \
+  F(ArgumentsLength)                      \
+  F(Arguments)                            \
+  F(ValueOf)                              \
+  F(SetValueOf)                           \
+  F(DateField)                            \
+  F(StringCharFromCode)                   \
+  F(StringCharAt)                         \
+  F(OneByteSeqStringSetChar)              \
+  F(TwoByteSeqStringSetChar)              \
+  F(ObjectEquals)                         \
+  F(IsObject)                             \
+  F(IsFunction)                           \
+  F(IsUndetectableObject)                 \
+  F(IsSpecObject)                         \
+  F(IsStringWrapperSafeForDefaultValueOf) \
+  F(MathPow)                              \
+  F(IsMinusZero)                          \
+  F(HasCachedArrayIndex)                  \
+  F(GetCachedArrayIndex)                  \
+  F(FastOneByteArrayJoin)                 \
+  F(GeneratorNext)                        \
+  F(GeneratorThrow)                       \
+  F(DebugBreakInOptimizedCode)            \
+  F(ClassOf)                              \
+  F(StringCharCodeAt)                     \
+  F(StringAdd)                            \
+  F(SubString)                            \
+  F(StringCompare)                        \
+  F(RegExpExec)                           \
+  F(RegExpConstructResult)                \
+  F(GetFromCache)                         \
+  F(NumberToString)                       \
+  F(DebugIsActive)
+
+#define GENERATOR_DECLARATION(Name) void Emit##Name(CallRuntime* call);
+  FOR_EACH_FULL_CODE_INTRINSIC(GENERATOR_DECLARATION)
+#undef GENERATOR_DECLARATION
 
   // Platform-specific code for resuming generators.
   void EmitGeneratorResume(Expression *generator,
@@ -589,19 +648,6 @@ class FullCodeGenerator: public AstVisitor {
   // 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,
-                                            LanguageMode language_mode) {
-    if (var->mode() == CONST) return op != Token::INIT_CONST;
-
-    if (var->mode() == CONST_LEGACY) {
-      return is_strict(language_mode) && 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,
@@ -640,13 +686,13 @@ class FullCodeGenerator: public AstVisitor {
   void EmitSetHomeObjectIfNeeded(Expression* initializer, int offset);
 
   void EmitLoadSuperConstructor();
-  bool ValidateSuperCall(Call* expr);
 
   void CallIC(Handle<Code> code,
               TypeFeedbackId id = TypeFeedbackId::None());
 
   void CallLoadIC(ContextualMode mode,
                   TypeFeedbackId id = TypeFeedbackId::None());
+  void CallGlobalLoadIC(Handle<String> name);
   void CallStoreIC(TypeFeedbackId id = TypeFeedbackId::None());
 
   void SetFunctionPosition(FunctionLiteral* fun);
@@ -656,6 +702,8 @@ class FullCodeGenerator: public AstVisitor {
   void SetSourcePosition(int pos);
 
   // Non-local control flow support.
+  void EnterTryBlock(int handler_index, Label* handler);
+  void ExitTryBlock(int handler_index);
   void EnterFinallyBlock();
   void ExitFinallyBlock();
 
@@ -711,10 +759,7 @@ class FullCodeGenerator: public AstVisitor {
   void PopulateDeoptimizationData(Handle<Code> code);
   void PopulateTypeFeedbackInfo(Handle<Code> code);
 
-  bool MustCreateObjectLiteralWithRuntime(ObjectLiteral* expr) const;
-  bool MustCreateArrayLiteralWithRuntime(ArrayLiteral* expr) const;
-
-  Handle<FixedArray> handler_table() { return handler_table_; }
+  Handle<HandlerTable> handler_table() { return handler_table_; }
 
   struct BailoutEntry {
     BailoutId id;
@@ -932,7 +977,7 @@ class FullCodeGenerator: public AstVisitor {
   ZoneList<BailoutEntry> bailout_entries_;
   ZoneList<BackEdgeEntry> back_edges_;
   int ic_total_count_;
-  Handle<FixedArray> handler_table_;
+  Handle<HandlerTable> handler_table_;
   Handle<Cell> profiling_counter_;
   bool generate_debug_code_;
 
index 69b48d6..044f6fe 100644 (file)
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef ENABLE_GDB_JIT_INTERFACE
 #include "src/v8.h"
 
 #include "src/base/bits.h"
 #include "src/gdb-jit.h"
 #include "src/global-handles.h"
 #include "src/messages.h"
-#include "src/natives.h"
+#include "src/objects.h"
 #include "src/ostreams.h"
-#include "src/scopes.h"
+#include "src/snapshot/natives.h"
 
 namespace v8 {
 namespace internal {
+namespace GDBJITInterface {
+
+#ifdef ENABLE_GDB_JIT_INTERFACE
 
 #ifdef __APPLE__
 #define __MACH_O
@@ -933,15 +935,9 @@ class CodeDescription BASE_EMBEDDED {
   };
 #endif
 
-  CodeDescription(const char* name, Code* code, Handle<Script> script,
-                  LineInfo* lineinfo, GDBJITInterface::CodeTag tag,
-                  CompilationInfo* info)
-      : name_(name),
-        code_(code),
-        script_(script),
-        lineinfo_(lineinfo),
-        tag_(tag),
-        info_(info) {}
+  CodeDescription(const char* name, Code* code, SharedFunctionInfo* shared,
+                  LineInfo* lineinfo)
+      : name_(name), code_(code), shared_info_(shared), lineinfo_(lineinfo) {}
 
   const char* name() const {
     return name_;
@@ -949,16 +945,16 @@ class CodeDescription BASE_EMBEDDED {
 
   LineInfo* lineinfo() const { return lineinfo_; }
 
-  GDBJITInterface::CodeTag tag() const {
-    return tag_;
+  bool is_function() const {
+    Code::Kind kind = code_->kind();
+    return kind == Code::FUNCTION || kind == Code::OPTIMIZED_FUNCTION;
   }
 
-  CompilationInfo* info() const {
-    return info_;
-  }
+  bool has_scope_info() const { return shared_info_ != NULL; }
 
-  bool IsInfoAvailable() const {
-    return info_ != NULL;
+  ScopeInfo* scope_info() const {
+    DCHECK(has_scope_info());
+    return shared_info_->scope_info();
   }
 
   uintptr_t CodeStart() const {
@@ -973,12 +969,16 @@ class CodeDescription BASE_EMBEDDED {
     return CodeEnd() - CodeStart();
   }
 
+  bool has_script() {
+    return shared_info_ != NULL && shared_info_->script()->IsScript();
+  }
+
+  Script* script() { return Script::cast(shared_info_->script()); }
+
   bool IsLineInfoAvailable() {
-    return !script_.is_null() &&
-        script_->source()->IsString() &&
-        script_->HasValidSource() &&
-        script_->name()->IsString() &&
-        lineinfo_ != NULL;
+    return has_script() && script()->source()->IsString() &&
+           script()->HasValidSource() && script()->name()->IsString() &&
+           lineinfo_ != NULL;
   }
 
 #if V8_TARGET_ARCH_X64
@@ -994,21 +994,17 @@ class CodeDescription BASE_EMBEDDED {
 #endif
 
   SmartArrayPointer<char> GetFilename() {
-    return String::cast(script_->name())->ToCString();
+    return String::cast(script()->name())->ToCString();
   }
 
-  int GetScriptLineNumber(int pos) {
-    return script_->GetLineNumber(pos) + 1;
-  }
+  int GetScriptLineNumber(int pos) { return script()->GetLineNumber(pos) + 1; }
 
 
  private:
   const char* name_;
   Code* code_;
-  Handle<Script> script_;
+  SharedFunctionInfo* shared_info_;
   LineInfo* lineinfo_;
-  GDBJITInterface::CodeTag tag_;
-  CompilationInfo* info_;
 #if V8_TARGET_ARCH_X64
   uintptr_t stack_state_start_addresses_[STACK_STATE_MAX];
 #endif
@@ -1095,8 +1091,8 @@ class DebugInfoSection : public DebugSection {
     w->Write<uint8_t>(kPointerSize);
     w->WriteString("v8value");
 
-    if (desc_->IsInfoAvailable()) {
-      Scope* scope = desc_->info()->scope();
+    if (desc_->has_scope_info()) {
+      ScopeInfo* scope = desc_->scope_info();
       w->WriteULEB128(2);
       w->WriteString(desc_->name());
       w->Write<intptr_t>(desc_->CodeStart());
@@ -1118,8 +1114,8 @@ class DebugInfoSection : public DebugSection {
 #endif
       fb_block_size.set(static_cast<uint32_t>(w->position() - fb_block_start));
 
-      int params = scope->num_parameters();
-      int slots = scope->num_stack_slots();
+      int params = scope->ParameterCount();
+      int slots = scope->StackLocalCount();
       int context_slots = scope->ContextLocalCount();
       // The real slot ID is internal_slots + context_slot_id.
       int internal_slots = Context::MIN_CONTEXT_SLOTS;
@@ -1129,7 +1125,7 @@ class DebugInfoSection : public DebugSection {
       for (int param = 0; param < params; ++param) {
         w->WriteULEB128(current_abbreviation++);
         w->WriteString(
-            scope->parameter(param)->name()->ToCString(DISALLOW_NULLS).get());
+            scope->ParameterName(param)->ToCString(DISALLOW_NULLS).get());
         w->Write<uint32_t>(ty_offset);
         Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>();
         uintptr_t block_start = w->position();
@@ -1174,13 +1170,10 @@ class DebugInfoSection : public DebugSection {
         w->WriteString(builder.Finalize());
       }
 
-      ZoneList<Variable*> stack_locals(locals, scope->zone());
-      ZoneList<Variable*> context_locals(context_slots, scope->zone());
-      scope->CollectStackAndContextLocals(&stack_locals, &context_locals);
       for (int local = 0; local < locals; ++local) {
         w->WriteULEB128(current_abbreviation++);
         w->WriteString(
-            stack_locals[local]->name()->ToCString(DISALLOW_NULLS).get());
+            scope->StackLocalName(local)->ToCString(DISALLOW_NULLS).get());
         w->Write<uint32_t>(ty_offset);
         Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>();
         uintptr_t block_start = w->position();
@@ -1302,7 +1295,7 @@ class DebugAbbrevSection : public DebugSection {
 
   bool WriteBodyInternal(Writer* w) {
     int current_abbreviation = 1;
-    bool extra_info = desc_->IsInfoAvailable();
+    bool extra_info = desc_->has_scope_info();
     DCHECK(desc_->IsLineInfoAvailable());
     w->WriteULEB128(current_abbreviation++);
     w->WriteULEB128(DW_TAG_COMPILE_UNIT);
@@ -1319,9 +1312,9 @@ class DebugAbbrevSection : public DebugSection {
     w->WriteULEB128(0);
 
     if (extra_info) {
-      Scope* scope = desc_->info()->scope();
-      int params = scope->num_parameters();
-      int slots = scope->num_stack_slots();
+      ScopeInfo* scope = desc_->scope_info();
+      int params = scope->ParameterCount();
+      int slots = scope->StackLocalCount();
       int context_slots = scope->ContextLocalCount();
       // The real slot ID is internal_slots + context_slot_id.
       int internal_slots = Context::MIN_CONTEXT_SLOTS;
@@ -1868,27 +1861,7 @@ static void DestroyCodeEntry(JITCodeEntry* entry) {
 }
 
 
-static void RegisterCodeEntry(JITCodeEntry* entry,
-                              bool dump_if_enabled,
-                              const char* name_hint) {
-#if defined(DEBUG) && !V8_OS_WIN
-  static int file_num = 0;
-  if (FLAG_gdbjit_dump && dump_if_enabled) {
-    static const int kMaxFileNameSize = 64;
-    static const char* kElfFilePrefix = "/tmp/elfdump";
-    static const char* kObjFileExt = ".o";
-    char file_name[64];
-
-    SNPrintF(Vector<char>(file_name, kMaxFileNameSize),
-             "%s%s%d%s",
-             kElfFilePrefix,
-             (name_hint != NULL) ? name_hint : "",
-             file_num++,
-             kObjFileExt);
-    WriteBytes(file_name, entry->symfile_addr_, entry->symfile_size_);
-  }
-#endif
-
+static void RegisterCodeEntry(JITCodeEntry* entry) {
   entry->next_ = __jit_debug_descriptor.first_entry_;
   if (entry->next_ != NULL) entry->next_->prev_ = entry;
   __jit_debug_descriptor.first_entry_ =
@@ -1955,69 +1928,65 @@ static JITCodeEntry* CreateELFObject(CodeDescription* desc, Isolate* isolate) {
 }
 
 
-static bool SameCodeObjects(void* key1, void* key2) {
-  return key1 == key2;
-}
-
+struct AddressRange {
+  Address start;
+  Address end;
+};
 
-static HashMap* GetEntries() {
-  static HashMap* entries = NULL;
-  if (entries == NULL) {
-    entries = new HashMap(&SameCodeObjects);
+struct SplayTreeConfig {
+  typedef AddressRange Key;
+  typedef JITCodeEntry* Value;
+  static const AddressRange kNoKey;
+  static Value NoValue() { return NULL; }
+  static int Compare(const AddressRange& a, const AddressRange& b) {
+    // ptrdiff_t probably doesn't fit in an int.
+    if (a.start < b.start) return -1;
+    if (a.start == b.start) return 0;
+    return 1;
   }
-  return entries;
-}
+};
 
+const AddressRange SplayTreeConfig::kNoKey = {0, 0};
+typedef SplayTree<SplayTreeConfig> CodeMap;
 
-static uint32_t HashForCodeObject(Code* code) {
-  static const uintptr_t kGoldenRatio = 2654435761u;
-  uintptr_t hash = reinterpret_cast<uintptr_t>(code->address());
-  return static_cast<uint32_t>((hash >> kCodeAlignmentBits) * kGoldenRatio);
+static CodeMap* GetCodeMap() {
+  static CodeMap* code_map = NULL;
+  if (code_map == NULL) code_map = new CodeMap();
+  return code_map;
 }
 
 
-static const intptr_t kLineInfoTag = 0x1;
-
-
-static bool IsLineInfoTagged(void* ptr) {
-  return 0 != (reinterpret_cast<intptr_t>(ptr) & kLineInfoTag);
+static uint32_t HashCodeAddress(Address addr) {
+  static const uintptr_t kGoldenRatio = 2654435761u;
+  uintptr_t offset = OffsetFrom(addr);
+  return static_cast<uint32_t>((offset >> kCodeAlignmentBits) * kGoldenRatio);
 }
 
 
-static void* TagLineInfo(LineInfo* ptr) {
-  return reinterpret_cast<void*>(
-      reinterpret_cast<intptr_t>(ptr) | kLineInfoTag);
+static HashMap* GetLineMap() {
+  static HashMap* line_map = NULL;
+  if (line_map == NULL) line_map = new HashMap(&HashMap::PointersMatch);
+  return line_map;
 }
 
 
-static LineInfo* UntagLineInfo(void* ptr) {
-  return reinterpret_cast<LineInfo*>(reinterpret_cast<intptr_t>(ptr) &
-                                     ~kLineInfoTag);
+static void PutLineInfo(Address addr, LineInfo* info) {
+  HashMap* line_map = GetLineMap();
+  HashMap::Entry* e = line_map->Lookup(addr, HashCodeAddress(addr), true);
+  if (e->value != NULL) delete static_cast<LineInfo*>(e->value);
+  e->value = info;
 }
 
 
-void GDBJITInterface::AddCode(Handle<Name> name,
-                              Handle<Script> script,
-                              Handle<Code> code,
-                              CompilationInfo* info) {
-  if (!FLAG_gdbjit) return;
-
-  Script::InitLineEnds(script);
-
-  if (!name.is_null() && name->IsString()) {
-    SmartArrayPointer<char> name_cstring =
-        Handle<String>::cast(name)->ToCString(DISALLOW_NULLS);
-    AddCode(name_cstring.get(), *code, GDBJITInterface::FUNCTION, *script,
-            info);
-  } else {
-    AddCode("", *code, GDBJITInterface::FUNCTION, *script, info);
-  }
+static LineInfo* GetLineInfo(Address addr) {
+  void* value = GetLineMap()->Remove(addr, HashCodeAddress(addr));
+  return static_cast<LineInfo*>(value);
 }
 
 
 static void AddUnwindInfo(CodeDescription* desc) {
 #if V8_TARGET_ARCH_X64
-  if (desc->tag() == GDBJITInterface::FUNCTION) {
+  if (desc->is_function()) {
     // To avoid propagating unwinding information through
     // compilation pipeline we use an approximation.
     // For most use cases this should not affect usability.
@@ -2055,39 +2024,83 @@ static void AddUnwindInfo(CodeDescription* desc) {
 static base::LazyMutex mutex = LAZY_MUTEX_INITIALIZER;
 
 
-void GDBJITInterface::AddCode(const char* name,
-                              Code* code,
-                              GDBJITInterface::CodeTag tag,
-                              Script* script,
-                              CompilationInfo* info) {
-  base::LockGuard<base::Mutex> lock_guard(mutex.Pointer());
+// Remove entries from the splay tree that intersect the given address range,
+// and deregister them from GDB.
+static void RemoveJITCodeEntries(CodeMap* map, const AddressRange& range) {
+  DCHECK(range.start < range.end);
+  CodeMap::Locator cur;
+  if (map->FindGreatestLessThan(range, &cur) || map->FindLeast(&cur)) {
+    // Skip entries that are entirely less than the range of interest.
+    while (cur.key().end <= range.start) {
+      // CodeMap::FindLeastGreaterThan succeeds for entries whose key is greater
+      // than _or equal to_ the given key, so we have to advance our key to get
+      // the next one.
+      AddressRange new_key;
+      new_key.start = cur.key().end;
+      new_key.end = 0;
+      if (!map->FindLeastGreaterThan(new_key, &cur)) return;
+    }
+    // Evict intersecting ranges.
+    while (cur.key().start < range.end) {
+      AddressRange old_range = cur.key();
+      JITCodeEntry* old_entry = cur.value();
+
+      UnregisterCodeEntry(old_entry);
+      DestroyCodeEntry(old_entry);
+
+      CHECK(map->Remove(old_range));
+      if (!map->FindLeastGreaterThan(old_range, &cur)) return;
+    }
+  }
+}
+
+
+// Insert the entry into the splay tree and register it with GDB.
+static void AddJITCodeEntry(CodeMap* map, const AddressRange& range,
+                            JITCodeEntry* entry, bool dump_if_enabled,
+                            const char* name_hint) {
+#if defined(DEBUG) && !V8_OS_WIN
+  static int file_num = 0;
+  if (FLAG_gdbjit_dump && dump_if_enabled) {
+    static const int kMaxFileNameSize = 64;
+    char file_name[64];
+
+    SNPrintF(Vector<char>(file_name, kMaxFileNameSize), "/tmp/elfdump%s%d.o",
+             (name_hint != NULL) ? name_hint : "", file_num++);
+    WriteBytes(file_name, entry->symfile_addr_, entry->symfile_size_);
+  }
+#endif
+
+  CodeMap::Locator cur;
+  CHECK(map->Insert(range, &cur));
+  cur.set_value(entry);
+
+  RegisterCodeEntry(entry);
+}
+
+
+static void AddCode(const char* name, Code* code, SharedFunctionInfo* shared,
+                    LineInfo* lineinfo) {
   DisallowHeapAllocation no_gc;
 
-  HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true);
-  if (e->value != NULL && !IsLineInfoTagged(e->value)) return;
+  CodeMap* code_map = GetCodeMap();
+  AddressRange range;
+  range.start = code->address();
+  range.end = code->address() + code->CodeSize();
+  RemoveJITCodeEntries(code_map, range);
 
-  LineInfo* lineinfo = UntagLineInfo(e->value);
-  CodeDescription code_desc(name,
-                            code,
-                            script != NULL ? Handle<Script>(script)
-                                           : Handle<Script>(),
-                            lineinfo,
-                            tag,
-                            info);
+  CodeDescription code_desc(name, code, shared, lineinfo);
 
   if (!FLAG_gdbjit_full && !code_desc.IsLineInfoAvailable()) {
     delete lineinfo;
-    GetEntries()->Remove(code, HashForCodeObject(code));
     return;
   }
 
   AddUnwindInfo(&code_desc);
   Isolate* isolate = code->GetIsolate();
   JITCodeEntry* entry = CreateELFObject(&code_desc, isolate);
-  DCHECK(!IsLineInfoTagged(entry));
 
   delete lineinfo;
-  e->value = entry;
 
   const char* name_hint = NULL;
   bool should_dump = false;
@@ -2100,82 +2113,35 @@ void GDBJITInterface::AddCode(const char* name,
       should_dump = (name_hint != NULL);
     }
   }
-  RegisterCodeEntry(entry, should_dump, name_hint);
+  AddJITCodeEntry(code_map, range, entry, should_dump, name_hint);
 }
 
 
-void GDBJITInterface::RemoveCode(Code* code) {
+void EventHandler(const v8::JitCodeEvent* event) {
   if (!FLAG_gdbjit) return;
-
-  base::LockGuard<base::Mutex> lock_guard(mutex.Pointer());
-  HashMap::Entry* e = GetEntries()->Lookup(code,
-                                           HashForCodeObject(code),
-                                           false);
-  if (e == NULL) return;
-
-  if (IsLineInfoTagged(e->value)) {
-    delete UntagLineInfo(e->value);
-  } else {
-    JITCodeEntry* entry = static_cast<JITCodeEntry*>(e->value);
-    UnregisterCodeEntry(entry);
-    DestroyCodeEntry(entry);
-  }
-  e->value = NULL;
-  GetEntries()->Remove(code, HashForCodeObject(code));
-}
-
-
-void GDBJITInterface::RemoveCodeRange(Address start, Address end) {
-  HashMap* entries = GetEntries();
-  Zone zone;
-  ZoneList<Code*> dead_codes(1, &zone);
-
-  for (HashMap::Entry* e = entries->Start(); e != NULL; e = entries->Next(e)) {
-    Code* code = reinterpret_cast<Code*>(e->key);
-    if (code->address() >= start && code->address() < end) {
-      dead_codes.Add(code, &zone);
-    }
-  }
-
-  for (int i = 0; i < dead_codes.length(); i++) {
-    RemoveCode(dead_codes.at(i));
-  }
-}
-
-
-static void RegisterDetailedLineInfo(Code* code, LineInfo* line_info) {
   base::LockGuard<base::Mutex> lock_guard(mutex.Pointer());
-  DCHECK(!IsLineInfoTagged(line_info));
-  HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true);
-  DCHECK(e->value == NULL);
-  e->value = TagLineInfo(line_info);
-}
-
-
-void GDBJITInterface::EventHandler(const v8::JitCodeEvent* event) {
-  if (!FLAG_gdbjit) return;
   switch (event->type) {
     case v8::JitCodeEvent::CODE_ADDED: {
-      Code* code = Code::GetCodeFromTargetAddress(
-          reinterpret_cast<Address>(event->code_start));
-      if (code->kind() == Code::OPTIMIZED_FUNCTION ||
-          code->kind() == Code::FUNCTION) {
-        break;
-      }
+      Address addr = reinterpret_cast<Address>(event->code_start);
+      Code* code = Code::GetCodeFromTargetAddress(addr);
+      LineInfo* lineinfo = GetLineInfo(addr);
       EmbeddedVector<char, 256> buffer;
       StringBuilder builder(buffer.start(), buffer.length());
       builder.AddSubstring(event->name.str, static_cast<int>(event->name.len));
-      AddCode(builder.Finalize(), code, NON_FUNCTION, NULL, NULL);
+      // It's called UnboundScript in the API but it's a SharedFunctionInfo.
+      SharedFunctionInfo* shared =
+          event->script.IsEmpty() ? NULL : *Utils::OpenHandle(*event->script);
+      AddCode(builder.Finalize(), code, shared, lineinfo);
       break;
     }
     case v8::JitCodeEvent::CODE_MOVED:
+      // Enabling the GDB JIT interface should disable code compaction.
+      UNREACHABLE();
       break;
-    case v8::JitCodeEvent::CODE_REMOVED: {
-      Code* code = Code::GetCodeFromTargetAddress(
-          reinterpret_cast<Address>(event->code_start));
-      RemoveCode(code);
+    case v8::JitCodeEvent::CODE_REMOVED:
+      // Do nothing.  Instead, adding code causes eviction of any entry whose
+      // address range intersects the address range of the added code.
       break;
-    }
     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
       LineInfo* line_info = reinterpret_cast<LineInfo*>(event->user_data);
       line_info->SetPosition(static_cast<intptr_t>(event->line_info.offset),
@@ -2191,14 +2157,12 @@ void GDBJITInterface::EventHandler(const v8::JitCodeEvent* event) {
     }
     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
       LineInfo* line_info = reinterpret_cast<LineInfo*>(event->user_data);
-      Code* code = Code::GetCodeFromTargetAddress(
-          reinterpret_cast<Address>(event->code_start));
-      RegisterDetailedLineInfo(code, line_info);
+      PutLineInfo(reinterpret_cast<Address>(event->code_start), line_info);
       break;
     }
   }
 }
-
-
-} }  // namespace v8::internal
 #endif
+}  // namespace GDBJITInterface
+}  // namespace internal
+}  // namespace v8
index 14536cf..4538270 100644 (file)
@@ -5,50 +5,35 @@
 #ifndef V8_GDB_JIT_H_
 #define V8_GDB_JIT_H_
 
-#include "src/allocation.h"
+#include "src/v8.h"
 
 //
-// Basic implementation of GDB JIT Interface client.
-// GBD JIT Interface is supported in GDB 7.0 and above.
-// Currently on x64 and ia32 architectures and Linux OS are supported.
+// GDB has two ways of interacting with JIT code.  With the "JIT compilation
+// interface", V8 can tell GDB when it emits JIT code.  Unfortunately to do so,
+// it has to create platform-native object files, possibly with platform-native
+// debugging information.  Currently only ELF and Mach-O are supported, which
+// limits this interface to Linux and Mac OS.  This JIT compilation interface
+// was introduced in GDB 7.0.  V8 support can be enabled with the --gdbjit flag.
+//
+// The other way that GDB can know about V8 code is via the "custom JIT reader"
+// interface, in which a GDB extension parses V8's private data to determine the
+// function, file, and line of a JIT frame, and how to unwind those frames.
+// This interface was introduced in GDB 7.6.  This interface still relies on V8
+// to register its code via the JIT compilation interface, but doesn't require
+// that V8 create ELF images.  Support will be added for this interface in the
+// future.
 //
-
-#ifdef ENABLE_GDB_JIT_INTERFACE
-#include "src/v8.h"
-
-#include "src/factory.h"
 
 namespace v8 {
 namespace internal {
-
-class CompilationInfo;
-
-class GDBJITInterface: public AllStatic {
- public:
-  enum CodeTag { NON_FUNCTION, FUNCTION };
-
-  // Main entry point into GDB JIT realized as a JitCodeEventHandler.
-  static void EventHandler(const v8::JitCodeEvent* event);
-
-  static void AddCode(Handle<Name> name,
-                      Handle<Script> script,
-                      Handle<Code> code,
-                      CompilationInfo* info);
-
-  static void RemoveCodeRange(Address start, Address end);
-
- private:
-  static void AddCode(const char* name, Code* code, CodeTag tag, Script* script,
-                      CompilationInfo* info);
-
-  static void RemoveCode(Code* code);
-};
-
-#define GDBJIT(action) GDBJITInterface::action
-
-} }   // namespace v8::internal
-#else
-#define GDBJIT(action) ((void) 0)
+namespace GDBJITInterface {
+#ifdef ENABLE_GDB_JIT_INTERFACE
+// JitCodeEventHandler that creates ELF/Mach-O objects and registers them with
+// GDB.
+void EventHandler(const v8::JitCodeEvent* event);
 #endif
+}  // namespace GDBJITInterface
+}  // namespace internal
+}  // namespace v8
 
 #endif
index 277cad6..25c6b4e 100644 (file)
@@ -230,20 +230,20 @@ class GlobalHandles::Node {
     weak_callback_ = weak_callback;
   }
 
-  void MakePhantom(void* parameter, int number_of_internal_fields,
-                   PhantomCallbackData<void>::Callback phantom_callback) {
-    DCHECK(number_of_internal_fields >= 0);
-    DCHECK(number_of_internal_fields <= 2);
-    DCHECK(phantom_callback != NULL);
+  void MakeWeak(void* parameter,
+                WeakCallbackInfo<void>::Callback phantom_callback,
+                v8::WeakCallbackType type) {
+    DCHECK(phantom_callback != nullptr);
     DCHECK(IsInUse());
-    CHECK(object_ != NULL);
+    CHECK(object_ != nullptr);
     set_state(WEAK);
-    if (number_of_internal_fields == 0) {
-      set_weakness_type(PHANTOM_WEAK_0_INTERNAL_FIELDS);
-    } else if (number_of_internal_fields == 1) {
-      set_weakness_type(PHANTOM_WEAK_1_INTERNAL_FIELDS);
-    } else {
+    switch (type) {
+      case v8::WeakCallbackType::kParameter:
+        set_weakness_type(PHANTOM_WEAK);
+        break;
+      case v8::WeakCallbackType::kInternalFields:
       set_weakness_type(PHANTOM_WEAK_2_INTERNAL_FIELDS);
+      break;
     }
     set_parameter(parameter);
     weak_callback_ = reinterpret_cast<WeakCallback>(phantom_callback);
@@ -264,38 +264,28 @@ class GlobalHandles::Node {
     if (weak_callback_ != NULL) {
       if (weakness_type() == NORMAL_WEAK) return;
 
-      v8::Isolate* api_isolate = reinterpret_cast<v8::Isolate*>(isolate);
-
-      DCHECK(weakness_type() == PHANTOM_WEAK_0_INTERNAL_FIELDS ||
-             weakness_type() == PHANTOM_WEAK_1_INTERNAL_FIELDS ||
+      DCHECK(weakness_type() == PHANTOM_WEAK ||
              weakness_type() == PHANTOM_WEAK_2_INTERNAL_FIELDS);
 
-      Object* internal_field0 = nullptr;
-      Object* internal_field1 = nullptr;
-      if (weakness_type() != PHANTOM_WEAK_0_INTERNAL_FIELDS) {
-        JSObject* jsobject = reinterpret_cast<JSObject*>(object());
-        DCHECK(jsobject->IsJSObject());
-        DCHECK(jsobject->GetInternalFieldCount() >= 1);
-        internal_field0 = jsobject->GetInternalField(0);
-        if (weakness_type() == PHANTOM_WEAK_2_INTERNAL_FIELDS) {
-          DCHECK(jsobject->GetInternalFieldCount() >= 2);
-          internal_field1 = jsobject->GetInternalField(1);
+      void* internal_fields[v8::kInternalFieldsInWeakCallback] = {nullptr,
+                                                                  nullptr};
+      if (weakness_type() != PHANTOM_WEAK && object()->IsJSObject()) {
+        auto jsobject = JSObject::cast(object());
+        int field_count = jsobject->GetInternalFieldCount();
+        for (int i = 0; i < v8::kInternalFieldsInWeakCallback; ++i) {
+          if (field_count == i) break;
+          auto field = jsobject->GetInternalField(i);
+          if (field->IsSmi()) internal_fields[i] = field;
         }
       }
 
-      // Zap with harmless value.
-      *location() = Smi::FromInt(0);
-      typedef PhantomCallbackData<void> Data;
-
-      if (!internal_field0->IsSmi()) internal_field0 = nullptr;
-      if (!internal_field1->IsSmi()) internal_field1 = nullptr;
-
-      Data data(api_isolate, parameter(), internal_field0, internal_field1);
-      Data::Callback callback =
-          reinterpret_cast<Data::Callback>(weak_callback_);
+      // Zap with something dangerous.
+      *location() = reinterpret_cast<Object*>(0x6057ca11);
 
+      typedef v8::WeakCallbackInfo<void> Data;
+      auto callback = reinterpret_cast<Data::Callback>(weak_callback_);
       pending_phantom_callbacks->Add(
-          PendingPhantomCallback(this, data, callback));
+          PendingPhantomCallback(this, callback, parameter(), internal_fields));
       DCHECK(IsInUse());
       set_state(NEAR_DEATH);
     }
@@ -562,14 +552,13 @@ void GlobalHandles::MakeWeak(Object** location, void* parameter,
 }
 
 
-typedef PhantomCallbackData<void>::Callback GenericCallback;
+typedef v8::WeakCallbackInfo<void>::Callback GenericCallback;
 
 
-void GlobalHandles::MakePhantom(Object** location, void* parameter,
-                                int number_of_internal_fields,
-                                GenericCallback phantom_callback) {
-  Node::FromLocation(location)
-      ->MakePhantom(parameter, number_of_internal_fields, phantom_callback);
+void GlobalHandles::MakeWeak(Object** location, void* parameter,
+                             GenericCallback phantom_callback,
+                             v8::WeakCallbackType type) {
+  Node::FromLocation(location)->MakeWeak(parameter, phantom_callback, type);
 }
 
 
@@ -633,13 +622,12 @@ void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
       // In the internal fields case we will need the internal
       // fields, so we can't zap the handle.
       if (node->state() == Node::PENDING) {
-        if (node->weakness_type() == PHANTOM_WEAK_0_INTERNAL_FIELDS) {
+        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() == PHANTOM_WEAK_1_INTERNAL_FIELDS ||
-                 node->weakness_type() == PHANTOM_WEAK_2_INTERNAL_FIELDS);
+          DCHECK(node->weakness_type() == PHANTOM_WEAK_2_INTERNAL_FIELDS);
         }
       } else {
         // Node is not pending, so that means the object survived.  We still
@@ -692,13 +680,12 @@ void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) {
     DCHECK(node->is_in_new_space_list());
     if ((node->is_independent() || node->is_partially_dependent()) &&
         node->IsWeakRetainer()) {
-      if (node->weakness_type() == PHANTOM_WEAK_0_INTERNAL_FIELDS) {
+      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() == PHANTOM_WEAK_1_INTERNAL_FIELDS ||
-               node->weakness_type() == PHANTOM_WEAK_2_INTERNAL_FIELDS);
+        DCHECK(node->weakness_type() == PHANTOM_WEAK_2_INTERNAL_FIELDS);
         // 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).
@@ -841,17 +828,50 @@ void GlobalHandles::UpdateListOfNewSpaceNodes() {
 
 int GlobalHandles::DispatchPendingPhantomCallbacks() {
   int freed_nodes = 0;
+  {
+    // The initial pass callbacks must simply clear the nodes.
+    for (auto i = pending_phantom_callbacks_.begin();
+         i != pending_phantom_callbacks_.end(); ++i) {
+      auto callback = i;
+      // Skip callbacks that have already been processed once.
+      if (callback->node() == nullptr) continue;
+      callback->Invoke(isolate());
+      freed_nodes++;
+    }
+  }
+  // The second pass empties the list.
   while (pending_phantom_callbacks_.length() != 0) {
-    PendingPhantomCallback callback = pending_phantom_callbacks_.RemoveLast();
-    DCHECK(callback.node()->IsInUse());
-    callback.invoke();
-    DCHECK(!callback.node()->IsInUse());
-    freed_nodes++;
+    auto callback = pending_phantom_callbacks_.RemoveLast();
+    DCHECK(callback.node() == nullptr);
+    // No second pass callback required.
+    if (callback.callback() == nullptr) continue;
+    // Fire second pass callback.
+    callback.Invoke(isolate());
   }
   return freed_nodes;
 }
 
 
+void GlobalHandles::PendingPhantomCallback::Invoke(Isolate* isolate) {
+  Data::Callback* callback_addr = nullptr;
+  if (node_ != nullptr) {
+    // Initialize for first pass callback.
+    DCHECK(node_->state() == Node::NEAR_DEATH);
+    callback_addr = &callback_;
+  }
+  Data data(reinterpret_cast<v8::Isolate*>(isolate), parameter_,
+            internal_fields_, callback_addr);
+  Data::Callback callback = callback_;
+  callback_ = nullptr;
+  callback(data);
+  if (node_ != nullptr) {
+    // Transition to second pass state.
+    DCHECK(node_->state() == Node::FREE);
+    node_ = nullptr;
+  }
+}
+
+
 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
@@ -859,6 +879,12 @@ int GlobalHandles::PostGarbageCollectionProcessing(GarbageCollector collector) {
   DCHECK(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
   const int initial_post_gc_processing_count = ++post_gc_processing_count_;
   int freed_nodes = 0;
+  freed_nodes += DispatchPendingPhantomCallbacks();
+  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;
+  }
   if (collector == SCAVENGER) {
     freed_nodes = PostScavengeProcessing(initial_post_gc_processing_count);
   } else {
@@ -869,7 +895,6 @@ int GlobalHandles::PostGarbageCollectionProcessing(GarbageCollector collector) {
     // PostScavengeProcessing.
     return freed_nodes;
   }
-  freed_nodes += DispatchPendingPhantomCallbacks();
   if (initial_post_gc_processing_count == post_gc_processing_count_) {
     UpdateListOfNewSpaceNodes();
   }
@@ -877,14 +902,6 @@ int GlobalHandles::PostGarbageCollectionProcessing(GarbageCollector collector) {
 }
 
 
-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()) {
index 767989c..cb5619f 100644 (file)
@@ -100,12 +100,11 @@ struct ObjectGroupRetainerInfo {
 enum WeaknessType {
   NORMAL_WEAK,  // Embedder gets a handle to the dying object.
   // In the following cases, the embedder gets the parameter they passed in
-  // earlier, and the 0, 1 or 2 first internal fields. Note that the internal
+  // earlier, and 0 or 2 first internal fields. Note that the internal
   // fields must contain aligned non-V8 pointers.  Getting pointers to V8
   // objects through this interface would be GC unsafe so in that case the
   // embedder gets a null pointer instead.
-  PHANTOM_WEAK_0_INTERNAL_FIELDS,
-  PHANTOM_WEAK_1_INTERNAL_FIELDS,
+  PHANTOM_WEAK,
   PHANTOM_WEAK_2_INTERNAL_FIELDS
 };
 
@@ -145,9 +144,9 @@ class GlobalHandles {
 
   // 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,
-                          int number_of_internal_fields,
-                          PhantomCallbackData<void>::Callback weak_callback);
+  static void MakeWeak(Object** location, void* parameter,
+                       WeakCallbackInfo<void>::Callback weak_callback,
+                       v8::WeakCallbackType type);
 
   void RecordStats(HeapStats* stats);
 
@@ -349,18 +348,26 @@ class GlobalHandles {
 
 class GlobalHandles::PendingPhantomCallback {
  public:
-  typedef PhantomCallbackData<void> Data;
-  PendingPhantomCallback(Node* node, Data data, Data::Callback callback)
-      : node_(node), data_(data), callback_(callback) {}
+  typedef v8::WeakCallbackInfo<void> Data;
+  PendingPhantomCallback(
+      Node* node, Data::Callback callback, void* parameter,
+      void* internal_fields[v8::kInternalFieldsInWeakCallback])
+      : node_(node), callback_(callback), parameter_(parameter) {
+    for (int i = 0; i < v8::kInternalFieldsInWeakCallback; ++i) {
+      internal_fields_[i] = internal_fields[i];
+    }
+  }
 
-  void invoke();
+  void Invoke(Isolate* isolate);
 
   Node* node() { return node_; }
+  Data::Callback callback() { return callback_; }
 
  private:
   Node* node_;
-  Data data_;
   Data::Callback callback_;
+  void* parameter_;
+  void* internal_fields_[v8::kInternalFieldsInWeakCallback];
 };
 
 
index 32396d8..e93fa3b 100644 (file)
@@ -89,7 +89,7 @@ namespace internal {
 
 // Determine whether double field unboxing feature is enabled.
 #if V8_TARGET_ARCH_64_BIT
-#define V8_DOUBLE_FIELDS_UNBOXING 0
+#define V8_DOUBLE_FIELDS_UNBOXING 1
 #else
 #define V8_DOUBLE_FIELDS_UNBOXING 0
 #endif
@@ -408,19 +408,18 @@ typedef bool (*WeakSlotCallbackWithHeap)(Heap* heap, Object** pointer);
 // 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.
-  OLD_DATA_SPACE,       // Must not have pointers to new space.
-  CODE_SPACE,           // No pointers to new space, marked executable.
-  MAP_SPACE,            // Only and all map objects.
-  CELL_SPACE,           // Only and all cell objects.
-  PROPERTY_CELL_SPACE,  // Only and all global property cell objects.
-  LO_SPACE,             // Promoted large objects.
+  NEW_SPACE,          // Semispaces collected with copying collector.
+  OLD_POINTER_SPACE,  // May contain pointers to new space.
+  OLD_DATA_SPACE,     // Must not have pointers to new space.
+  CODE_SPACE,         // No pointers to new space, marked executable.
+  MAP_SPACE,          // Only and all map objects.
+  CELL_SPACE,         // Only and all cell objects.
+  LO_SPACE,           // Promoted large objects.
 
   FIRST_SPACE = NEW_SPACE,
   LAST_SPACE = LO_SPACE,
   FIRST_PAGED_SPACE = OLD_POINTER_SPACE,
-  LAST_PAGED_SPACE = PROPERTY_CELL_SPACE
+  LAST_PAGED_SPACE = CELL_SPACE
 };
 const int kSpaceTagSize = 3;
 const int kSpaceTagMask = (1 << kSpaceTagSize) - 1;
@@ -452,6 +451,13 @@ enum VisitMode {
 enum NativesFlag { NOT_NATIVES_CODE, NATIVES_CODE };
 
 
+// ParseRestriction is used to restrict the set of valid statements in a
+// unit of compilation.  Restriction violations cause a syntax error.
+enum ParseRestriction {
+  NO_PARSE_RESTRICTION,         // All expressions are allowed.
+  ONLY_SINGLE_FUNCTION_LITERAL  // Only a single FunctionLiteral expression.
+};
+
 // A CodeDesc describes a buffer holding instructions and relocation
 // information. The instructions start at the beginning of the buffer
 // and grow forward, the relocation information starts at the end of
@@ -696,9 +702,15 @@ enum ScopeType {
   ARROW_SCOPE      // The top-level scope for an arrow function literal.
 };
 
-
+// The mips architecture prior to revision 5 has inverted encoding for sNaN.
+#if (V8_TARGET_ARCH_MIPS && !defined(_MIPS_ARCH_MIPS32R6)) || \
+    (V8_TARGET_ARCH_MIPS64 && !defined(_MIPS_ARCH_MIPS64R6))
+const uint32_t kHoleNanUpper32 = 0xFFFF7FFF;
+const uint32_t kHoleNanLower32 = 0xFFFF7FFF;
+#else
 const uint32_t kHoleNanUpper32 = 0xFFF7FFFF;
 const uint32_t kHoleNanLower32 = 0xFFF7FFFF;
+#endif
 
 const uint64_t kHoleNanInt64 =
     (static_cast<uint64_t>(kHoleNanUpper32) << 32) | kHoleNanLower32;
@@ -711,10 +723,12 @@ enum VariableMode {
 
   CONST_LEGACY,    // declared via legacy 'const' declarations
 
-  LET,             // declared via 'let' declarations
+  LET,             // declared via 'let' declarations (first lexical)
 
   CONST,           // declared via 'const' declarations
 
+  IMPORT,          // declared via 'import' declarations (last lexical)
+
   // Variables introduced by the compiler:
   INTERNAL,        // like VAR, but not user-visible (may or may not
                    // be in a context)
@@ -742,17 +756,17 @@ inline bool IsDynamicVariableMode(VariableMode mode) {
 
 
 inline bool IsDeclaredVariableMode(VariableMode mode) {
-  return mode >= VAR && mode <= CONST;
+  return mode >= VAR && mode <= IMPORT;
 }
 
 
 inline bool IsLexicalVariableMode(VariableMode mode) {
-  return mode == LET || mode == CONST;
+  return mode >= LET && mode <= IMPORT;
 }
 
 
 inline bool IsImmutableVariableMode(VariableMode mode) {
-  return mode == CONST || mode == CONST_LEGACY;
+  return mode == CONST || mode == CONST_LEGACY || mode == IMPORT;
 }
 
 
@@ -796,6 +810,10 @@ enum InitializationFlag {
 enum MaybeAssignedFlag { kNotAssigned, kMaybeAssigned };
 
 
+// Serialized in PreparseData, so numeric values should not be changed.
+enum ParseErrorType { kSyntaxError = 0, kReferenceError = 1 };
+
+
 enum ClearExceptionFlag {
   KEEP_EXCEPTION,
   CLEAR_EXCEPTION
@@ -821,8 +839,13 @@ enum FunctionKind {
   kDefaultConstructor = 1 << 4,
   kSubclassConstructor = 1 << 5,
   kBaseConstructor = 1 << 6,
+  kInObjectLiteral = 1 << 7,
   kDefaultBaseConstructor = kDefaultConstructor | kBaseConstructor,
-  kDefaultSubclassConstructor = kDefaultConstructor | kSubclassConstructor
+  kDefaultSubclassConstructor = kDefaultConstructor | kSubclassConstructor,
+  kConciseMethodInObjectLiteral = kConciseMethod | kInObjectLiteral,
+  kConciseGeneratorMethodInObjectLiteral =
+      kConciseGeneratorMethod | kInObjectLiteral,
+  kAccessorFunctionInObjectLiteral = kAccessorFunction | kInObjectLiteral,
 };
 
 
@@ -836,7 +859,10 @@ inline bool IsValidFunctionKind(FunctionKind kind) {
          kind == FunctionKind::kDefaultBaseConstructor ||
          kind == FunctionKind::kDefaultSubclassConstructor ||
          kind == FunctionKind::kBaseConstructor ||
-         kind == FunctionKind::kSubclassConstructor;
+         kind == FunctionKind::kSubclassConstructor ||
+         kind == FunctionKind::kConciseMethodInObjectLiteral ||
+         kind == FunctionKind::kConciseGeneratorMethodInObjectLiteral ||
+         kind == FunctionKind::kAccessorFunctionInObjectLiteral;
 }
 
 
@@ -888,6 +914,19 @@ inline bool IsConstructor(FunctionKind kind) {
          (FunctionKind::kBaseConstructor | FunctionKind::kSubclassConstructor |
           FunctionKind::kDefaultConstructor);
 }
+
+
+inline bool IsInObjectLiteral(FunctionKind kind) {
+  DCHECK(IsValidFunctionKind(kind));
+  return kind & FunctionKind::kInObjectLiteral;
+}
+
+
+inline FunctionKind WithObjectLiteralBit(FunctionKind kind) {
+  kind = static_cast<FunctionKind>(kind | FunctionKind::kInObjectLiteral);
+  DCHECK(IsValidFunctionKind(kind));
+  return kind;
+}
 } }  // namespace v8::internal
 
 namespace i = v8::internal;
index 72625a5..5152a55 100644 (file)
@@ -211,7 +211,7 @@ function ArrayOf() {
 function HarmonyArrayExtendSymbolPrototype() {
   %CheckIsBootstrapping();
 
-  InstallConstants($Symbol, $Array(
+  InstallConstants(global.Symbol, $Array(
     // TODO(dslomov, caitp): Move to symbol.js when shipping
    "isConcatSpreadable", symbolIsConcatSpreadable
   ));
diff --git a/deps/v8/src/harmony-reflect.js b/deps/v8/src/harmony-reflect.js
new file mode 100644 (file)
index 0000000..f900d70
--- /dev/null
@@ -0,0 +1,18 @@
+// 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';
+
+var $Reflect = global.Reflect;
+
+function SetUpReflect() {
+  %CheckIsBootstrapping();
+
+  InstallFunctions($Reflect, DONT_ENUM, $Array(
+   "apply", ReflectApply,
+   "construct", ReflectConstruct
+  ));
+}
+
+SetUpReflect();
diff --git a/deps/v8/src/harmony-string.js b/deps/v8/src/harmony-string.js
deleted file mode 100644 (file)
index 6bbe139..0000000
+++ /dev/null
@@ -1,194 +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.
-
-"use strict";
-
-// This file relies on the fact that the following declaration has been made
-// in runtime.js:
-// var $String = global.String;
-// var $Array = global.Array;
-
-// -------------------------------------------------------------------
-
-// ES6 draft 01-20-14, section 21.1.3.13
-function StringRepeat(count) {
-  CHECK_OBJECT_COERCIBLE(this, "String.prototype.repeat");
-
-  var s = TO_STRING_INLINE(this);
-  var n = ToInteger(count);
-  // 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 r = "";
-  while (true) {
-    if (n & 1) r += s;
-    n >>= 1;
-    if (n === 0) return r;
-    s += s;
-  }
-}
-
-
-// ES6 draft 04-05-14, section 21.1.3.18
-function StringStartsWith(searchString /* position */) {  // length == 1
-  CHECK_OBJECT_COERCIBLE(this, "String.prototype.startsWith");
-
-  var s = TO_STRING_INLINE(this);
-
-  if (IS_REGEXP(searchString)) {
-    throw MakeTypeError("first_argument_not_regexp",
-                        ["String.prototype.startsWith"]);
-  }
-
-  var ss = TO_STRING_INLINE(searchString);
-  var pos = 0;
-  if (%_ArgumentsLength() > 1) {
-    pos = %_Arguments(1);  // position
-    pos = ToInteger(pos);
-  }
-
-  var s_len = s.length;
-  var start = MathMin(MathMax(pos, 0), s_len);
-  var ss_len = ss.length;
-  if (ss_len + start > s_len) {
-    return false;
-  }
-
-  return %StringIndexOf(s, ss, start) === start;
-}
-
-
-// ES6 draft 04-05-14, section 21.1.3.7
-function StringEndsWith(searchString /* position */) {  // length == 1
-  CHECK_OBJECT_COERCIBLE(this, "String.prototype.endsWith");
-
-  var s = TO_STRING_INLINE(this);
-
-  if (IS_REGEXP(searchString)) {
-    throw MakeTypeError("first_argument_not_regexp",
-                        ["String.prototype.endsWith"]);
-  }
-
-  var ss = TO_STRING_INLINE(searchString);
-  var s_len = s.length;
-  var pos = s_len;
-  if (%_ArgumentsLength() > 1) {
-    var arg = %_Arguments(1);  // position
-    if (!IS_UNDEFINED(arg)) {
-      pos = ToInteger(arg);
-    }
-  }
-
-  var end = MathMin(MathMax(pos, 0), s_len);
-  var ss_len = ss.length;
-  var start = end - ss_len;
-  if (start < 0) {
-    return false;
-  }
-
-  return %StringLastIndexOf(s, ss, start) === start;
-}
-
-
-// ES6 draft 04-05-14, section 21.1.3.6
-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.includes"]);
-  }
-
-  var ss = TO_STRING_INLINE(searchString);
-  var pos = 0;
-  if (%_ArgumentsLength() > 1) {
-    pos = %_Arguments(1);  // position
-    pos = ToInteger(pos);
-  }
-
-  var s_len = s.length;
-  var start = MathMin(MathMax(pos, 0), s_len);
-  var ss_len = ss.length;
-  if (ss_len + start > s_len) {
-    return false;
-  }
-
-  return %StringIndexOf(s, ss, start) !== -1;
-}
-
-
-// ES6 Draft 05-22-2014, section 21.1.3.3
-function StringCodePointAt(pos) {
-  CHECK_OBJECT_COERCIBLE(this, "String.prototype.codePointAt");
-
-  var string = TO_STRING_INLINE(this);
-  var size = string.length;
-  pos = TO_INTEGER(pos);
-  if (pos < 0 || pos >= size) {
-    return UNDEFINED;
-  }
-  var first = %_StringCharCodeAt(string, pos);
-  if (first < 0xD800 || first > 0xDBFF || pos + 1 == size) {
-    return first;
-  }
-  var second = %_StringCharCodeAt(string, pos + 1);
-  if (second < 0xDC00 || second > 0xDFFF) {
-    return first;
-  }
-  return (first - 0xD800) * 0x400 + second + 0x2400;
-}
-
-
-// ES6 Draft 05-22-2014, section 21.1.2.2
-function StringFromCodePoint(_) {  // length = 1
-  var code;
-  var length = %_ArgumentsLength();
-  var index;
-  var result = "";
-  for (index = 0; index < length; index++) {
-    code = %_Arguments(index);
-    if (!%_IsSmi(code)) {
-      code = ToNumber(code);
-    }
-    if (code < 0 || code > 0x10FFFF || code !== TO_INTEGER(code)) {
-      throw MakeRangeError("invalid_code_point", [code]);
-    }
-    if (code <= 0xFFFF) {
-      result += %_StringCharFromCode(code);
-    } else {
-      code -= 0x10000;
-      result += %_StringCharFromCode((code >>> 10) & 0x3FF | 0xD800);
-      result += %_StringCharFromCode(code & 0x3FF | 0xDC00);
-    }
-  }
-  return result;
-}
-
-
-// -------------------------------------------------------------------
-
-function ExtendStringPrototype() {
-  %CheckIsBootstrapping();
-
-  // Set up the non-enumerable functions on the String object.
-  InstallFunctions($String, DONT_ENUM, $Array(
-    "fromCodePoint", StringFromCodePoint
-  ));
-
-  // Set up the non-enumerable functions on the String prototype object.
-  InstallFunctions($String.prototype, DONT_ENUM, $Array(
-    "codePointAt", StringCodePointAt,
-    "includes", StringIncludes,
-    "endsWith", StringEndsWith,
-    "repeat", StringRepeat,
-    "startsWith", StringStartsWith
-  ));
-}
-
-ExtendStringPrototype();
index aed8ca0..4f4f986 100644 (file)
@@ -7,7 +7,6 @@
 // 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;
 
 DefaultObjectToString = ObjectToStringHarmony;
 // ES6 draft 08-24-14, section 19.1.3.6
@@ -26,7 +25,7 @@ function ObjectToStringHarmony() {
 function HarmonyToStringExtendSymbolPrototype() {
   %CheckIsBootstrapping();
 
-  InstallConstants($Symbol, $Array(
+  InstallConstants(global.Symbol, $Array(
     // TODO(dslomov, caitp): Move to symbol.js when shipping
    "toStringTag", symbolToStringTag
   ));
index d86ce5e..0fe5034 100644 (file)
@@ -15,7 +15,6 @@ namespace internal {
 HeapProfiler::HeapProfiler(Heap* heap)
     : ids_(new HeapObjectsMap(heap)),
       names_(new StringsStorage(heap)),
-      next_snapshot_uid_(1),
       is_tracking_object_moves_(false) {
 }
 
@@ -63,10 +62,9 @@ v8::RetainedObjectInfo* HeapProfiler::ExecuteWrapperClassCallback(
 
 
 HeapSnapshot* HeapProfiler::TakeSnapshot(
-    const char* name,
     v8::ActivityControl* control,
     v8::HeapProfiler::ObjectNameResolver* resolver) {
-  HeapSnapshot* result = new HeapSnapshot(this, name, next_snapshot_uid_++);
+  HeapSnapshot* result = new HeapSnapshot(this);
   {
     HeapSnapshotGenerator generator(result, control, resolver, heap());
     if (!generator.GenerateSnapshot()) {
@@ -82,14 +80,6 @@ HeapSnapshot* HeapProfiler::TakeSnapshot(
 }
 
 
-HeapSnapshot* HeapProfiler::TakeSnapshot(
-    String* name,
-    v8::ActivityControl* control,
-    v8::HeapProfiler::ObjectNameResolver* resolver) {
-  return TakeSnapshot(names_->GetName(name), control, resolver);
-}
-
-
 void HeapProfiler::StartHeapObjectsTracking(bool track_allocations) {
   ids_->UpdateHeapObjectsMap();
   is_tracking_object_moves_ = true;
@@ -101,8 +91,9 @@ void HeapProfiler::StartHeapObjectsTracking(bool track_allocations) {
 }
 
 
-SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream) {
-  return ids_->PushHeapObjectsStats(stream);
+SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream,
+                                                    int64_t* timestamp_us) {
+  return ids_->PushHeapObjectsStats(stream, timestamp_us);
 }
 
 
index 4197d4d..68e1365 100644 (file)
@@ -22,11 +22,6 @@ class HeapProfiler {
   size_t GetMemorySizeUsedByProfiler();
 
   HeapSnapshot* TakeSnapshot(
-      const char* name,
-      v8::ActivityControl* control,
-      v8::HeapProfiler::ObjectNameResolver* resolver);
-  HeapSnapshot* TakeSnapshot(
-      String* name,
       v8::ActivityControl* control,
       v8::HeapProfiler::ObjectNameResolver* resolver);
 
@@ -38,7 +33,8 @@ class HeapProfiler {
   HeapObjectsMap* heap_object_map() const { return ids_.get(); }
   StringsStorage* names() const { return names_.get(); }
 
-  SnapshotObjectId PushHeapObjectsStats(OutputStream* stream);
+  SnapshotObjectId PushHeapObjectsStats(OutputStream* stream,
+                                        int64_t* timestamp_us);
   int GetSnapshotsCount();
   HeapSnapshot* GetSnapshot(int index);
   SnapshotObjectId GetSnapshotObjectId(Handle<Object> obj);
@@ -73,7 +69,6 @@ class HeapProfiler {
   SmartPointer<HeapObjectsMap> ids_;
   List<HeapSnapshot*> snapshots_;
   SmartPointer<StringsStorage> names_;
-  unsigned next_snapshot_uid_;
   List<v8::HeapProfiler::WrapperInfoCallback> wrapper_callbacks_;
   SmartPointer<AllocationTracker> allocation_tracker_;
   bool is_tracking_object_moves_;
index 8e18518..b8f9ab3 100644 (file)
@@ -178,12 +178,8 @@ template <> struct SnapshotSizeConstants<8> {
 }  // namespace
 
 
-HeapSnapshot::HeapSnapshot(HeapProfiler* profiler,
-                           const char* title,
-                           unsigned uid)
+HeapSnapshot::HeapSnapshot(HeapProfiler* profiler)
     : profiler_(profiler),
-      title_(title),
-      uid_(uid),
       root_index_(HeapEntry::kNoEntry),
       gc_roots_index_(HeapEntry::kNoEntry),
       max_snapshot_js_object_id_(0) {
@@ -615,7 +611,8 @@ int HeapObjectsMap::FindUntrackedObjects() {
 }
 
 
-SnapshotObjectId HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) {
+SnapshotObjectId HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream,
+                                                      int64_t* timestamp_us) {
   UpdateHeapObjectsMap();
   time_intervals_.Add(TimeInterval(next_id_));
   int prefered_chunk_size = stream->GetChunkSize();
@@ -657,6 +654,10 @@ SnapshotObjectId HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) {
     if (result == OutputStream::kAbort) return last_assigned_id();
   }
   stream->EndOfStream();
+  if (timestamp_us) {
+    *timestamp_us = (time_intervals_.last().timestamp -
+                     time_intervals_[0].timestamp).InMicroseconds();
+  }
   return last_assigned_id();
 }
 
@@ -1286,39 +1287,31 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
 
 
 void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
-  if (map->HasTransitionArray()) {
-    TransitionArray* transitions = map->transitions();
+  Object* raw_transitions = map->raw_transitions();
+  if (TransitionArray::IsFullTransitionArray(raw_transitions)) {
+    TransitionArray* transitions = TransitionArray::cast(raw_transitions);
     int transitions_entry = GetEntry(transitions)->index();
-    Object* back_pointer = transitions->back_pointer_storage();
-    TagObject(back_pointer, "(back pointer)");
-    SetInternalReference(transitions, transitions_entry,
-                         "back_pointer", back_pointer);
 
     if (FLAG_collect_maps && map->CanTransition()) {
-      if (!transitions->IsSimpleTransition()) {
-        if (transitions->HasPrototypeTransitions()) {
-          FixedArray* prototype_transitions =
-              transitions->GetPrototypeTransitions();
-          MarkAsWeakContainer(prototype_transitions);
-          TagObject(prototype_transitions, "(prototype transitions");
-          SetInternalReference(transitions, transitions_entry,
-                               "prototype_transitions", prototype_transitions);
-        }
-        // TODO(alph): transitions keys are strong links.
-        MarkAsWeakContainer(transitions);
+      if (transitions->HasPrototypeTransitions()) {
+        FixedArray* prototype_transitions =
+            transitions->GetPrototypeTransitions();
+        MarkAsWeakContainer(prototype_transitions);
+        TagObject(prototype_transitions, "(prototype transitions");
+        SetInternalReference(transitions, transitions_entry,
+                             "prototype_transitions", prototype_transitions);
       }
+      // TODO(alph): transitions keys are strong links.
+      MarkAsWeakContainer(transitions);
     }
 
     TagObject(transitions, "(transition array)");
-    SetInternalReference(map, entry,
-                         "transitions", transitions,
-                         Map::kTransitionsOrBackPointerOffset);
-  } else {
-    Object* back_pointer = map->GetBackPointer();
-    TagObject(back_pointer, "(back pointer)");
-    SetInternalReference(map, entry,
-                         "back_pointer", back_pointer,
-                         Map::kTransitionsOrBackPointerOffset);
+    SetInternalReference(map, entry, "transitions", transitions,
+                         Map::kTransitionsOffset);
+  } else if (TransitionArray::IsSimpleTransition(raw_transitions)) {
+    TagObject(raw_transitions, "(transition)");
+    SetInternalReference(map, entry, "transition", raw_transitions,
+                         Map::kTransitionsOffset);
   }
   DescriptorArray* descriptors = map->instance_descriptors();
   TagObject(descriptors, "(map descriptors)");
@@ -1332,9 +1325,15 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
                        Map::kCodeCacheOffset);
   SetInternalReference(map, entry,
                        "prototype", map->prototype(), Map::kPrototypeOffset);
-  SetInternalReference(map, entry,
-                       "constructor", map->constructor(),
-                       Map::kConstructorOffset);
+  Object* constructor_or_backpointer = map->constructor_or_backpointer();
+  if (constructor_or_backpointer->IsMap()) {
+    TagObject(constructor_or_backpointer, "(back pointer)");
+    SetInternalReference(map, entry, "back_pointer", constructor_or_backpointer,
+                         Map::kConstructorOrBackPointerOffset);
+  } else {
+    SetInternalReference(map, entry, "constructor", constructor_or_backpointer,
+                         Map::kConstructorOrBackPointerOffset);
+  }
   TagObject(map->dependent_code(), "(dependent code)");
   MarkAsWeakContainer(map->dependent_code());
   SetInternalReference(map, entry,
@@ -1518,9 +1517,8 @@ void V8HeapExplorer::ExtractCellReferences(int entry, Cell* cell) {
 
 void V8HeapExplorer::ExtractPropertyCellReferences(int entry,
                                                    PropertyCell* cell) {
-  ExtractCellReferences(entry, cell);
-  SetInternalReference(cell, entry, "type", cell->type(),
-                       PropertyCell::kTypeOffset);
+  SetInternalReference(cell, entry, "value", cell->value(),
+                       PropertyCell::kValueOffset);
   MarkAsWeakContainer(cell->dependent_code());
   SetInternalReference(cell, entry, "dependent_code", cell->dependent_code(),
                        PropertyCell::kDependentCodeOffset);
@@ -2750,6 +2748,11 @@ void HeapSnapshotJSONSerializer::SerializeImpl() {
   if (writer_->aborted()) return;
   writer_->AddString("],\n");
 
+  writer_->AddString("\"samples\":[");
+  SerializeSamples();
+  if (writer_->aborted()) return;
+  writer_->AddString("],\n");
+
   writer_->AddString("\"strings\":[");
   SerializeStrings();
   if (writer_->aborted()) return;
@@ -2885,12 +2888,7 @@ void HeapSnapshotJSONSerializer::SerializeNodes() {
 
 
 void HeapSnapshotJSONSerializer::SerializeSnapshot() {
-  writer_->AddString("\"title\":\"");
-  writer_->AddString(snapshot_->title());
-  writer_->AddString("\"");
-  writer_->AddString(",\"uid\":");
-  writer_->AddNumber(snapshot_->uid());
-  writer_->AddString(",\"meta\":");
+  writer_->AddString("\"meta\":");
   // The object describing node serialization layout.
   // We use a set of macros to improve readability.
 #define JSON_A(s) "[" s "]"
@@ -2951,7 +2949,10 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
         JSON_S("function_info_index") ","
         JSON_S("count") ","
         JSON_S("size") ","
-        JSON_S("children"))));
+        JSON_S("children")) ","
+    JSON_S("sample_fields") ":" JSON_A(
+        JSON_S("timestamp_us") ","
+        JSON_S("last_assigned_id"))));
 #undef JSON_S
 #undef JSON_O
 #undef JSON_A
@@ -3040,13 +3041,10 @@ void HeapSnapshotJSONSerializer::SerializeTraceNodeInfos() {
   EmbeddedVector<char, kBufferSize> buffer;
   const List<AllocationTracker::FunctionInfo*>& list =
       tracker->function_info_list();
-  bool first_entry = true;
   for (int i = 0; i < list.length(); i++) {
     AllocationTracker::FunctionInfo* info = list[i];
     int buffer_pos = 0;
-    if (first_entry) {
-      first_entry = false;
-    } else {
+    if (i > 0) {
       buffer[buffer_pos++] = ',';
     }
     buffer_pos = utoa(info->function_id, buffer, buffer_pos);
@@ -3069,6 +3067,34 @@ void HeapSnapshotJSONSerializer::SerializeTraceNodeInfos() {
 }
 
 
+void HeapSnapshotJSONSerializer::SerializeSamples() {
+  const List<HeapObjectsMap::TimeInterval>& samples =
+      snapshot_->profiler()->heap_object_map()->samples();
+  if (samples.is_empty()) return;
+  base::TimeTicks start_time = samples[0].timestamp;
+  // The buffer needs space for 2 unsigned ints, 2 commas, \n and \0
+  const int kBufferSize = MaxDecimalDigitsIn<sizeof(
+                              base::TimeDelta().InMicroseconds())>::kUnsigned +
+                          MaxDecimalDigitsIn<sizeof(samples[0].id)>::kUnsigned +
+                          2 + 1 + 1;
+  EmbeddedVector<char, kBufferSize> buffer;
+  for (int i = 0; i < samples.length(); i++) {
+    HeapObjectsMap::TimeInterval& sample = samples[i];
+    int buffer_pos = 0;
+    if (i > 0) {
+      buffer[buffer_pos++] = ',';
+    }
+    base::TimeDelta time_delta = sample.timestamp - start_time;
+    buffer_pos = utoa(time_delta.InMicroseconds(), buffer, buffer_pos);
+    buffer[buffer_pos++] = ',';
+    buffer_pos = utoa(sample.last_assigned_id(), buffer, buffer_pos);
+    buffer[buffer_pos++] = '\n';
+    buffer[buffer_pos++] = '\0';
+    writer_->AddString(buffer.start());
+  }
+}
+
+
 void HeapSnapshotJSONSerializer::SerializeString(const unsigned char* s) {
   writer_->AddCharacter('\n');
   writer_->AddCharacter('\"');
index 8aef437..5859eb8 100644 (file)
@@ -5,7 +5,7 @@
 #ifndef V8_HEAP_SNAPSHOT_GENERATOR_H_
 #define V8_HEAP_SNAPSHOT_GENERATOR_H_
 
-#include "src/profile-generator-inl.h"
+#include "src/strings-storage.h"
 
 namespace v8 {
 namespace internal {
@@ -141,14 +141,10 @@ class HeapEntry BASE_EMBEDDED {
 // HeapSnapshotGenerator fills in a HeapSnapshot.
 class HeapSnapshot {
  public:
-  HeapSnapshot(HeapProfiler* profiler,
-               const char* title,
-               unsigned uid);
+  explicit HeapSnapshot(HeapProfiler* profiler);
   void Delete();
 
   HeapProfiler* profiler() { return profiler_; }
-  const char* title() { return title_; }
-  unsigned uid() { return uid_; }
   size_t RawSnapshotSize() const;
   HeapEntry* root() { return &entries_[root_index_]; }
   HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; }
@@ -181,8 +177,6 @@ class HeapSnapshot {
   HeapEntry* AddGcSubrootEntry(int tag, SnapshotObjectId id);
 
   HeapProfiler* profiler_;
-  const char* title_;
-  unsigned uid_;
   int root_index_;
   int gc_roots_index_;
   int gc_subroot_indexes_[VisitorSynchronization::kNumberOfSyncTags];
@@ -200,6 +194,16 @@ class HeapSnapshot {
 
 class HeapObjectsMap {
  public:
+  struct TimeInterval {
+    explicit TimeInterval(SnapshotObjectId id)
+        : id(id), size(0), count(0), timestamp(base::TimeTicks::Now()) {}
+    SnapshotObjectId last_assigned_id() const { return id - kObjectIdStep; }
+    SnapshotObjectId id;
+    uint32_t size;
+    uint32_t count;
+    base::TimeTicks timestamp;
+  };
+
   explicit HeapObjectsMap(Heap* heap);
 
   Heap* heap() const { return heap_; }
@@ -215,7 +219,9 @@ class HeapObjectsMap {
   }
 
   void StopHeapObjectsTracking();
-  SnapshotObjectId PushHeapObjectsStats(OutputStream* stream);
+  SnapshotObjectId PushHeapObjectsStats(OutputStream* stream,
+                                        int64_t* timestamp_us);
+  const List<TimeInterval>& samples() const { return time_intervals_; }
   size_t GetUsedMemorySize() const;
 
   SnapshotObjectId GenerateId(v8::RetainedObjectInfo* info);
@@ -242,12 +248,6 @@ class HeapObjectsMap {
     unsigned int size;
     bool accessed;
   };
-  struct TimeInterval {
-    explicit TimeInterval(SnapshotObjectId id) : id(id), size(0), count(0) { }
-    SnapshotObjectId id;
-    uint32_t size;
-    uint32_t count;
-  };
 
   SnapshotObjectId next_id_;
   HashMap entries_map_;
@@ -590,6 +590,7 @@ class HeapSnapshotJSONSerializer {
   void SerializeTraceTree();
   void SerializeTraceNode(AllocationTraceNode* node);
   void SerializeTraceNodeInfos();
+  void SerializeSamples();
   void SerializeString(const unsigned char* s);
   void SerializeStrings();
 
index ff2a559..5060bc9 100644 (file)
@@ -13,9 +13,10 @@ 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::kMaxMarkCompactsInIdleRound = 2;
 const int GCIdleTimeHandler::kIdleScavengeThreshold = 5;
 const double GCIdleTimeHandler::kHighContextDisposalRate = 100;
+const size_t GCIdleTimeHandler::kMinTimeForOverApproximatingWeakClosureInMs = 1;
 
 
 void GCIdleTimeAction::Print() {
@@ -116,7 +117,7 @@ bool GCIdleTimeHandler::ShouldDoScavenge(
     size_t scavenge_speed_in_bytes_per_ms,
     size_t new_space_allocation_throughput_in_bytes_per_ms) {
   size_t new_space_allocation_limit =
-      kMaxFrameRenderingIdleTime * scavenge_speed_in_bytes_per_ms;
+      kMaxScheduledIdleTime * 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.
@@ -132,8 +133,7 @@ bool GCIdleTimeHandler::ShouldDoScavenge(
   } 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;
+        new_space_allocation_throughput_in_bytes_per_ms * kMaxScheduledIdleTime;
   }
 
   if (scavenge_speed_in_bytes_per_ms == 0) {
@@ -153,9 +153,10 @@ bool GCIdleTimeHandler::ShouldDoScavenge(
 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);
+  return idle_time_in_ms >= kMaxScheduledIdleTime &&
+         idle_time_in_ms >=
+             EstimateMarkCompactTime(size_of_objects,
+                                     mark_compact_speed_in_bytes_per_ms);
 }
 
 
@@ -176,11 +177,29 @@ bool GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact(
 }
 
 
+bool GCIdleTimeHandler::ShouldDoOverApproximateWeakClosure(
+    size_t idle_time_in_ms) {
+  // TODO(jochen): Estimate the time it will take to build the object groups.
+  return idle_time_in_ms >= kMinTimeForOverApproximatingWeakClosureInMs;
+}
+
+
+GCIdleTimeAction GCIdleTimeHandler::NothingOrDone() {
+  if (idle_times_which_made_no_progress_since_last_idle_round_ >=
+      kMaxNoProgressIdleTimesPerIdleRound) {
+    return GCIdleTimeAction::Done();
+  } else {
+    idle_times_which_made_no_progress_since_last_idle_round_++;
+    return GCIdleTimeAction::Nothing();
+  }
+}
+
+
 // The following logic is implemented by the controller:
 // (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
+// (2) If the new space is almost full and we can afford 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
@@ -229,33 +248,23 @@ GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms,
     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.
-      // TODO(ulan): Once we enable code compaction for incremental marking, we
-      // can get rid of this special case and always start incremental marking.
-      int remaining_mark_sweeps =
-          kMaxMarkCompactsInIdleRound - mark_compacts_since_idle_round_started_;
-      if (static_cast<size_t>(idle_time_in_ms) > kMaxFrameRenderingIdleTime &&
-          (remaining_mark_sweeps <= 2 ||
-           !heap_state.can_start_incremental_marking)) {
-        return GCIdleTimeAction::FullGC();
-      }
-    }
-    if (!heap_state.can_start_incremental_marking) {
-      return GCIdleTimeAction::Nothing();
+      return GCIdleTimeAction::FullGC();
     }
   }
+
   // TODO(hpayer): Estimate finalize sweeping time.
-  if (heap_state.sweeping_in_progress &&
-      static_cast<size_t>(idle_time_in_ms) >= kMinTimeForFinalizeSweeping) {
-    return GCIdleTimeAction::FinalizeSweeping();
+  if (heap_state.sweeping_in_progress) {
+    if (static_cast<size_t>(idle_time_in_ms) >= kMinTimeForFinalizeSweeping) {
+      return GCIdleTimeAction::FinalizeSweeping();
+    }
+    return NothingOrDone();
   }
 
   if (heap_state.incremental_marking_stopped &&
       !heap_state.can_start_incremental_marking) {
-    return GCIdleTimeAction::Nothing();
+    return NothingOrDone();
   }
+
   size_t step_size = EstimateMarkingStepSize(
       static_cast<size_t>(kIncrementalMarkingStepTimeInMs),
       heap_state.incremental_marking_speed_in_bytes_per_ms);
index 6e7b710..a9b9d76 100644 (file)
@@ -122,13 +122,13 @@ class GCIdleTimeHandler {
   // Number of scavenges that will trigger start of new idle round.
   static const int kIdleScavengeThreshold;
 
-  // That is the maximum idle time we will have during frame rendering.
-  static const size_t kMaxFrameRenderingIdleTime = 16;
+  // This is the maximum scheduled idle time. Note that it can be more than
+  // 16.66 ms when there is currently no rendering going on.
+  static const size_t kMaxScheduledIdleTime = 50;
 
-  // Minimum idle time to start incremental marking.
-  static const size_t kMinIdleTimeToStartIncrementalMarking = 10;
+  // The maximum idle time when frames are rendered is 16.66ms.
+  static const size_t kMaxFrameRenderingIdleTime = 17;
 
-  // 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;
 
@@ -138,6 +138,13 @@ class GCIdleTimeHandler {
   // Incremental marking step time.
   static const size_t kIncrementalMarkingStepTimeInMs = 1;
 
+  static const size_t kMinTimeForOverApproximatingWeakClosureInMs;
+
+  // Number of times we will return a Nothing action per Idle round despite
+  // having idle time available before we returning a Done action to ensure we
+  // don't keep scheduling idle tasks and making no progress.
+  static const int kMaxNoProgressIdleTimesPerIdleRound = 10;
+
   class HeapState {
    public:
     void Print();
@@ -159,7 +166,8 @@ class GCIdleTimeHandler {
 
   GCIdleTimeHandler()
       : mark_compacts_since_idle_round_started_(0),
-        scavenges_since_last_idle_round_(0) {}
+        scavenges_since_last_idle_round_(0),
+        idle_times_which_made_no_progress_since_last_idle_round_(0) {}
 
   GCIdleTimeAction Compute(double idle_time_in_ms, HeapState heap_state);
 
@@ -195,13 +203,20 @@ class GCIdleTimeHandler {
       size_t idle_time_in_ms, size_t size_of_objects,
       size_t final_incremental_mark_compact_speed_in_bytes_per_ms);
 
+  static bool ShouldDoOverApproximateWeakClosure(size_t idle_time_in_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:
-  void StartIdleRound() { mark_compacts_since_idle_round_started_ = 0; }
+  GCIdleTimeAction NothingOrDone();
+
+  void StartIdleRound() {
+    mark_compacts_since_idle_round_started_ = 0;
+    idle_times_which_made_no_progress_since_last_idle_round_ = 0;
+  }
   bool IsMarkCompactIdleRoundFinished() {
     return mark_compacts_since_idle_round_started_ ==
            kMaxMarkCompactsInIdleRound;
@@ -212,6 +227,7 @@ class GCIdleTimeHandler {
 
   int mark_compacts_since_idle_round_started_;
   int scavenges_since_last_idle_round_;
+  int idle_times_which_made_no_progress_since_last_idle_round_;
 
   DISALLOW_COPY_AND_ASSIGN(GCIdleTimeHandler);
 };
index e81829c..f18d089 100644 (file)
@@ -8,7 +8,6 @@
 #include <cmath>
 
 #include "src/base/platform/platform.h"
-#include "src/cpu-profiler.h"
 #include "src/heap/heap.h"
 #include "src/heap/store-buffer.h"
 #include "src/heap/store-buffer-inl.h"
@@ -199,8 +198,6 @@ AllocationResult Heap::AllocateRaw(int size_in_bytes, AllocationSpace space,
     allocation = lo_space_->AllocateRaw(size_in_bytes, NOT_EXECUTABLE);
   } else if (CELL_SPACE == space) {
     allocation = cell_space_->AllocateRaw(size_in_bytes);
-  } else if (PROPERTY_CELL_SPACE == space) {
-    allocation = property_cell_space_->AllocateRaw(size_in_bytes);
   } else {
     DCHECK(MAP_SPACE == space);
     allocation = map_space_->AllocateRaw(size_in_bytes);
@@ -242,13 +239,9 @@ void Heap::OnMoveEvent(HeapObject* target, HeapObject* source,
     heap_profiler->ObjectMoveEvent(source->address(), target->address(),
                                    size_in_bytes);
   }
-
-  if (isolate_->logger()->is_logging_code_events() ||
-      isolate_->cpu_profiler()->is_profiling()) {
-    if (target->IsSharedFunctionInfo()) {
-      PROFILE(isolate_, SharedFunctionInfoMoveEvent(source->address(),
-                                                    target->address()));
-    }
+  if (target->IsSharedFunctionInfo()) {
+    LOG_CODE_EVENT(isolate_, SharedFunctionInfoMoveEvent(source->address(),
+                                                         target->address()));
   }
 
   if (FLAG_verify_predictable) {
@@ -400,7 +393,6 @@ AllocationSpace Heap::TargetSpaceId(InstanceType type) {
   DCHECK(type != CODE_TYPE);
   DCHECK(type != ODDBALL_TYPE);
   DCHECK(type != CELL_TYPE);
-  DCHECK(type != PROPERTY_CELL_TYPE);
 
   if (type <= LAST_NAME_TYPE) {
     if (type == SYMBOL_TYPE) return OLD_POINTER_SPACE;
@@ -448,7 +440,6 @@ bool Heap::AllowedToBeMigrated(HeapObject* obj, AllocationSpace dst) {
       return dst == src && type == CODE_TYPE;
     case MAP_SPACE:
     case CELL_SPACE:
-    case PROPERTY_CELL_SPACE:
     case LO_SPACE:
       return false;
   }
@@ -556,6 +547,8 @@ void Heap::ScavengeObject(HeapObject** p, HeapObject* object) {
   if (first_word.IsForwardingAddress()) {
     HeapObject* dest = first_word.ToForwardingAddress();
     DCHECK(object->GetIsolate()->heap()->InFromSpace(*p));
+    // TODO(jochen): Remove again after fixing http://crbug.com/452095
+    CHECK((*p)->IsHeapObject() && dest->IsHeapObject());
     *p = dest;
     return;
   }
@@ -707,18 +700,12 @@ void Heap::CompletelyClearInstanceofCache() {
 
 AlwaysAllocateScope::AlwaysAllocateScope(Isolate* isolate)
     : heap_(isolate->heap()), daf_(isolate) {
-  // We shouldn't hit any nested scopes, because that requires
-  // non-handle code to call handle code. The code still works but
-  // performance will degrade, so we want to catch this situation
-  // in debug mode.
-  DCHECK(heap_->always_allocate_scope_depth_ == 0);
   heap_->always_allocate_scope_depth_++;
 }
 
 
 AlwaysAllocateScope::~AlwaysAllocateScope() {
   heap_->always_allocate_scope_depth_--;
-  DCHECK(heap_->always_allocate_scope_depth_ == 0);
 }
 
 
index 002b8ce..1570249 100644 (file)
 #include "src/heap/store-buffer.h"
 #include "src/heap-profiler.h"
 #include "src/isolate-inl.h"
-#include "src/natives.h"
 #include "src/runtime-profiler.h"
 #include "src/scopeinfo.h"
-#include "src/serialize.h"
-#include "src/snapshot.h"
+#include "src/snapshot/natives.h"
+#include "src/snapshot/serialize.h"
+#include "src/snapshot/snapshot.h"
 #include "src/utils.h"
 #include "src/v8threads.h"
 #include "src/vm-state-inl.h"
@@ -89,7 +89,6 @@ Heap::Heap()
       code_space_(NULL),
       map_space_(NULL),
       cell_space_(NULL),
-      property_cell_space_(NULL),
       lo_space_(NULL),
       gc_state_(NOT_IN_GC),
       gc_post_processing_depth_(0),
@@ -144,7 +143,10 @@ Heap::Heap()
       external_string_table_(this),
       chunks_queued_for_free_(NULL),
       gc_callbacks_depth_(0),
-      deserialization_complete_(false) {
+      deserialization_complete_(false),
+      concurrent_sweeping_enabled_(false),
+      migration_failure_(false),
+      previous_migration_failure_(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.
@@ -174,18 +176,24 @@ intptr_t Heap::Capacity() {
 
   return new_space_.Capacity() + old_pointer_space_->Capacity() +
          old_data_space_->Capacity() + code_space_->Capacity() +
-         map_space_->Capacity() + cell_space_->Capacity() +
-         property_cell_space_->Capacity();
+         map_space_->Capacity() + cell_space_->Capacity();
 }
 
 
-intptr_t Heap::CommittedMemory() {
+intptr_t Heap::CommittedOldGenerationMemory() {
   if (!HasBeenSetUp()) return 0;
 
-  return new_space_.CommittedMemory() + old_pointer_space_->CommittedMemory() +
+  return old_pointer_space_->CommittedMemory() +
          old_data_space_->CommittedMemory() + code_space_->CommittedMemory() +
          map_space_->CommittedMemory() + cell_space_->CommittedMemory() +
-         property_cell_space_->CommittedMemory() + lo_space_->Size();
+         lo_space_->Size();
+}
+
+
+intptr_t Heap::CommittedMemory() {
+  if (!HasBeenSetUp()) return 0;
+
+  return new_space_.CommittedMemory() + CommittedOldGenerationMemory();
 }
 
 
@@ -198,7 +206,6 @@ size_t Heap::CommittedPhysicalMemory() {
          code_space_->CommittedPhysicalMemory() +
          map_space_->CommittedPhysicalMemory() +
          cell_space_->CommittedPhysicalMemory() +
-         property_cell_space_->CommittedPhysicalMemory() +
          lo_space_->CommittedPhysicalMemory();
 }
 
@@ -225,15 +232,14 @@ intptr_t Heap::Available() {
 
   return new_space_.Available() + old_pointer_space_->Available() +
          old_data_space_->Available() + code_space_->Available() +
-         map_space_->Available() + cell_space_->Available() +
-         property_cell_space_->Available();
+         map_space_->Available() + cell_space_->Available();
 }
 
 
 bool Heap::HasBeenSetUp() {
   return old_pointer_space_ != NULL && old_data_space_ != NULL &&
          code_space_ != NULL && map_space_ != NULL && cell_space_ != NULL &&
-         property_cell_space_ != NULL && lo_space_ != NULL;
+         lo_space_ != NULL;
 }
 
 
@@ -373,14 +379,6 @@ void Heap::PrintShortHeapStatistics() {
            ", committed: %6" V8_PTR_PREFIX "d KB\n",
            cell_space_->SizeOfObjects() / KB, cell_space_->Available() / KB,
            cell_space_->CommittedMemory() / KB);
-  PrintPID("PropertyCell space, used: %6" V8_PTR_PREFIX
-           "d KB"
-           ", available: %6" V8_PTR_PREFIX
-           "d KB"
-           ", committed: %6" V8_PTR_PREFIX "d KB\n",
-           property_cell_space_->SizeOfObjects() / KB,
-           property_cell_space_->Available() / KB,
-           property_cell_space_->CommittedMemory() / KB);
   PrintPID("Large object space, used: %6" V8_PTR_PREFIX
            "d KB"
            ", available: %6" V8_PTR_PREFIX
@@ -669,9 +667,6 @@ void Heap::GarbageCollectionEpilogue() {
     isolate_->counters()->heap_fraction_cell_space()->AddSample(
         static_cast<int>((cell_space()->CommittedMemory() * 100.0) /
                          CommittedMemory()));
-    isolate_->counters()->heap_fraction_property_cell_space()->AddSample(
-        static_cast<int>((property_cell_space()->CommittedMemory() * 100.0) /
-                         CommittedMemory()));
     isolate_->counters()->heap_fraction_lo_space()->AddSample(static_cast<int>(
         (lo_space()->CommittedMemory() * 100.0) / CommittedMemory()));
 
@@ -683,10 +678,6 @@ void Heap::GarbageCollectionEpilogue() {
         static_cast<int>(map_space()->CommittedMemory() / KB));
     isolate_->counters()->heap_sample_cell_space_committed()->AddSample(
         static_cast<int>(cell_space()->CommittedMemory() / KB));
-    isolate_->counters()
-        ->heap_sample_property_cell_space_committed()
-        ->AddSample(
-            static_cast<int>(property_cell_space()->CommittedMemory() / KB));
     isolate_->counters()->heap_sample_code_space_committed()->AddSample(
         static_cast<int>(code_space()->CommittedMemory() / KB));
 
@@ -718,7 +709,6 @@ void Heap::GarbageCollectionEpilogue() {
   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(code_space)
   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(map_space)
   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(cell_space)
-  UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(property_cell_space)
   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(lo_space)
 #undef UPDATE_COUNTERS_FOR_SPACE
 #undef UPDATE_FRAGMENTATION_FOR_SPACE
@@ -731,6 +721,13 @@ void Heap::GarbageCollectionEpilogue() {
   // Remember the last top pointer so that we can later find out
   // whether we allocated in new space since the last GC.
   new_space_top_after_last_gc_ = new_space()->top();
+
+  if (migration_failure_) {
+    set_previous_migration_failure(true);
+  } else {
+    set_previous_migration_failure(false);
+  }
+  set_migration_failure(false);
 }
 
 
@@ -741,8 +738,9 @@ void Heap::HandleGCRequest() {
     return;
   }
   DCHECK(FLAG_overapproximate_weak_closure);
-  DCHECK(!incremental_marking()->weak_closure_was_overapproximated());
-  OverApproximateWeakClosure("GC interrupt");
+  if (!incremental_marking()->weak_closure_was_overapproximated()) {
+    OverApproximateWeakClosure("GC interrupt");
+  }
 }
 
 
@@ -751,6 +749,10 @@ void Heap::OverApproximateWeakClosure(const char* gc_reason) {
     PrintF("[IncrementalMarking] Overapproximate weak closure (%s).\n",
            gc_reason);
   }
+
+  GCTracer::Scope gc_scope(tracer(),
+                           GCTracer::Scope::MC_INCREMENTAL_WEAKCLOSURE);
+
   {
     GCCallbacksScope scope(this);
     if (scope.CheckReenter()) {
@@ -761,9 +763,7 @@ void Heap::OverApproximateWeakClosure(const char* gc_reason) {
       CallGCPrologueCallbacks(kGCTypeMarkSweepCompact, kNoGCCallbackFlags);
     }
   }
-  mark_compact_collector()->OverApproximateWeakClosure();
-  incremental_marking()->set_should_hurry(false);
-  incremental_marking()->set_weak_closure_was_overapproximated(true);
+  incremental_marking()->MarkObjectGroups();
   {
     GCCallbacksScope scope(this);
     if (scope.CheckReenter()) {
@@ -805,6 +805,7 @@ void Heap::CollectAllAvailableGarbage(const char* gc_reason) {
     DisallowHeapAllocation no_recursive_gc;
     isolate()->optimizing_compiler_thread()->Flush();
   }
+  isolate()->ClearSerializerData();
   mark_compact_collector()->SetFlags(kMakeHeapIterableMask |
                                      kReduceMemoryFootprintMask);
   isolate_->compilation_cache()->Clear();
@@ -829,10 +830,14 @@ void Heap::EnsureFillerObjectAtTop() {
   // pointer of the new space page. We store a filler object there to
   // identify the unused space.
   Address from_top = new_space_.top();
-  Address from_limit = new_space_.limit();
-  if (from_top < from_limit) {
-    int remaining_in_page = static_cast<int>(from_limit - from_top);
-    CreateFillerObjectAt(from_top, remaining_in_page);
+  // Check that from_top is inside its page (i.e., not at the end).
+  Address space_end = new_space_.ToSpaceEnd();
+  if (from_top < space_end) {
+    Page* page = Page::FromAddress(from_top);
+    if (page->Contains(from_top)) {
+      int remaining_in_page = static_cast<int>(page->area_end() - from_top);
+      CreateFillerObjectAt(from_top, remaining_in_page);
+    }
   }
 }
 
@@ -923,6 +928,7 @@ int Heap::NotifyContextDisposed(bool dependant_context) {
     isolate()->optimizing_compiler_thread()->Flush();
   }
   AgeInlineCaches();
+  set_retained_maps(ArrayList::cast(empty_fixed_array()));
   tracer()->AddContextDisposalTime(base::OS::TimeCurrentMillis());
   return ++contexts_disposed_;
 }
@@ -1365,10 +1371,10 @@ static void VerifyNonPointerSpacePointers(Heap* heap) {
        object = code_it.Next())
     object->Iterate(&v);
 
-    HeapObjectIterator data_it(heap->old_data_space());
-    for (HeapObject* object = data_it.Next(); object != NULL;
-         object = data_it.Next())
-      object->Iterate(&v);
+  HeapObjectIterator data_it(heap->old_data_space());
+  for (HeapObject* object = data_it.Next(); object != NULL;
+       object = data_it.Next())
+    object->Iterate(&v);
 }
 #endif  // VERIFY_HEAP
 
@@ -1515,6 +1521,10 @@ class ScavengeWeakObjectRetainer : public WeakObjectRetainer {
 
 void Heap::Scavenge() {
   RelocationLock relocation_lock(this);
+  // There are soft limits in the allocation code, designed to trigger a mark
+  // sweep collection by failing allocations. There is no sense in trying to
+  // trigger one during scavenge: scavenges allocation should always succeed.
+  AlwaysAllocateScope scope(isolate());
 
 #ifdef VERIFY_HEAP
   if (FLAG_verify_heap) VerifyNonPointerSpacePointers(this);
@@ -1560,10 +1570,6 @@ void Heap::Scavenge() {
   Address new_space_front = new_space_.ToSpaceStart();
   promotion_queue_.Initialize();
 
-#ifdef DEBUG
-  store_buffer()->Clean();
-#endif
-
   ScavengeVisitor scavenge_visitor(this);
   // Copy roots.
   IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE);
@@ -1587,21 +1593,6 @@ void Heap::Scavenge() {
     }
   }
 
-  // Copy objects reachable from global property cells by scavenging global
-  // property cell values directly.
-  HeapObjectIterator js_global_property_cell_iterator(property_cell_space_);
-  for (HeapObject* heap_object = js_global_property_cell_iterator.Next();
-       heap_object != NULL;
-       heap_object = js_global_property_cell_iterator.Next()) {
-    if (heap_object->IsPropertyCell()) {
-      PropertyCell* cell = PropertyCell::cast(heap_object);
-      Address value_address = cell->ValueAddress();
-      scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
-      Address type_address = cell->TypeAddress();
-      scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(type_address));
-    }
-  }
-
   // Copy objects reachable from the encountered weak collections list.
   scavenge_visitor.VisitPointer(&encountered_weak_collections_);
   // Copy objects reachable from the encountered weak cells.
@@ -1730,29 +1721,63 @@ void Heap::UpdateReferencesInExternalStringTable(
 
 
 void Heap::ProcessAllWeakReferences(WeakObjectRetainer* retainer) {
-  ProcessArrayBuffers(retainer);
+  ProcessArrayBuffers(retainer, false);
+  ProcessNewArrayBufferViews(retainer);
   ProcessNativeContexts(retainer);
   ProcessAllocationSites(retainer);
 }
 
 
 void Heap::ProcessYoungWeakReferences(WeakObjectRetainer* retainer) {
-  ProcessArrayBuffers(retainer);
+  ProcessArrayBuffers(retainer, true);
+  ProcessNewArrayBufferViews(retainer);
   ProcessNativeContexts(retainer);
 }
 
 
 void Heap::ProcessNativeContexts(WeakObjectRetainer* retainer) {
-  Object* head = VisitWeakList<Context>(this, native_contexts_list(), retainer);
+  Object* head =
+      VisitWeakList<Context>(this, native_contexts_list(), retainer, false);
   // Update the head of the list of contexts.
   set_native_contexts_list(head);
 }
 
 
-void Heap::ProcessArrayBuffers(WeakObjectRetainer* retainer) {
-  Object* array_buffer_obj =
-      VisitWeakList<JSArrayBuffer>(this, array_buffers_list(), retainer);
+void Heap::ProcessArrayBuffers(WeakObjectRetainer* retainer,
+                               bool stop_after_young) {
+  Object* array_buffer_obj = VisitWeakList<JSArrayBuffer>(
+      this, array_buffers_list(), retainer, stop_after_young);
   set_array_buffers_list(array_buffer_obj);
+
+#ifdef DEBUG
+  // Verify invariant that young array buffers come before old array buffers
+  // in array buffers list if there was no promotion failure.
+  Object* undefined = undefined_value();
+  Object* next = array_buffers_list();
+  bool old_objects_recorded = false;
+  if (migration_failure()) return;
+  while (next != undefined) {
+    if (!old_objects_recorded) {
+      old_objects_recorded = !InNewSpace(next);
+    }
+    DCHECK((InNewSpace(next) && !old_objects_recorded) || !InNewSpace(next));
+    next = JSArrayBuffer::cast(next)->weak_next();
+  }
+#endif
+}
+
+
+void Heap::ProcessNewArrayBufferViews(WeakObjectRetainer* retainer) {
+  // Retain the list of new space views.
+  Object* typed_array_obj = VisitWeakList<JSArrayBufferView>(
+      this, new_array_buffer_views_list_, retainer, false);
+  set_new_array_buffer_views_list(typed_array_obj);
+
+  // Some objects in the list may be in old space now. Find them
+  // and move them to the corresponding array buffer.
+  Object* view = VisitNewArrayBufferViewsWeakList(
+      this, new_array_buffer_views_list_, retainer);
+  set_new_array_buffer_views_list(view);
 }
 
 
@@ -1768,8 +1793,8 @@ void Heap::TearDownArrayBuffers() {
 
 
 void Heap::ProcessAllocationSites(WeakObjectRetainer* retainer) {
-  Object* allocation_site_obj =
-      VisitWeakList<AllocationSite>(this, allocation_sites_list(), retainer);
+  Object* allocation_site_obj = VisitWeakList<AllocationSite>(
+      this, allocation_sites_list(), retainer, false);
   set_allocation_sites_list(allocation_site_obj);
 }
 
@@ -1883,6 +1908,18 @@ Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
         // to new space.
         DCHECK(!target->IsMap());
         Address obj_address = target->address();
+
+        // We are not collecting slots on new space objects during mutation
+        // thus we have to scan for pointers to evacuation candidates when we
+        // promote objects. But we should not record any slots in non-black
+        // objects. Grey object's slots would be rescanned.
+        // White object might not survive until the end of collection
+        // it would be a violation of the invariant to record it's slots.
+        bool record_slots = false;
+        if (incremental_marking()->IsCompacting()) {
+          MarkBit mark_bit = Marking::MarkBitFrom(target);
+          record_slots = Marking::IsBlack(mark_bit);
+        }
 #if V8_DOUBLE_FIELDS_UNBOXING
         LayoutDescriptorHelper helper(target->map());
         bool has_only_tagged_fields = helper.all_fields_tagged();
@@ -1892,15 +1929,15 @@ Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
             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);
+                  record_slots, obj_address + offset,
+                  obj_address + end_of_region_offset, &ScavengeObject);
             }
             offset = end_of_region_offset;
           }
         } else {
 #endif
-          IterateAndMarkPointersToFromSpace(obj_address, obj_address + size,
-                                            &ScavengeObject);
+          IterateAndMarkPointersToFromSpace(
+              record_slots, obj_address, obj_address + size, &ScavengeObject);
 #if V8_DOUBLE_FIELDS_UNBOXING
         }
 #endif
@@ -2111,12 +2148,10 @@ class ScavengingVisitor : public StaticVisitorBase {
       if (alignment != kObjectAlignment) {
         target = EnsureDoubleAligned(heap, target, allocation_size);
       }
+      MigrateObject(heap, object, target, object_size);
 
-      // 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.
+      // Update slot to new target.
       *slot = target;
-      MigrateObject(heap, object, target, object_size);
 
       heap->IncrementSemiSpaceCopiedObjectSize(object_size);
       return true;
@@ -2150,23 +2185,11 @@ class ScavengingVisitor : public StaticVisitorBase {
       if (alignment != kObjectAlignment) {
         target = EnsureDoubleAligned(heap, target, allocation_size);
       }
-
-      // 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.
-
-      // 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);
 
+      // Update slot to new target.
+      *slot = target;
+
       if (object_contents == POINTER_OBJECT) {
         if (map->instance_type() == JS_FUNCTION_TYPE) {
           heap->promotion_queue()->insert(target,
@@ -2195,6 +2218,7 @@ class ScavengingVisitor : public StaticVisitorBase {
       if (SemiSpaceCopyObject<alignment>(map, slot, object, object_size)) {
         return;
       }
+      heap->set_migration_failure(true);
     }
 
     if (PromoteObject<object_contents, alignment>(map, slot, object,
@@ -2409,6 +2433,8 @@ void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
   MapWord first_word = object->map_word();
   SLOW_DCHECK(!first_word.IsForwardingAddress());
   Map* map = first_word.ToMap();
+  // TODO(jochen): Remove again after fixing http://crbug.com/452095
+  CHECK((*p)->IsHeapObject() == object->IsHeapObject());
   map->GetHeap()->DoScavengeObject(map, p, object);
 }
 
@@ -2450,6 +2476,7 @@ AllocationResult Heap::AllocatePartialMap(InstanceType instance_type,
                    Map::OwnsDescriptors::encode(true) |
                    Map::Counter::encode(Map::kRetainingCounterStart);
   reinterpret_cast<Map*>(result)->set_bit_field3(bit_field3);
+  reinterpret_cast<Map*>(result)->set_weak_cell_cache(Smi::FromInt(0));
   return result;
 }
 
@@ -2465,14 +2492,15 @@ AllocationResult Heap::AllocateMap(InstanceType instance_type,
   Map* map = Map::cast(result);
   map->set_instance_type(instance_type);
   map->set_prototype(null_value(), SKIP_WRITE_BARRIER);
-  map->set_constructor(null_value(), SKIP_WRITE_BARRIER);
+  map->set_constructor_or_backpointer(null_value(), SKIP_WRITE_BARRIER);
   map->set_instance_size(instance_size);
   map->set_inobject_properties(0);
   map->set_pre_allocated_property_fields(0);
   map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
   map->set_dependent_code(DependentCode::cast(empty_fixed_array()),
                           SKIP_WRITE_BARRIER);
-  map->init_back_pointer(undefined_value());
+  map->set_weak_cell_cache(Smi::FromInt(0));
+  map->set_raw_transitions(Smi::FromInt(0));
   map->set_unused_property_fields(0);
   map->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
@@ -2606,7 +2634,7 @@ bool Heap::CreateInitialMaps() {
   // Fix the instance_descriptors for the existing maps.
   meta_map()->set_code_cache(empty_fixed_array());
   meta_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
-  meta_map()->init_back_pointer(undefined_value());
+  meta_map()->set_raw_transitions(Smi::FromInt(0));
   meta_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     meta_map()->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
@@ -2615,7 +2643,7 @@ bool Heap::CreateInitialMaps() {
   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_raw_transitions(Smi::FromInt(0));
   fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     fixed_array_map()->set_layout_descriptor(
@@ -2624,7 +2652,7 @@ bool Heap::CreateInitialMaps() {
 
   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_raw_transitions(Smi::FromInt(0));
   undefined_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     undefined_map()->set_layout_descriptor(
@@ -2633,7 +2661,7 @@ bool Heap::CreateInitialMaps() {
 
   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_raw_transitions(Smi::FromInt(0));
   null_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     null_map()->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
@@ -2642,7 +2670,7 @@ bool Heap::CreateInitialMaps() {
   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_raw_transitions(Smi::FromInt(0));
   constant_pool_array_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     constant_pool_array_map()->set_layout_descriptor(
@@ -2651,19 +2679,19 @@ bool Heap::CreateInitialMaps() {
 
   // Fix prototype object for existing maps.
   meta_map()->set_prototype(null_value());
-  meta_map()->set_constructor(null_value());
+  meta_map()->set_constructor_or_backpointer(null_value());
 
   fixed_array_map()->set_prototype(null_value());
-  fixed_array_map()->set_constructor(null_value());
+  fixed_array_map()->set_constructor_or_backpointer(null_value());
 
   undefined_map()->set_prototype(null_value());
-  undefined_map()->set_constructor(null_value());
+  undefined_map()->set_constructor_or_backpointer(null_value());
 
   null_map()->set_prototype(null_value());
-  null_map()->set_constructor(null_value());
+  null_map()->set_constructor_or_backpointer(null_value());
 
   constant_pool_array_map()->set_prototype(null_value());
-  constant_pool_array_map()->set_constructor(null_value());
+  constant_pool_array_map()->set_constructor_or_backpointer(null_value());
 
   {  // Map allocation
 #define ALLOCATE_MAP(instance_type, size, field_name)               \
@@ -2852,7 +2880,7 @@ AllocationResult Heap::AllocatePropertyCell() {
 
   HeapObject* result;
   AllocationResult allocation =
-      AllocateRaw(size, PROPERTY_CELL_SPACE, PROPERTY_CELL_SPACE);
+      AllocateRaw(size, OLD_POINTER_SPACE, OLD_POINTER_SPACE);
   if (!allocation.To(&result)) return allocation;
 
   result->set_map_no_write_barrier(global_property_cell_map());
@@ -2860,7 +2888,6 @@ AllocationResult Heap::AllocatePropertyCell() {
   cell->set_dependent_code(DependentCode::cast(empty_fixed_array()),
                            SKIP_WRITE_BARRIER);
   cell->set_value(the_hole_value());
-  cell->set_type(HeapType::None());
   return result;
 }
 
@@ -2868,7 +2895,7 @@ AllocationResult Heap::AllocatePropertyCell() {
 AllocationResult Heap::AllocateWeakCell(HeapObject* value) {
   int size = WeakCell::kSize;
   STATIC_ASSERT(WeakCell::kSize <= Page::kMaxRegularHeapObjectSize);
-  HeapObject* result;
+  HeapObject* result = NULL;
   {
     AllocationResult allocation =
         AllocateRaw(size, OLD_POINTER_SPACE, OLD_POINTER_SPACE);
@@ -3093,10 +3120,9 @@ void Heap::CreateInitialObjects() {
   set_microtask_queue(empty_fixed_array());
 
   if (FLAG_vector_ics) {
-    FeedbackVectorSpec spec(0, 1);
-    spec.SetKind(0, Code::KEYED_LOAD_IC);
+    FeedbackVectorSpec spec(0, Code::KEYED_LOAD_IC);
     Handle<TypeFeedbackVector> dummy_vector =
-        factory->NewTypeFeedbackVector(spec);
+        factory->NewTypeFeedbackVector(&spec);
     dummy_vector->Set(FeedbackVectorICSlot(0),
                       *TypeFeedbackVector::MegamorphicSentinel(isolate()),
                       SKIP_WRITE_BARRIER);
@@ -3106,6 +3132,7 @@ void Heap::CreateInitialObjects() {
   }
 
   set_detached_contexts(empty_fixed_array());
+  set_retained_maps(ArrayList::cast(empty_fixed_array()));
 
   set_weak_object_to_code_table(
       *WeakHashTable::New(isolate(), 16, USE_DEFAULT_MINIMUM_CAPACITY,
@@ -3140,30 +3167,34 @@ void Heap::CreateInitialObjects() {
 
 
 bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
-  RootListIndex writable_roots[] = {
-      kStoreBufferTopRootIndex,
-      kStackLimitRootIndex,
-      kNumberStringCacheRootIndex,
-      kInstanceofCacheFunctionRootIndex,
-      kInstanceofCacheMapRootIndex,
-      kInstanceofCacheAnswerRootIndex,
-      kCodeStubsRootIndex,
-      kNonMonomorphicCacheRootIndex,
-      kPolymorphicCodeCacheRootIndex,
-      kLastScriptIdRootIndex,
-      kEmptyScriptRootIndex,
-      kRealStackLimitRootIndex,
-      kArgumentsAdaptorDeoptPCOffsetRootIndex,
-      kConstructStubDeoptPCOffsetRootIndex,
-      kGetterStubDeoptPCOffsetRootIndex,
-      kSetterStubDeoptPCOffsetRootIndex,
-      kStringTableRootIndex,
-  };
+  switch (root_index) {
+    case kStoreBufferTopRootIndex:
+    case kNumberStringCacheRootIndex:
+    case kInstanceofCacheFunctionRootIndex:
+    case kInstanceofCacheMapRootIndex:
+    case kInstanceofCacheAnswerRootIndex:
+    case kCodeStubsRootIndex:
+    case kNonMonomorphicCacheRootIndex:
+    case kPolymorphicCodeCacheRootIndex:
+    case kEmptyScriptRootIndex:
+    case kSymbolRegistryRootIndex:
+    case kMaterializedObjectsRootIndex:
+    case kAllocationSitesScratchpadRootIndex:
+    case kMicrotaskQueueRootIndex:
+    case kDetachedContextsRootIndex:
+    case kWeakObjectToCodeTableRootIndex:
+    case kRetainedMapsRootIndex:
+// Smi values
+#define SMI_ENTRY(type, name, Name) case k##Name##RootIndex:
+      SMI_ROOT_LIST(SMI_ENTRY)
+#undef SMI_ENTRY
+    // String table
+    case kStringTableRootIndex:
+      return true;
 
-  for (unsigned int i = 0; i < arraysize(writable_roots); i++) {
-    if (root_index == writable_roots[i]) return true;
+    default:
+      return false;
   }
-  return false;
 }
 
 
@@ -3500,6 +3531,7 @@ void Heap::AdjustLiveBytes(Address address, int by, InvocationMode mode) {
 
 FixedArrayBase* Heap::LeftTrimFixedArray(FixedArrayBase* object,
                                          int elements_to_trim) {
+  DCHECK(!object->IsFixedTypedArrayBase());
   const int element_size = object->IsFixedArray() ? kPointerSize : kDoubleSize;
   const int bytes_to_trim = elements_to_trim * element_size;
   Map* map = object->map();
@@ -3555,14 +3587,30 @@ void Heap::RightTrimFixedArray<Heap::FROM_MUTATOR>(FixedArrayBase*, int);
 
 template<Heap::InvocationMode mode>
 void Heap::RightTrimFixedArray(FixedArrayBase* object, int elements_to_trim) {
-  const int element_size = object->IsFixedArray() ? kPointerSize : kDoubleSize;
-  const int bytes_to_trim = elements_to_trim * element_size;
+  const int len = object->length();
+  DCHECK(elements_to_trim < len);
+
+  int bytes_to_trim;
+  if (object->IsFixedTypedArrayBase()) {
+    InstanceType type = object->map()->instance_type();
+    bytes_to_trim =
+        FixedTypedArrayBase::TypedArraySize(type, len) -
+        FixedTypedArrayBase::TypedArraySize(type, len - elements_to_trim);
+  } else {
+    const int element_size =
+        object->IsFixedArray() ? kPointerSize : kDoubleSize;
+    bytes_to_trim = elements_to_trim * element_size;
+  }
 
   // For now this trick is only applied to objects in new and paged space.
   DCHECK(object->map() != fixed_cow_array_map());
 
-  const int len = object->length();
-  DCHECK(elements_to_trim < len);
+  if (bytes_to_trim == 0) {
+    // No need to create filler and update live bytes counters, just initialize
+    // header of the trimmed array.
+    object->synchronized_set_length(len - elements_to_trim);
+    return;
+  }
 
   // Calculate location of new array end.
   Address new_end = object->address() + object->Size() - bytes_to_trim;
@@ -3710,7 +3758,7 @@ AllocationResult Heap::CopyCode(Code* code) {
     new_constant_pool = empty_constant_pool_array();
   }
 
-  HeapObject* result;
+  HeapObject* result = NULL;
   // Allocate an object the same size as the code object.
   int obj_size = code->Size();
   allocation = AllocateRaw(obj_size, CODE_SPACE, CODE_SPACE);
@@ -3850,9 +3898,9 @@ void Heap::InitializeJSObjectFromMap(JSObject* obj, FixedArray* properties,
   // Pre-allocated fields need to be initialized with undefined_value as well
   // so that object accesses before the constructor completes (e.g. in the
   // debugger) will not cause a crash.
-  if (map->constructor()->IsJSFunction() &&
-      JSFunction::cast(map->constructor())
-          ->IsInobjectSlackTrackingInProgress()) {
+  Object* constructor = map->GetConstructor();
+  if (constructor->IsJSFunction() &&
+      JSFunction::cast(constructor)->IsInobjectSlackTrackingInProgress()) {
     // We might want to shrink the object later.
     DCHECK(obj->GetInternalFieldCount() == 0);
     filler = Heap::one_pointer_filler_map();
@@ -4439,7 +4487,7 @@ AllocationResult Heap::AllocateExtendedConstantPoolArray(
 AllocationResult Heap::AllocateEmptyConstantPoolArray() {
   ConstantPoolArray::NumberOfEntries small(0, 0, 0, 0);
   int size = ConstantPoolArray::SizeFor(small);
-  HeapObject* result;
+  HeapObject* result = NULL;
   {
     AllocationResult allocation =
         AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
@@ -4455,7 +4503,7 @@ AllocationResult Heap::AllocateSymbol() {
   // Statically ensure that it is safe to allocate symbols in paged spaces.
   STATIC_ASSERT(Symbol::kSize <= Page::kMaxRegularHeapObjectSize);
 
-  HeapObject* result;
+  HeapObject* result = NULL;
   AllocationResult allocation =
       AllocateRaw(Symbol::kSize, OLD_POINTER_SPACE, OLD_POINTER_SPACE);
   if (!allocation.To(&result)) return allocation;
@@ -4545,11 +4593,20 @@ void Heap::IdleMarkCompact(const char* message) {
 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))) {
+  if (FLAG_overapproximate_weak_closure &&
+      (incremental_marking()->IsReadyToOverApproximateWeakClosure() ||
+       (!incremental_marking()->weak_closure_was_overapproximated() &&
+        mark_compact_collector_.marking_deque()->IsEmpty() &&
+        gc_idle_time_handler_.ShouldDoOverApproximateWeakClosure(
+            static_cast<size_t>(idle_time_in_ms))))) {
+    OverApproximateWeakClosure(
+        "Idle notification: overapproximate weak closure");
+    return true;
+  } else 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;
   }
@@ -4595,13 +4652,14 @@ bool Heap::IdleNotification(double deadline_in_seconds) {
   // TODO(ulan): Start incremental marking only for large heaps.
   intptr_t limit = old_generation_allocation_limit_;
   if (static_cast<size_t>(idle_time_in_ms) >
-      GCIdleTimeHandler::kMinIdleTimeToStartIncrementalMarking) {
+      GCIdleTimeHandler::kMaxFrameRenderingIdleTime) {
     limit = idle_old_generation_allocation_limit_;
   }
 
   heap_state.can_start_incremental_marking =
       incremental_marking()->WorthActivating() &&
-      NextGCIsLikelyToBeFull(limit) && FLAG_incremental_marking;
+      NextGCIsLikelyToBeFull(limit) && FLAG_incremental_marking &&
+      !mark_compact_collector()->sweeping_in_progress();
   heap_state.sweeping_in_progress =
       mark_compact_collector()->sweeping_in_progress();
   heap_state.mark_compact_speed_in_bytes_per_ms =
@@ -4689,6 +4747,7 @@ bool Heap::IdleNotification(double deadline_in_seconds) {
 
   if ((FLAG_trace_idle_notification && action.type > DO_NOTHING) ||
       FLAG_trace_idle_notification_verbose) {
+    PrintPID("%8.0f ms: ", isolate()->time_millis_since_init());
     PrintF(
         "Idle notification: requested idle time %.2f ms, used idle time %.2f "
         "ms, deadline usage %.2f ms [",
@@ -4711,7 +4770,7 @@ bool Heap::IdleNotification(double deadline_in_seconds) {
 
 bool Heap::RecentIdleNotificationHappened() {
   return (last_idle_notification_time_ +
-          GCIdleTimeHandler::kMaxFrameRenderingIdleTime) >
+          GCIdleTimeHandler::kMaxScheduledIdleTime) >
          MonotonicallyIncreasingTimeInMs();
 }
 
@@ -4768,8 +4827,6 @@ void Heap::ReportHeapStatistics(const char* title) {
   map_space_->ReportStatistics();
   PrintF("Cell space : ");
   cell_space_->ReportStatistics();
-  PrintF("PropertyCell space : ");
-  property_cell_space_->ReportStatistics();
   PrintF("Large object space : ");
   lo_space_->ReportStatistics();
   PrintF(">>>>>> ========================================= >>>>>>\n");
@@ -4787,7 +4844,6 @@ bool Heap::Contains(Address addr) {
           old_pointer_space_->Contains(addr) ||
           old_data_space_->Contains(addr) || code_space_->Contains(addr) ||
           map_space_->Contains(addr) || cell_space_->Contains(addr) ||
-          property_cell_space_->Contains(addr) ||
           lo_space_->SlowContains(addr));
 }
 
@@ -4814,8 +4870,6 @@ bool Heap::InSpace(Address addr, AllocationSpace space) {
       return map_space_->Contains(addr);
     case CELL_SPACE:
       return cell_space_->Contains(addr);
-    case PROPERTY_CELL_SPACE:
-      return property_cell_space_->Contains(addr);
     case LO_SPACE:
       return lo_space_->SlowContains(addr);
   }
@@ -4864,7 +4918,6 @@ void Heap::Verify() {
   old_data_space_->Verify(&no_dirty_regions_visitor);
   code_space_->Verify(&no_dirty_regions_visitor);
   cell_space_->Verify(&no_dirty_regions_visitor);
-  property_cell_space_->Verify(&no_dirty_regions_visitor);
 
   lo_space_->Verify();
 }
@@ -4884,22 +4937,11 @@ void Heap::ZapFromSpace() {
 }
 
 
-void Heap::IterateAndMarkPointersToFromSpace(Address start, Address end,
+void Heap::IterateAndMarkPointersToFromSpace(bool record_slots, Address start,
+                                             Address end,
                                              ObjectSlotCallback callback) {
   Address slot_address = start;
 
-  // We are not collecting slots on new space objects during mutation
-  // thus we have to scan for pointers to evacuation candidates when we
-  // promote objects. But we should not record any slots in non-black
-  // objects. Grey object's slots would be rescanned.
-  // White object might not survive until the end of collection
-  // it would be a violation of the invariant to record it's slots.
-  bool record_slots = false;
-  if (incremental_marking()->IsCompacting()) {
-    MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::FromAddress(start));
-    record_slots = Marking::IsBlack(mark_bit);
-  }
-
   while (slot_address < end) {
     Object** slot = reinterpret_cast<Object**>(slot_address);
     Object* object = *slot;
@@ -4929,143 +4971,6 @@ void Heap::IterateAndMarkPointersToFromSpace(Address start, Address end,
 }
 
 
-#ifdef DEBUG
-typedef bool (*CheckStoreBufferFilter)(Object** addr);
-
-
-bool IsAMapPointerAddress(Object** addr) {
-  uintptr_t a = reinterpret_cast<uintptr_t>(addr);
-  int mod = a % Map::kSize;
-  return mod >= Map::kPointerFieldsBeginOffset &&
-         mod < Map::kPointerFieldsEndOffset;
-}
-
-
-bool EverythingsAPointer(Object** addr) { return true; }
-
-
-static void CheckStoreBuffer(Heap* heap, Object** current, Object** limit,
-                             Object**** store_buffer_position,
-                             Object*** store_buffer_top,
-                             CheckStoreBufferFilter filter,
-                             Address special_garbage_start,
-                             Address special_garbage_end) {
-  Map* free_space_map = heap->free_space_map();
-  for (; current < limit; current++) {
-    Object* o = *current;
-    Address current_address = reinterpret_cast<Address>(current);
-    // Skip free space.
-    if (o == free_space_map) {
-      Address current_address = reinterpret_cast<Address>(current);
-      FreeSpace* free_space =
-          FreeSpace::cast(HeapObject::FromAddress(current_address));
-      int skip = free_space->Size();
-      DCHECK(current_address + skip <= reinterpret_cast<Address>(limit));
-      DCHECK(skip > 0);
-      current_address += skip - kPointerSize;
-      current = reinterpret_cast<Object**>(current_address);
-      continue;
-    }
-    // Skip the current linear allocation space between top and limit which is
-    // unmarked with the free space map, but can contain junk.
-    if (current_address == special_garbage_start &&
-        special_garbage_end != special_garbage_start) {
-      current_address = special_garbage_end - kPointerSize;
-      current = reinterpret_cast<Object**>(current_address);
-      continue;
-    }
-    if (!(*filter)(current)) continue;
-    DCHECK(current_address < special_garbage_start ||
-           current_address >= special_garbage_end);
-    DCHECK(reinterpret_cast<uintptr_t>(o) != kFreeListZapValue);
-    // We have to check that the pointer does not point into new space
-    // without trying to cast it to a heap object since the hash field of
-    // a string can contain values like 1 and 3 which are tagged null
-    // pointers.
-    if (!heap->InNewSpace(o)) continue;
-    while (**store_buffer_position < current &&
-           *store_buffer_position < store_buffer_top) {
-      (*store_buffer_position)++;
-    }
-    if (**store_buffer_position != current ||
-        *store_buffer_position == store_buffer_top) {
-      Object** obj_start = current;
-      while (!(*obj_start)->IsMap()) obj_start--;
-      UNREACHABLE();
-    }
-  }
-}
-
-
-// Check that the store buffer contains all intergenerational pointers by
-// scanning a page and ensuring that all pointers to young space are in the
-// store buffer.
-void Heap::OldPointerSpaceCheckStoreBuffer() {
-  OldSpace* space = old_pointer_space();
-  PageIterator pages(space);
-
-  store_buffer()->SortUniq();
-
-  while (pages.has_next()) {
-    Page* page = pages.next();
-    Object** current = reinterpret_cast<Object**>(page->area_start());
-
-    Address end = page->area_end();
-
-    Object*** store_buffer_position = store_buffer()->Start();
-    Object*** store_buffer_top = store_buffer()->Top();
-
-    Object** limit = reinterpret_cast<Object**>(end);
-    CheckStoreBuffer(this, current, limit, &store_buffer_position,
-                     store_buffer_top, &EverythingsAPointer, space->top(),
-                     space->limit());
-  }
-}
-
-
-void Heap::MapSpaceCheckStoreBuffer() {
-  MapSpace* space = map_space();
-  PageIterator pages(space);
-
-  store_buffer()->SortUniq();
-
-  while (pages.has_next()) {
-    Page* page = pages.next();
-    Object** current = reinterpret_cast<Object**>(page->area_start());
-
-    Address end = page->area_end();
-
-    Object*** store_buffer_position = store_buffer()->Start();
-    Object*** store_buffer_top = store_buffer()->Top();
-
-    Object** limit = reinterpret_cast<Object**>(end);
-    CheckStoreBuffer(this, current, limit, &store_buffer_position,
-                     store_buffer_top, &IsAMapPointerAddress, space->top(),
-                     space->limit());
-  }
-}
-
-
-void Heap::LargeObjectSpaceCheckStoreBuffer() {
-  LargeObjectIterator it(lo_space());
-  for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
-    // We only have code, sequential strings, or fixed arrays in large
-    // object space, and only fixed arrays can possibly contain pointers to
-    // the young generation.
-    if (object->IsFixedArray()) {
-      Object*** store_buffer_position = store_buffer()->Start();
-      Object*** store_buffer_top = store_buffer()->Top();
-      Object** current = reinterpret_cast<Object**>(object->address());
-      Object** limit =
-          reinterpret_cast<Object**>(object->address() + object->Size());
-      CheckStoreBuffer(this, current, limit, &store_buffer_position,
-                       store_buffer_top, &EverythingsAPointer, NULL, NULL);
-    }
-  }
-}
-#endif
-
-
 void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) {
   IterateStrongRoots(v, mode);
   IterateWeakRoots(v, mode);
@@ -5203,7 +5108,7 @@ bool Heap::ConfigureHeap(int max_semi_space_size, int max_old_space_size,
     max_semi_space_size_ = Page::kPageSize;
   }
 
-  if (Snapshot::HaveASnapshotToStartFrom()) {
+  if (isolate()->snapshot_available()) {
     // If we are using a snapshot we always reserve the default amount
     // of memory for each semispace because code in the snapshot has
     // write-barrier code that relies on the size and alignment of new
@@ -5326,8 +5231,6 @@ void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
   *stats->map_space_capacity = map_space_->Capacity();
   *stats->cell_space_size = cell_space_->SizeOfObjects();
   *stats->cell_space_capacity = cell_space_->Capacity();
-  *stats->property_cell_space_size = property_cell_space_->SizeOfObjects();
-  *stats->property_cell_space_capacity = property_cell_space_->Capacity();
   *stats->lo_space_size = lo_space_->Size();
   isolate_->global_handles()->RecordStats(stats);
   *stats->memory_allocator_size = isolate()->memory_allocator()->Size();
@@ -5353,7 +5256,7 @@ intptr_t Heap::PromotedSpaceSizeOfObjects() {
   return old_pointer_space_->SizeOfObjects() +
          old_data_space_->SizeOfObjects() + code_space_->SizeOfObjects() +
          map_space_->SizeOfObjects() + cell_space_->SizeOfObjects() +
-         property_cell_space_->SizeOfObjects() + lo_space_->SizeOfObjects();
+         lo_space_->SizeOfObjects();
 }
 
 
@@ -5473,6 +5376,9 @@ bool Heap::SetUp() {
     if (!ConfigureHeapDefault()) return false;
   }
 
+  concurrent_sweeping_enabled_ =
+      FLAG_concurrent_sweeping && isolate_->max_available_threads() > 1;
+
   base::CallOnce(&initialize_gc_once, &InitializeGCOnce);
 
   MarkMapPointersAsEncoded(false);
@@ -5518,12 +5424,6 @@ bool Heap::SetUp() {
   if (cell_space_ == NULL) return false;
   if (!cell_space_->SetUp()) return false;
 
-  // Initialize global property cell space.
-  property_cell_space_ = new PropertyCellSpace(this, max_old_generation_size_,
-                                               PROPERTY_CELL_SPACE);
-  if (property_cell_space_ == NULL) return false;
-  if (!property_cell_space_->SetUp()) return false;
-
   // The large object code space may contain code or data.  We set the memory
   // to be non-executable here for safety, but this means we need to enable it
   // explicitly when allocating large code objects.
@@ -5564,6 +5464,7 @@ bool Heap::CreateHeapObjects() {
 
   set_native_contexts_list(undefined_value());
   set_array_buffers_list(undefined_value());
+  set_new_array_buffer_views_list(undefined_value());
   set_allocation_sites_list(undefined_value());
   return true;
 }
@@ -5637,8 +5538,6 @@ void Heap::TearDown() {
            map_space_->MaximumCommittedMemory());
     PrintF("maximum_committed_by_cell_space=%" V8_PTR_PREFIX "d ",
            cell_space_->MaximumCommittedMemory());
-    PrintF("maximum_committed_by_property_space=%" V8_PTR_PREFIX "d ",
-           property_cell_space_->MaximumCommittedMemory());
     PrintF("maximum_committed_by_lo_space=%" V8_PTR_PREFIX "d ",
            lo_space_->MaximumCommittedMemory());
     PrintF("\n\n");
@@ -5688,12 +5587,6 @@ void Heap::TearDown() {
     cell_space_ = NULL;
   }
 
-  if (property_cell_space_ != NULL) {
-    property_cell_space_->TearDown();
-    delete property_cell_space_;
-    property_cell_space_ = NULL;
-  }
-
   if (lo_space_ != NULL) {
     lo_space_->TearDown();
     delete lo_space_;
@@ -5768,6 +5661,19 @@ DependentCode* Heap::LookupWeakObjectToCodeDependency(Handle<HeapObject> obj) {
 }
 
 
+void Heap::AddRetainedMap(Handle<Map> map) {
+  if (FLAG_retain_maps_for_n_gc == 0) return;
+  Handle<WeakCell> cell = Map::WeakCellForMap(map);
+  Handle<ArrayList> array(retained_maps(), isolate());
+  array = ArrayList::Add(
+      array, cell, handle(Smi::FromInt(FLAG_retain_maps_for_n_gc), isolate()),
+      ArrayList::kReloadLengthAfterAllocation);
+  if (*array != retained_maps()) {
+    set_retained_maps(*array);
+  }
+}
+
+
 void Heap::FatalProcessOutOfMemory(const char* location, bool take_snapshot) {
   v8::internal::V8::FatalProcessOutOfMemory(location, take_snapshot);
 }
@@ -5807,8 +5713,6 @@ Space* AllSpaces::next() {
       return heap_->map_space();
     case CELL_SPACE:
       return heap_->cell_space();
-    case PROPERTY_CELL_SPACE:
-      return heap_->property_cell_space();
     case LO_SPACE:
       return heap_->lo_space();
     default:
@@ -5829,8 +5733,6 @@ PagedSpace* PagedSpaces::next() {
       return heap_->map_space();
     case CELL_SPACE:
       return heap_->cell_space();
-    case PROPERTY_CELL_SPACE:
-      return heap_->property_cell_space();
     default:
       return NULL;
   }
@@ -5917,10 +5819,6 @@ ObjectIterator* SpaceIterator::CreateIterator() {
     case CELL_SPACE:
       iterator_ = new HeapObjectIterator(heap_->cell_space(), size_func_);
       break;
-    case PROPERTY_CELL_SPACE:
-      iterator_ =
-          new HeapObjectIterator(heap_->property_cell_space(), size_func_);
-      break;
     case LO_SPACE:
       iterator_ = new LargeObjectIterator(heap_->lo_space(), size_func_);
       break;
index 21eb7e6..ee701b2 100644 (file)
@@ -38,7 +38,6 @@ namespace internal {
   V(Oddball, true_value, TrueValue)                                            \
   V(Oddball, false_value, FalseValue)                                          \
   V(Oddball, uninitialized_value, UninitializedValue)                          \
-  V(Oddball, exception, Exception)                                             \
   V(Map, cell_map, CellMap)                                                    \
   V(Map, global_property_cell_map, GlobalPropertyCellMap)                      \
   V(Map, shared_function_info_map, SharedFunctionInfoMap)                      \
@@ -53,17 +52,20 @@ namespace internal {
   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)                          \
+  V(Map, one_byte_string_map, OneByteStringMap)                                \
+  V(Map, one_byte_internalized_string_map, OneByteInternalizedStringMap)       \
+  V(Map, function_context_map, FunctionContextMap)                             \
   V(FixedArray, empty_fixed_array, EmptyFixedArray)                            \
   V(ByteArray, empty_byte_array, EmptyByteArray)                               \
   V(DescriptorArray, empty_descriptor_array, EmptyDescriptorArray)             \
   V(ConstantPoolArray, empty_constant_pool_array, EmptyConstantPoolArray)      \
-  V(Oddball, arguments_marker, ArgumentsMarker)                                \
   /* The roots above this line should be boring from a GC point of view.    */ \
   /* This means they are never in new space and never on a page that is     */ \
   /* being compacted.                                                       */ \
+  V(Oddball, no_interceptor_result_sentinel, NoInterceptorResultSentinel)      \
+  V(Oddball, arguments_marker, ArgumentsMarker)                                \
+  V(Oddball, exception, Exception)                                             \
+  V(Oddball, termination_exception, TerminationException)                      \
   V(FixedArray, number_string_cache, NumberStringCache)                        \
   V(Object, instanceof_cache_function, InstanceofCacheFunction)                \
   V(Object, instanceof_cache_map, InstanceofCacheMap)                          \
@@ -71,13 +73,13 @@ namespace internal {
   V(FixedArray, single_character_string_cache, SingleCharacterStringCache)     \
   V(FixedArray, string_split_cache, StringSplitCache)                          \
   V(FixedArray, regexp_multiple_cache, RegExpMultipleCache)                    \
-  V(Oddball, termination_exception, TerminationException)                      \
   V(Smi, hash_seed, HashSeed)                                                  \
+  V(Map, hash_table_map, HashTableMap)                                         \
+  V(Map, ordered_hash_table_map, OrderedHashTableMap)                          \
   V(Map, symbol_map, SymbolMap)                                                \
   V(Map, string_map, StringMap)                                                \
-  V(Map, one_byte_string_map, OneByteStringMap)                                \
-  V(Map, cons_string_map, ConsStringMap)                                       \
   V(Map, cons_one_byte_string_map, ConsOneByteStringMap)                       \
+  V(Map, cons_string_map, ConsStringMap)                                       \
   V(Map, sliced_string_map, SlicedStringMap)                                   \
   V(Map, sliced_one_byte_string_map, SlicedOneByteStringMap)                   \
   V(Map, external_string_map, ExternalStringMap)                               \
@@ -89,7 +91,6 @@ namespace internal {
   V(Map, short_external_string_with_one_byte_data_map,                         \
     ShortExternalStringWithOneByteDataMap)                                     \
   V(Map, internalized_string_map, InternalizedStringMap)                       \
-  V(Map, one_byte_internalized_string_map, OneByteInternalizedStringMap)       \
   V(Map, external_internalized_string_map, ExternalInternalizedStringMap)      \
   V(Map, external_internalized_string_with_one_byte_data_map,                  \
     ExternalInternalizedStringWithOneByteDataMap)                              \
@@ -141,7 +142,6 @@ namespace internal {
   V(FixedTypedArrayBase, empty_fixed_uint8_clamped_array,                      \
     EmptyFixedUint8ClampedArray)                                               \
   V(Map, sloppy_arguments_elements_map, SloppyArgumentsElementsMap)            \
-  V(Map, function_context_map, FunctionContextMap)                             \
   V(Map, catch_context_map, CatchContextMap)                                   \
   V(Map, with_context_map, WithContextMap)                                     \
   V(Map, block_context_map, BlockContextMap)                                   \
@@ -159,10 +159,11 @@ namespace internal {
   V(Map, termination_exception_map, TerminationExceptionMap)                   \
   V(Map, message_object_map, JSMessageObjectMap)                               \
   V(Map, foreign_map, ForeignMap)                                              \
+  V(Map, neander_map, NeanderMap)                                              \
+  V(Map, external_map, ExternalMap)                                            \
   V(HeapNumber, nan_value, NanValue)                                           \
   V(HeapNumber, infinity_value, InfinityValue)                                 \
   V(HeapNumber, minus_zero_value, MinusZeroValue)                              \
-  V(Map, neander_map, NeanderMap)                                              \
   V(JSObject, message_listeners, MessageListeners)                             \
   V(UnseededNumberDictionary, code_stubs, CodeStubs)                           \
   V(UnseededNumberDictionary, non_monomorphic_cache, NonMonomorphicCache)      \
@@ -172,9 +173,8 @@ namespace internal {
   V(FixedArray, natives_source_cache, NativesSourceCache)                      \
   V(Script, empty_script, EmptyScript)                                         \
   V(NameDictionary, intrinsic_function_names, IntrinsicFunctionNames)          \
-  V(Cell, undefined_cell, UndefineCell)                                        \
+  V(Cell, undefined_cell, UndefinedCell)                                       \
   V(JSObject, observation_state, ObservationState)                             \
-  V(Map, external_map, ExternalMap)                                            \
   V(Object, symbol_registry, SymbolRegistry)                                   \
   V(SeededNumberDictionary, empty_slow_element_dictionary,                     \
     EmptySlowElementDictionary)                                                \
@@ -183,6 +183,7 @@ namespace internal {
   V(FixedArray, microtask_queue, MicrotaskQueue)                               \
   V(FixedArray, keyed_load_dummy_vector, KeyedLoadDummyVector)                 \
   V(FixedArray, detached_contexts, DetachedContexts)                           \
+  V(ArrayList, retained_maps, RetainedMaps)                                    \
   V(WeakHashTable, weak_object_to_code_table, WeakObjectToCodeTable)
 
 // Entries in this list are limited to Smis and are not visited during GC.
@@ -195,6 +196,7 @@ namespace internal {
   V(Smi, getter_stub_deopt_pc_offset, GetterStubDeoptPCOffset)             \
   V(Smi, setter_stub_deopt_pc_offset, SetterStubDeoptPCOffset)
 
+
 #define ROOT_LIST(V)  \
   STRONG_ROOT_LIST(V) \
   SMI_ROOT_LIST(V)    \
@@ -607,6 +609,9 @@ class Heap {
   // Returns the amount of memory currently committed for the heap.
   intptr_t CommittedMemory();
 
+  // Returns the amount of memory currently committed for the old space.
+  intptr_t CommittedOldGenerationMemory();
+
   // Returns the amount of executable memory currently committed for the heap.
   intptr_t CommittedMemoryExecutable();
 
@@ -645,7 +650,6 @@ class Heap {
   OldSpace* code_space() { return code_space_; }
   MapSpace* map_space() { return map_space_; }
   CellSpace* cell_space() { return cell_space_; }
-  PropertyCellSpace* property_cell_space() { return property_cell_space_; }
   LargeObjectSpace* lo_space() { return lo_space_; }
   PagedSpace* paged_space(int idx) {
     switch (idx) {
@@ -657,8 +661,6 @@ class Heap {
         return map_space();
       case CELL_SPACE:
         return cell_space();
-      case PROPERTY_CELL_SPACE:
-        return property_cell_space();
       case CODE_SPACE:
         return code_space();
       case NEW_SPACE:
@@ -694,6 +696,12 @@ class Heap {
     return old_data_space_->allocation_limit_address();
   }
 
+  // TODO(hpayer): There is still a missmatch between capacity and actual
+  // committed memory size.
+  bool CanExpandOldGeneration(int size) {
+    return (CommittedOldGenerationMemory() + size) < MaxOldGenerationSize();
+  }
+
   // Returns a deep copy of the JavaScript object.
   // Properties and elements are copied too.
   // Optionally takes an AllocationSite to be appended in an AllocationMemento.
@@ -863,6 +871,13 @@ class Heap {
   void set_array_buffers_list(Object* object) { array_buffers_list_ = object; }
   Object* array_buffers_list() const { return array_buffers_list_; }
 
+  void set_new_array_buffer_views_list(Object* object) {
+    new_array_buffer_views_list_ = object;
+  }
+  Object* new_array_buffer_views_list() const {
+    return new_array_buffer_views_list_;
+  }
+
   void set_allocation_sites_list(Object* object) {
     allocation_sites_list_ = object;
   }
@@ -898,7 +913,8 @@ class Heap {
 
   // Iterate pointers to from semispace of new space found in memory interval
   // from start to end.
-  void IterateAndMarkPointersToFromSpace(Address start, Address end,
+  void IterateAndMarkPointersToFromSpace(bool record_slots, Address start,
+                                         Address end,
                                          ObjectSlotCallback callback);
 
   // Returns whether the object resides in new space.
@@ -981,10 +997,6 @@ class Heap {
   void Print();
   void PrintHandles();
 
-  void OldPointerSpaceCheckStoreBuffer();
-  void MapSpaceCheckStoreBuffer();
-  void LargeObjectSpaceCheckStoreBuffer();
-
   // Report heap statistics.
   void ReportHeapStatistics(const char* title);
   void ReportCodeStatistics(const char* title);
@@ -1090,7 +1102,13 @@ class Heap {
 
   static const int kInitalOldGenerationLimitFactor = 2;
 
+#if V8_OS_ANDROID
+  // Don't apply pointer multiplier on Android since it has no swap space and
+  // should instead adapt it's heap size based on available physical memory.
+  static const int kPointerMultiplier = 1;
+#else
   static const int kPointerMultiplier = i::kPointerSize / 4;
+#endif
 
   // The new space size has to be a power of 2. Sizes are in MB.
   static const int kMaxSemiSpaceSizeLowMemoryDevice = 1 * kPointerMultiplier;
@@ -1308,6 +1326,8 @@ class Heap {
   // Returns the current sweep generation.
   int sweep_generation() { return sweep_generation_; }
 
+  bool concurrent_sweeping_enabled() { return concurrent_sweeping_enabled_; }
+
   inline Isolate* isolate();
 
   void CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags);
@@ -1450,6 +1470,8 @@ class Heap {
 
   DependentCode* LookupWeakObjectToCodeDependency(Handle<HeapObject> obj);
 
+  void AddRetainedMap(Handle<Map> map);
+
   static void FatalProcessOutOfMemory(const char* location,
                                       bool take_snapshot = false);
 
@@ -1465,6 +1487,18 @@ class Heap {
 
   bool deserialization_complete() const { return deserialization_complete_; }
 
+  bool migration_failure() const { return migration_failure_; }
+  void set_migration_failure(bool migration_failure) {
+    migration_failure_ = migration_failure;
+  }
+
+  bool previous_migration_failure() const {
+    return previous_migration_failure_;
+  }
+  void set_previous_migration_failure(bool previous_migration_failure) {
+    previous_migration_failure_ = previous_migration_failure;
+  }
+
  protected:
   // Methods made available to tests.
 
@@ -1566,7 +1600,6 @@ class Heap {
   OldSpace* code_space_;
   MapSpace* map_space_;
   CellSpace* cell_space_;
-  PropertyCellSpace* property_cell_space_;
   LargeObjectSpace* lo_space_;
   HeapState gc_state_;
   int gc_post_processing_depth_;
@@ -1602,6 +1635,8 @@ class Heap {
   inline void set_##name(type* value) {                                       \
     /* The deserializer makes use of the fact that these common roots are */  \
     /* never in new space and never on a page that is being compacted.    */  \
+    DCHECK(!deserialization_complete() ||                                     \
+           RootCanBeWrittenAfterInitialization(k##camel_name##RootIndex));    \
     DCHECK(k##camel_name##RootIndex >= kOldSpaceRoots || !InNewSpace(value)); \
     roots_[k##camel_name##RootIndex] = value;                                 \
   }
@@ -1621,8 +1656,8 @@ class Heap {
   // generation and on every allocation in large object space.
   intptr_t old_generation_allocation_limit_;
 
-  // The allocation limit when there is > kMinIdleTimeToStartIncrementalMarking
-  // idle time in the idle time handler.
+  // The allocation limit when there is >16.66ms idle time in the idle time
+  // handler.
   intptr_t idle_old_generation_allocation_limit_;
 
   // Indicates that an allocation has failed in the old generation since the
@@ -1634,11 +1669,16 @@ class Heap {
   bool inline_allocation_disabled_;
 
   // Weak list heads, threaded through the objects.
-  // List heads are initilized lazily and contain the undefined_value at start.
+  // List heads are initialized lazily and contain the undefined_value at start.
   Object* native_contexts_list_;
   Object* array_buffers_list_;
   Object* allocation_sites_list_;
 
+  // This is a global list of array buffer views in new space. When the views
+  // get promoted, they are removed form the list and added to the corresponding
+  // array buffer.
+  Object* new_array_buffer_views_list_;
+
   // List of encountered weak collections (JSWeakMap and JSWeakSet) during
   // marking. It is initialized during marking, destroyed after marking and
   // contains Smi(0) while marking is not active.
@@ -1971,7 +2011,8 @@ class Heap {
   void MarkCompactEpilogue();
 
   void ProcessNativeContexts(WeakObjectRetainer* retainer);
-  void ProcessArrayBuffers(WeakObjectRetainer* retainer);
+  void ProcessArrayBuffers(WeakObjectRetainer* retainer, bool stop_after_young);
+  void ProcessNewArrayBufferViews(WeakObjectRetainer* retainer);
   void ProcessAllocationSites(WeakObjectRetainer* retainer);
 
   // Deopts all code that contains allocation instruction which are tenured or
@@ -2131,6 +2172,15 @@ class Heap {
 
   bool deserialization_complete_;
 
+  bool concurrent_sweeping_enabled_;
+
+  // A migration failure indicates that a semi-space copy of an object during
+  // a scavenge failed and the object got promoted instead.
+  bool migration_failure_;
+
+  // A migration failure happened in the previous scavenge.
+  bool previous_migration_failure_;
+
   friend class AlwaysAllocateScope;
   friend class Deserializer;
   friend class Factory;
@@ -2177,8 +2227,6 @@ class HeapStats {
   int* size_per_type;                      // 22
   int* os_error;                           // 23
   int* end_marker;                         // 24
-  intptr_t* property_cell_space_size;      // 25
-  intptr_t* property_cell_space_capacity;  // 26
 };
 
 
index dfd3ed2..83ebbda 100644 (file)
@@ -30,6 +30,7 @@ IncrementalMarking::IncrementalMarking(Heap* heap)
       unscanned_bytes_of_large_object_(0),
       was_activated_(false),
       weak_closure_was_overapproximated_(false),
+      weak_closure_approximation_rounds_(0),
       request_type_(COMPLETE_MARKING) {}
 
 
@@ -251,13 +252,7 @@ class IncrementalMarkingMarkingVisitor
 
   // Marks the object grey and pushes it on the marking stack.
   INLINE(static void MarkObject(Heap* heap, Object* obj)) {
-    HeapObject* heap_object = HeapObject::cast(obj);
-    MarkBit mark_bit = Marking::MarkBitFrom(heap_object);
-    if (mark_bit.data_only()) {
-      MarkBlackOrKeepGrey(heap_object, mark_bit, heap_object->Size());
-    } else if (Marking::IsWhite(mark_bit)) {
-      heap->incremental_marking()->WhiteToGreyAndPush(heap_object, mark_bit);
-    }
+    IncrementalMarking::MarkObject(heap, HeapObject::cast(obj));
   }
 
   // Marks the object black without pushing it on the marking stack.
@@ -280,7 +275,7 @@ class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor {
  public:
   explicit IncrementalMarkingRootMarkingVisitor(
       IncrementalMarking* incremental_marking)
-      : incremental_marking_(incremental_marking) {}
+      : heap_(incremental_marking->heap()) {}
 
   void VisitPointer(Object** p) { MarkObjectByPointer(p); }
 
@@ -293,18 +288,10 @@ class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor {
     Object* obj = *p;
     if (!obj->IsHeapObject()) return;
 
-    HeapObject* heap_object = HeapObject::cast(obj);
-    MarkBit mark_bit = Marking::MarkBitFrom(heap_object);
-    if (mark_bit.data_only()) {
-      MarkBlackOrKeepGrey(heap_object, mark_bit, heap_object->Size());
-    } else {
-      if (Marking::IsWhite(mark_bit)) {
-        incremental_marking_->WhiteToGreyAndPush(heap_object, mark_bit);
-      }
-    }
+    IncrementalMarking::MarkObject(heap_, HeapObject::cast(obj));
   }
 
-  IncrementalMarking* incremental_marking_;
+  Heap* heap_;
 };
 
 
@@ -326,7 +313,6 @@ void IncrementalMarking::SetOldSpacePageFlags(MemoryChunk* chunk,
       chunk->SetFlag(MemoryChunk::RESCAN_ON_EVACUATION);
     }
   } else if (chunk->owner()->identity() == CELL_SPACE ||
-             chunk->owner()->identity() == PROPERTY_CELL_SPACE ||
              chunk->scan_on_scavenge()) {
     chunk->ClearFlag(MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING);
     chunk->ClearFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING);
@@ -373,7 +359,6 @@ void IncrementalMarking::DeactivateIncrementalWriteBarrier() {
   DeactivateIncrementalWriteBarrierForSpace(heap_->old_pointer_space());
   DeactivateIncrementalWriteBarrierForSpace(heap_->old_data_space());
   DeactivateIncrementalWriteBarrierForSpace(heap_->cell_space());
-  DeactivateIncrementalWriteBarrierForSpace(heap_->property_cell_space());
   DeactivateIncrementalWriteBarrierForSpace(heap_->map_space());
   DeactivateIncrementalWriteBarrierForSpace(heap_->code_space());
   DeactivateIncrementalWriteBarrierForSpace(heap_->new_space());
@@ -408,7 +393,6 @@ void IncrementalMarking::ActivateIncrementalWriteBarrier() {
   ActivateIncrementalWriteBarrier(heap_->old_pointer_space());
   ActivateIncrementalWriteBarrier(heap_->old_data_space());
   ActivateIncrementalWriteBarrier(heap_->cell_space());
-  ActivateIncrementalWriteBarrier(heap_->property_cell_space());
   ActivateIncrementalWriteBarrier(heap_->map_space());
   ActivateIncrementalWriteBarrier(heap_->code_space());
   ActivateIncrementalWriteBarrier(heap_->new_space());
@@ -561,6 +545,35 @@ void IncrementalMarking::StartMarking(CompactionFlag flag) {
 }
 
 
+void IncrementalMarking::MarkObjectGroups() {
+  DCHECK(FLAG_overapproximate_weak_closure);
+  DCHECK(!weak_closure_was_overapproximated_);
+
+  int old_marking_deque_top =
+      heap_->mark_compact_collector()->marking_deque()->top();
+
+  heap_->mark_compact_collector()->MarkImplicitRefGroups(&MarkObject);
+
+  IncrementalMarkingRootMarkingVisitor visitor(this);
+  heap_->isolate()->global_handles()->IterateObjectGroups(
+      &visitor, &MarkCompactCollector::IsUnmarkedHeapObjectWithHeap);
+
+  int marking_progress =
+      abs(old_marking_deque_top -
+          heap_->mark_compact_collector()->marking_deque()->top());
+
+  ++weak_closure_approximation_rounds_;
+  if ((weak_closure_approximation_rounds_ >=
+       FLAG_max_object_groups_marking_rounds) ||
+      (marking_progress < FLAG_min_progress_during_object_groups_marking)) {
+    weak_closure_was_overapproximated_ = true;
+  }
+
+  heap_->isolate()->global_handles()->RemoveImplicitRefGroups();
+  heap_->isolate()->global_handles()->RemoveObjectGroups();
+}
+
+
 void IncrementalMarking::PrepareForScavenge() {
   if (!IsMarking()) return;
   NewSpacePageIterator it(heap_->new_space()->FromSpaceStart(),
@@ -641,6 +654,16 @@ void IncrementalMarking::VisitObject(Map* map, HeapObject* obj, int size) {
 }
 
 
+void IncrementalMarking::MarkObject(Heap* heap, HeapObject* obj) {
+  MarkBit mark_bit = Marking::MarkBitFrom(obj);
+  if (mark_bit.data_only()) {
+    MarkBlackOrKeepGrey(obj, mark_bit, obj->Size());
+  } else if (Marking::IsWhite(mark_bit)) {
+    heap->incremental_marking()->WhiteToGreyAndPush(obj, mark_bit);
+  }
+}
+
+
 intptr_t IncrementalMarking::ProcessMarkingDeque(intptr_t bytes_to_process) {
   intptr_t bytes_processed = 0;
   Map* filler_map = heap_->one_pointer_filler_map();
@@ -773,15 +796,16 @@ void IncrementalMarking::Finalize() {
 }
 
 
-void IncrementalMarking::OverApproximateWeakClosure() {
+void IncrementalMarking::OverApproximateWeakClosure(CompletionAction action) {
   DCHECK(FLAG_overapproximate_weak_closure);
   DCHECK(!weak_closure_was_overapproximated_);
   if (FLAG_trace_incremental_marking) {
     PrintF("[IncrementalMarking] requesting weak closure overapproximation.\n");
   }
-  set_should_hurry(true);
   request_type_ = OVERAPPROXIMATION;
-  heap_->isolate()->stack_guard()->RequestGC();
+  if (action == GC_VIA_STACK_GUARD) {
+    heap_->isolate()->stack_guard()->RequestGC();
+  }
 }
 
 
@@ -796,8 +820,8 @@ void IncrementalMarking::MarkingComplete(CompletionAction action) {
   if (FLAG_trace_incremental_marking) {
     PrintF("[IncrementalMarking] Complete (normal).\n");
   }
+  request_type_ = COMPLETE_MARKING;
   if (action == GC_VIA_STACK_GUARD) {
-    request_type_ = COMPLETE_MARKING;
     heap_->isolate()->stack_guard()->RequestGC();
   }
 }
@@ -806,6 +830,7 @@ void IncrementalMarking::MarkingComplete(CompletionAction action) {
 void IncrementalMarking::Epilogue() {
   was_activated_ = false;
   weak_closure_was_overapproximated_ = false;
+  weak_closure_approximation_rounds_ = 0;
 }
 
 
@@ -937,7 +962,7 @@ intptr_t IncrementalMarking::Step(intptr_t allocated_bytes,
     if (state_ == SWEEPING) {
       if (heap_->mark_compact_collector()->sweeping_in_progress() &&
           (heap_->mark_compact_collector()->IsSweepingCompleted() ||
-           !FLAG_concurrent_sweeping)) {
+           !heap_->concurrent_sweeping_enabled())) {
         heap_->mark_compact_collector()->EnsureSweepingCompleted();
       }
       if (!heap_->mark_compact_collector()->sweeping_in_progress()) {
@@ -950,9 +975,8 @@ intptr_t IncrementalMarking::Step(intptr_t allocated_bytes,
         if (completion == FORCE_COMPLETION ||
             IsIdleMarkingDelayCounterLimitReached()) {
           if (FLAG_overapproximate_weak_closure &&
-              !weak_closure_was_overapproximated_ &&
-              action == GC_VIA_STACK_GUARD) {
-            OverApproximateWeakClosure();
+              !weak_closure_was_overapproximated_) {
+            OverApproximateWeakClosure(action);
           } else {
             MarkingComplete(action);
           }
index d6dfe17..7d41cfe 100644 (file)
@@ -41,7 +41,8 @@ class IncrementalMarking {
   bool weak_closure_was_overapproximated() const {
     return weak_closure_was_overapproximated_;
   }
-  void set_weak_closure_was_overapproximated(bool val) {
+
+  void SetWeakClosureWasOverApproximatedForTesting(bool val) {
     weak_closure_was_overapproximated_ = val;
   }
 
@@ -53,6 +54,11 @@ class IncrementalMarking {
 
   inline bool IsComplete() { return state() == COMPLETE; }
 
+  inline bool IsReadyToOverApproximateWeakClosure() const {
+    return request_type_ == OVERAPPROXIMATION &&
+           !weak_closure_was_overapproximated_;
+  }
+
   GCRequestType request_type() const { return request_type_; }
 
   bool WorthActivating();
@@ -67,6 +73,8 @@ class IncrementalMarking {
 
   void Stop();
 
+  void MarkObjectGroups();
+
   void PrepareForScavenge();
 
   void UpdateMarkingDequeAfterScavenge();
@@ -77,7 +85,7 @@ class IncrementalMarking {
 
   void Abort();
 
-  void OverApproximateWeakClosure();
+  void OverApproximateWeakClosure(CompletionAction action);
 
   void MarkingComplete(CompletionAction action);
 
@@ -189,6 +197,10 @@ class IncrementalMarking {
 
   bool IsIdleMarkingDelayCounterLimitReached();
 
+  INLINE(static void MarkObject(Heap* heap, HeapObject* object));
+
+  Heap* heap() const { return heap_; }
+
  private:
   int64_t SpaceLeftInOldSpace();
 
@@ -243,6 +255,8 @@ class IncrementalMarking {
 
   bool weak_closure_was_overapproximated_;
 
+  int weak_closure_approximation_rounds_;
+
   GCRequestType request_type_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(IncrementalMarking);
index b525bf6..4f7f61e 100644 (file)
@@ -99,6 +99,7 @@ static void VerifyMarking(Heap* heap, Address bottom, Address top) {
   for (Address current = bottom; current < top; current += kPointerSize) {
     object = HeapObject::FromAddress(current);
     if (MarkCompactCollector::IsMarked(object)) {
+      CHECK(Marking::IsBlack(Marking::MarkBitFrom(object)));
       CHECK(current >= next_object_must_be_here_or_later);
       object->Iterate(&visitor);
       next_object_must_be_here_or_later = current + object->Size();
@@ -138,7 +139,6 @@ static void VerifyMarking(Heap* heap) {
   VerifyMarking(heap->old_data_space());
   VerifyMarking(heap->code_space());
   VerifyMarking(heap->cell_space());
-  VerifyMarking(heap->property_cell_space());
   VerifyMarking(heap->map_space());
   VerifyMarking(heap->new_space());
 
@@ -219,7 +219,6 @@ static void VerifyEvacuation(Heap* heap) {
   VerifyEvacuation(heap, heap->old_data_space());
   VerifyEvacuation(heap, heap->code_space());
   VerifyEvacuation(heap, heap->cell_space());
-  VerifyEvacuation(heap, heap->property_cell_space());
   VerifyEvacuation(heap, heap->map_space());
   VerifyEvacuation(heap->new_space());
 
@@ -262,11 +261,6 @@ bool MarkCompactCollector::StartCompaction(CompactionMode mode) {
   if (!compacting_) {
     DCHECK(evacuation_candidates_.length() == 0);
 
-#ifdef ENABLE_GDB_JIT_INTERFACE
-    // If GDBJIT interface is active disable compaction.
-    if (FLAG_gdbjit) return false;
-#endif
-
     CollectEvacuationCandidates(heap()->old_pointer_space());
     CollectEvacuationCandidates(heap()->old_data_space());
 
@@ -280,7 +274,6 @@ bool MarkCompactCollector::StartCompaction(CompactionMode mode) {
     if (FLAG_trace_fragmentation) {
       TraceFragmentation(heap()->map_space());
       TraceFragmentation(heap()->cell_space());
-      TraceFragmentation(heap()->property_cell_space());
     }
 
     heap()->old_pointer_space()->EvictEvacuationCandidatesFromFreeLists();
@@ -294,6 +287,60 @@ bool MarkCompactCollector::StartCompaction(CompactionMode mode) {
 }
 
 
+void MarkCompactCollector::ClearInvalidSlotsBufferEntries(PagedSpace* space) {
+  PageIterator it(space);
+  while (it.has_next()) {
+    Page* p = it.next();
+    SlotsBuffer::RemoveInvalidSlots(heap_, p->slots_buffer());
+  }
+}
+
+
+void MarkCompactCollector::ClearInvalidStoreAndSlotsBufferEntries() {
+  heap_->store_buffer()->ClearInvalidStoreBufferEntries();
+
+  ClearInvalidSlotsBufferEntries(heap_->old_pointer_space());
+  ClearInvalidSlotsBufferEntries(heap_->old_data_space());
+  ClearInvalidSlotsBufferEntries(heap_->code_space());
+  ClearInvalidSlotsBufferEntries(heap_->cell_space());
+  ClearInvalidSlotsBufferEntries(heap_->map_space());
+
+  LargeObjectIterator it(heap_->lo_space());
+  for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
+    MemoryChunk* chunk = MemoryChunk::FromAddress(object->address());
+    SlotsBuffer::RemoveInvalidSlots(heap_, chunk->slots_buffer());
+  }
+}
+
+
+#ifdef VERIFY_HEAP
+static void VerifyValidSlotsBufferEntries(Heap* heap, PagedSpace* space) {
+  PageIterator it(space);
+  while (it.has_next()) {
+    Page* p = it.next();
+    SlotsBuffer::VerifySlots(heap, p->slots_buffer());
+  }
+}
+
+
+static void VerifyValidStoreAndSlotsBufferEntries(Heap* heap) {
+  heap->store_buffer()->VerifyValidStoreBufferEntries();
+
+  VerifyValidSlotsBufferEntries(heap, heap->old_pointer_space());
+  VerifyValidSlotsBufferEntries(heap, heap->old_data_space());
+  VerifyValidSlotsBufferEntries(heap, heap->code_space());
+  VerifyValidSlotsBufferEntries(heap, heap->cell_space());
+  VerifyValidSlotsBufferEntries(heap, heap->map_space());
+
+  LargeObjectIterator it(heap->lo_space());
+  for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
+    MemoryChunk* chunk = MemoryChunk::FromAddress(object->address());
+    SlotsBuffer::VerifySlots(heap, chunk->slots_buffer());
+  }
+}
+#endif
+
+
 void MarkCompactCollector::CollectGarbage() {
   // Make sure that Prepare() has been called. The individual steps below will
   // update the state as they proceed.
@@ -319,6 +366,14 @@ void MarkCompactCollector::CollectGarbage() {
   }
 #endif
 
+  ClearInvalidStoreAndSlotsBufferEntries();
+
+#ifdef VERIFY_HEAP
+  if (FLAG_verify_heap) {
+    VerifyValidStoreAndSlotsBufferEntries(heap_);
+  }
+#endif
+
   SweepSpaces();
 
 #ifdef VERIFY_HEAP
@@ -367,7 +422,6 @@ void MarkCompactCollector::VerifyMarkbitsAreClean() {
   VerifyMarkbitsAreClean(heap_->old_data_space());
   VerifyMarkbitsAreClean(heap_->code_space());
   VerifyMarkbitsAreClean(heap_->cell_space());
-  VerifyMarkbitsAreClean(heap_->property_cell_space());
   VerifyMarkbitsAreClean(heap_->map_space());
   VerifyMarkbitsAreClean(heap_->new_space());
 
@@ -426,7 +480,6 @@ void MarkCompactCollector::ClearMarkbits() {
   ClearMarkbitsInPagedSpace(heap_->old_pointer_space());
   ClearMarkbitsInPagedSpace(heap_->old_data_space());
   ClearMarkbitsInPagedSpace(heap_->cell_space());
-  ClearMarkbitsInPagedSpace(heap_->property_cell_space());
   ClearMarkbitsInNewSpace(heap_->new_space());
 
   LargeObjectIterator it(heap_->lo_space());
@@ -477,12 +530,12 @@ void MarkCompactCollector::EnsureSweepingCompleted() {
 
   // If sweeping is not completed or not running at all, we try to complete it
   // here.
-  if (!FLAG_concurrent_sweeping || !IsSweepingCompleted()) {
+  if (!heap()->concurrent_sweeping_enabled() || !IsSweepingCompleted()) {
     SweepInParallel(heap()->paged_space(OLD_DATA_SPACE), 0);
     SweepInParallel(heap()->paged_space(OLD_POINTER_SPACE), 0);
   }
   // Wait twice for both jobs.
-  if (FLAG_concurrent_sweeping) {
+  if (heap()->concurrent_sweeping_enabled()) {
     pending_sweeper_jobs_semaphore_.Wait();
     pending_sweeper_jobs_semaphore_.Wait();
   }
@@ -584,8 +637,6 @@ const char* AllocationSpaceName(AllocationSpace space) {
       return "MAP_SPACE";
     case CELL_SPACE:
       return "CELL_SPACE";
-    case PROPERTY_CELL_SPACE:
-      return "PROPERTY_CELL_SPACE";
     case LO_SPACE:
       return "LO_SPACE";
     default:
@@ -602,11 +653,11 @@ const char* AllocationSpaceName(AllocationSpace space) {
 static int FreeListFragmentation(PagedSpace* space, Page* p) {
   // If page was not swept then there are no free list items on it.
   if (!p->WasSwept()) {
-    if (FLAG_trace_fragmentation) {
+    if (FLAG_trace_fragmentation_verbose) {
       PrintF("%p [%s]: %d bytes live (unswept)\n", reinterpret_cast<void*>(p),
              AllocationSpaceName(space->identity()), p->LiveBytes());
     }
-    return 0;
+    return FLAG_always_compact ? 1 : 0;
   }
 
   PagedSpace::SizeStats sizes;
@@ -623,7 +674,7 @@ static int FreeListFragmentation(PagedSpace* space, Page* p) {
     ratio_threshold = 15;
   }
 
-  if (FLAG_trace_fragmentation) {
+  if (FLAG_trace_fragmentation_verbose) {
     PrintF("%p [%s]: %d (%.2f%%) %d (%.2f%%) %d (%.2f%%) %d (%.2f%%) %s\n",
            reinterpret_cast<void*>(p), AllocationSpaceName(space->identity()),
            static_cast<int>(sizes.small_size_),
@@ -699,6 +750,10 @@ void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) {
     max_evacuation_candidates *= 2;
   }
 
+  if (FLAG_always_compact) {
+    max_evacuation_candidates = kMaxMaxEvacuationCandidates;
+  }
+
   if (FLAG_trace_fragmentation && mode == REDUCE_MEMORY_FOOTPRINT) {
     PrintF(
         "Estimated over reserved memory: %.1f / %.1f MB (threshold %d), "
@@ -712,24 +767,42 @@ void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) {
 
   Candidate candidates[kMaxMaxEvacuationCandidates];
 
+  if (FLAG_trace_fragmentation &&
+      max_evacuation_candidates >= kMaxMaxEvacuationCandidates) {
+    PrintF("Hit max page compaction limit of %d pages\n",
+           kMaxMaxEvacuationCandidates);
+  }
   max_evacuation_candidates =
       Min(kMaxMaxEvacuationCandidates, max_evacuation_candidates);
 
   int count = 0;
   int fragmentation = 0;
+  int page_number = 0;
   Candidate* least = NULL;
 
   PageIterator it(space);
   while (it.has_next()) {
     Page* p = it.next();
     if (p->NeverEvacuate()) continue;
-    p->ClearEvacuationCandidate();
+
+    // Invariant: Evacuation candidates are just created when marking is
+    // started. At the end of a GC all evacuation candidates are cleared and
+    // their slot buffers are released.
+    CHECK(!p->IsEvacuationCandidate());
+    CHECK(p->slots_buffer() == NULL);
 
     if (FLAG_stress_compaction) {
-      unsigned int counter = space->heap()->ms_count();
-      uintptr_t page_number = reinterpret_cast<uintptr_t>(p) >> kPageSizeBits;
-      if ((counter & 1) == (page_number & 1)) fragmentation = 1;
-    } else if (mode == REDUCE_MEMORY_FOOTPRINT) {
+      if (FLAG_manual_evacuation_candidates_selection) {
+        if (p->IsFlagSet(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING)) {
+          p->ClearFlag(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING);
+          fragmentation = 1;
+        }
+      } else {
+        unsigned int counter = space->heap()->ms_count();
+        if ((counter & 1) == (page_number & 1)) fragmentation = 1;
+        page_number++;
+      }
+    } else if (mode == REDUCE_MEMORY_FOOTPRINT && !FLAG_always_compact) {
       // Don't try to release too many pages.
       if (estimated_release >= over_reserved) {
         continue;
@@ -754,7 +827,7 @@ void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) {
         fragmentation = 0;
       }
 
-      if (FLAG_trace_fragmentation) {
+      if (FLAG_trace_fragmentation_verbose) {
         PrintF("%p [%s]: %d (%.2f%%) free %s\n", reinterpret_cast<void*>(p),
                AllocationSpaceName(space->identity()),
                static_cast<int>(free_bytes),
@@ -1470,8 +1543,9 @@ class MarkCompactMarkingVisitor::ObjectStatsTracker<
       heap->RecordFixedArraySubTypeStats(DESCRIPTOR_ARRAY_SUB_TYPE,
                                          fixed_array_size);
     }
-    if (map_obj->HasTransitionArray()) {
-      int fixed_array_size = map_obj->transitions()->Size();
+    if (TransitionArray::IsFullTransitionArray(map_obj->raw_transitions())) {
+      int fixed_array_size =
+          TransitionArray::cast(map_obj->raw_transitions())->Size();
       heap->RecordFixedArraySubTypeStats(TRANSITION_ARRAY_SUB_TYPE,
                                          fixed_array_size);
     }
@@ -1966,7 +2040,8 @@ void MarkCompactCollector::MarkRoots(RootMarkingVisitor* visitor) {
 }
 
 
-void MarkCompactCollector::MarkImplicitRefGroups() {
+void MarkCompactCollector::MarkImplicitRefGroups(
+    MarkObjectFunction mark_object) {
   List<ImplicitRefGroup*>* ref_groups =
       isolate()->global_handles()->implicit_ref_groups();
 
@@ -1984,9 +2059,7 @@ void MarkCompactCollector::MarkImplicitRefGroups() {
     // A parent object is marked, so mark all child heap objects.
     for (size_t j = 0; j < entry->length; ++j) {
       if ((*children[j])->IsHeapObject()) {
-        HeapObject* child = HeapObject::cast(*children[j]);
-        MarkBit mark = Marking::MarkBitFrom(child);
-        MarkObject(child, mark);
+        mark_object(heap(), HeapObject::cast(*children[j]));
       }
     }
 
@@ -2050,10 +2123,6 @@ void MarkCompactCollector::RefillMarkingDeque() {
   DiscoverGreyObjectsInSpace(heap(), &marking_deque_, heap()->cell_space());
   if (marking_deque_.IsFull()) return;
 
-  DiscoverGreyObjectsInSpace(heap(), &marking_deque_,
-                             heap()->property_cell_space());
-  if (marking_deque_.IsFull()) return;
-
   LargeObjectIterator lo_it(heap()->lo_space());
   DiscoverGreyObjectsWithIterator(heap(), &marking_deque_, &lo_it);
   if (marking_deque_.IsFull()) return;
@@ -2085,7 +2154,7 @@ void MarkCompactCollector::ProcessEphemeralMarking(
     if (!only_process_harmony_weak_collections) {
       isolate()->global_handles()->IterateObjectGroups(
           visitor, &IsUnmarkedHeapObjectWithHeap);
-      MarkImplicitRefGroups();
+      MarkImplicitRefGroups(&MarkCompactMarkingVisitor::MarkObject);
     }
     ProcessWeakCollections();
     work_to_do = !marking_deque_.IsEmpty();
@@ -2112,6 +2181,71 @@ void MarkCompactCollector::ProcessTopOptimizedFrame(ObjectVisitor* visitor) {
 }
 
 
+void MarkCompactCollector::RetainMaps() {
+  if (reduce_memory_footprint_ || abort_incremental_marking_ ||
+      FLAG_retain_maps_for_n_gc == 0) {
+    // Do not retain dead maps if flag disables it or there is
+    // - memory pressure (reduce_memory_footprint_),
+    // - GC is requested by tests or dev-tools (abort_incremental_marking_).
+    return;
+  }
+
+  ArrayList* retained_maps = heap()->retained_maps();
+  int length = retained_maps->Length();
+  int new_length = 0;
+  for (int i = 0; i < length; i += 2) {
+    DCHECK(retained_maps->Get(i)->IsWeakCell());
+    WeakCell* cell = WeakCell::cast(retained_maps->Get(i));
+    if (cell->cleared()) continue;
+    int age = Smi::cast(retained_maps->Get(i + 1))->value();
+    int new_age;
+    Map* map = Map::cast(cell->value());
+    MarkBit map_mark = Marking::MarkBitFrom(map);
+    if (!map_mark.Get()) {
+      if (age == 0) {
+        // The map has aged. Do not retain this map.
+        continue;
+      }
+      Object* constructor = map->GetConstructor();
+      if (!constructor->IsHeapObject() ||
+          !Marking::MarkBitFrom(HeapObject::cast(constructor)).Get()) {
+        // The constructor is dead, no new objects with this map can
+        // be created. Do not retain this map.
+        continue;
+      }
+      Object* prototype = map->prototype();
+      if (prototype->IsHeapObject() &&
+          !Marking::MarkBitFrom(HeapObject::cast(prototype)).Get()) {
+        // The prototype is not marked, age the map.
+        new_age = age - 1;
+      } else {
+        // The prototype and the constructor are marked, this map keeps only
+        // transition tree alive, not JSObjects. Do not age the map.
+        new_age = age;
+      }
+      MarkObject(map, map_mark);
+    } else {
+      new_age = FLAG_retain_maps_for_n_gc;
+    }
+    if (i != new_length) {
+      retained_maps->Set(new_length, cell);
+      Object** slot = retained_maps->Slot(new_length);
+      RecordSlot(slot, slot, cell);
+      retained_maps->Set(new_length + 1, Smi::FromInt(new_age));
+    } else if (new_age != age) {
+      retained_maps->Set(new_length + 1, Smi::FromInt(new_age));
+    }
+    new_length += 2;
+  }
+  Object* undefined = heap()->undefined_value();
+  for (int i = new_length; i < length; i++) {
+    retained_maps->Clear(i, undefined);
+  }
+  if (new_length != length) retained_maps->SetLength(new_length);
+  ProcessMarkingDeque();
+}
+
+
 void MarkCompactCollector::EnsureMarkingDequeIsCommittedAndInitialize() {
   if (marking_deque_memory_ == NULL) {
     marking_deque_memory_ = new base::VirtualMemory(4 * MB);
@@ -2150,21 +2284,6 @@ void MarkCompactCollector::UncommitMarkingDeque() {
 }
 
 
-void MarkCompactCollector::OverApproximateWeakClosure() {
-  GCTracer::Scope gc_scope(heap()->tracer(),
-                           GCTracer::Scope::MC_INCREMENTAL_WEAKCLOSURE);
-
-  RootMarkingVisitor root_visitor(heap());
-  isolate()->global_handles()->IterateObjectGroups(
-      &root_visitor, &IsUnmarkedHeapObjectWithHeap);
-  MarkImplicitRefGroups();
-
-  // Remove object groups after marking phase.
-  heap()->isolate()->global_handles()->RemoveObjectGroups();
-  heap()->isolate()->global_handles()->RemoveImplicitRefGroups();
-}
-
-
 void MarkCompactCollector::MarkLiveObjects() {
   GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_MARK);
   double start_time = 0.0;
@@ -2209,17 +2328,6 @@ void MarkCompactCollector::MarkLiveObjects() {
         }
       }
     }
-    {
-      HeapObjectIterator js_global_property_cell_iterator(
-          heap()->property_cell_space());
-      HeapObject* cell;
-      while ((cell = js_global_property_cell_iterator.Next()) != NULL) {
-        DCHECK(cell->IsPropertyCell());
-        if (IsMarked(cell)) {
-          MarkCompactMarkingVisitor::VisitPropertyCell(cell->map(), cell);
-        }
-      }
-    }
   }
 
   RootMarkingVisitor root_visitor(heap());
@@ -2227,6 +2335,11 @@ void MarkCompactCollector::MarkLiveObjects() {
 
   ProcessTopOptimizedFrame(&root_visitor);
 
+  // Retaining dying maps should happen before or during ephemeral marking
+  // because a map could keep the key of an ephemeron alive. Note that map
+  // aging is imprecise: maps that are kept alive only by ephemerons will age.
+  RetainMaps();
+
   {
     GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_WEAKCLOSURE);
 
@@ -2332,6 +2445,7 @@ void MarkCompactCollector::ClearNonLiveReferences() {
     if (!table->IsKey(key)) continue;
     uint32_t value_index = table->EntryToValueIndex(i);
     Object* value = table->get(value_index);
+    DCHECK(key->IsWeakCell());
     if (WeakCell::cast(key)->cleared()) {
       have_code_to_deoptimize_ |=
           DependentCode::cast(value)->MarkCodeForDeoptimization(
@@ -2345,10 +2459,12 @@ void MarkCompactCollector::ClearNonLiveReferences() {
 
 
 void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) {
-  int number_of_transitions = map->NumberOfProtoTransitions();
-  FixedArray* prototype_transitions = map->GetPrototypeTransitions();
+  FixedArray* prototype_transitions =
+      TransitionArray::GetPrototypeTransitions(map);
+  int number_of_transitions =
+      TransitionArray::NumberOfPrototypeTransitions(prototype_transitions);
 
-  const int header = Map::kProtoTransitionHeaderSize;
+  const int header = TransitionArray::kProtoTransitionHeaderSize;
   int new_number_of_transitions = 0;
   for (int i = 0; i < number_of_transitions; i++) {
     Object* cached_map = prototype_transitions->get(header + i);
@@ -2362,7 +2478,8 @@ void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) {
   }
 
   if (new_number_of_transitions != number_of_transitions) {
-    map->SetNumberOfProtoTransitions(new_number_of_transitions);
+    TransitionArray::SetNumberOfPrototypeTransitions(prototype_transitions,
+                                                     new_number_of_transitions);
   }
 
   // Fill slots that became free with undefined value.
@@ -2383,7 +2500,7 @@ void MarkCompactCollector::ClearNonLiveMapTransitions(Map* map,
   bool current_is_alive = map_mark.Get();
   bool parent_is_alive = Marking::MarkBitFrom(parent).Get();
   if (!current_is_alive && parent_is_alive) {
-    ClearMapTransitions(parent);
+    ClearMapTransitions(parent, map);
   }
 }
 
@@ -2397,28 +2514,43 @@ bool MarkCompactCollector::ClearMapBackPointer(Map* target) {
 }
 
 
-void MarkCompactCollector::ClearMapTransitions(Map* map) {
-  // If there are no transitions to be cleared, return.
-  // TODO(verwaest) Should be an assert, otherwise back pointers are not
-  // properly cleared.
-  if (!map->HasTransitionArray()) return;
+void MarkCompactCollector::ClearMapTransitions(Map* map, Map* dead_transition) {
+  Object* transitions = map->raw_transitions();
+  int num_transitions = TransitionArray::NumberOfTransitions(transitions);
 
-  TransitionArray* t = map->transitions();
+  int number_of_own_descriptors = map->NumberOfOwnDescriptors();
+  DescriptorArray* descriptors = map->instance_descriptors();
+
+  // A previously existing simple transition (stored in a WeakCell) may have
+  // been cleared. Clear the useless cell pointer, and take ownership
+  // of the descriptor array.
+  if (transitions->IsWeakCell() && WeakCell::cast(transitions)->cleared()) {
+    map->set_raw_transitions(Smi::FromInt(0));
+  }
+  if (num_transitions == 0 &&
+      descriptors == dead_transition->instance_descriptors() &&
+      number_of_own_descriptors > 0) {
+    TrimDescriptorArray(map, descriptors, number_of_own_descriptors);
+    DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors);
+    map->set_owns_descriptors(true);
+    return;
+  }
 
   int transition_index = 0;
 
-  DescriptorArray* descriptors = map->instance_descriptors();
   bool descriptors_owner_died = false;
 
   // Compact all live descriptors to the left.
-  for (int i = 0; i < t->number_of_transitions(); ++i) {
-    Map* target = t->GetTarget(i);
+  for (int i = 0; i < num_transitions; ++i) {
+    Map* target = TransitionArray::GetTarget(transitions, i);
     if (ClearMapBackPointer(target)) {
       if (target->instance_descriptors() == descriptors) {
         descriptors_owner_died = true;
       }
     } else {
       if (i != transition_index) {
+        DCHECK(TransitionArray::IsFullTransitionArray(transitions));
+        TransitionArray* t = TransitionArray::cast(transitions);
         Name* key = t->GetKey(i);
         t->SetKey(transition_index, key);
         Object** key_slot = t->GetKeySlot(transition_index);
@@ -2433,9 +2565,7 @@ void MarkCompactCollector::ClearMapTransitions(Map* map) {
   // If there are no transitions to be cleared, return.
   // TODO(verwaest) Should be an assert, otherwise back pointers are not
   // properly cleared.
-  if (transition_index == t->number_of_transitions()) return;
-
-  int number_of_own_descriptors = map->NumberOfOwnDescriptors();
+  if (transition_index == num_transitions) return;
 
   if (descriptors_owner_died) {
     if (number_of_own_descriptors > 0) {
@@ -2451,14 +2581,17 @@ void MarkCompactCollector::ClearMapTransitions(Map* map) {
   // such that number_of_transitions() == 0. If this assumption changes,
   // 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;
+  int trim = TransitionArray::Capacity(transitions) - transition_index;
   if (trim > 0) {
+    // Non-full-TransitionArray cases can never reach this point.
+    DCHECK(TransitionArray::IsFullTransitionArray(transitions));
+    TransitionArray* t = TransitionArray::cast(transitions);
     heap_->RightTrimFixedArray<Heap::FROM_GC>(
-        t, t->IsSimpleTransition() ? trim
-                                   : trim * TransitionArray::kTransitionSize);
+        t, trim * TransitionArray::kTransitionSize);
     t->SetNumberOfTransitions(transition_index);
+    // The map still has a full transition array.
+    DCHECK(TransitionArray::IsFullTransitionArray(map->raw_transitions()));
   }
-  DCHECK(map->HasTransitionArray());
 }
 
 
@@ -2475,6 +2608,13 @@ void MarkCompactCollector::TrimDescriptorArray(Map* map,
 
   if (descriptors->HasEnumCache()) TrimEnumCache(map, descriptors);
   descriptors->Sort();
+
+  if (FLAG_unbox_double_fields) {
+    LayoutDescriptor* layout_descriptor = map->layout_descriptor();
+    layout_descriptor = layout_descriptor->Trim(heap_, map, descriptors,
+                                                number_of_own_descriptors);
+    SLOW_DCHECK(layout_descriptor->IsConsistentWithMap(map, true));
+  }
 }
 
 
@@ -2750,6 +2890,8 @@ class PointersUpdatingVisitor : public ObjectVisitor {
     // Avoid unnecessary changes that might unnecessary flush the instruction
     // cache.
     if (target != old_target) {
+      // TODO(jochen): Remove again after fixing http://crbug.com/452095
+      CHECK(target->IsHeapObject() == old_target->IsHeapObject());
       rinfo->set_target_object(target);
     }
   }
@@ -2760,6 +2902,8 @@ class PointersUpdatingVisitor : public ObjectVisitor {
     Object* old_target = target;
     VisitPointer(&target);
     if (target != old_target) {
+      // TODO(jochen): Remove again after fixing http://crbug.com/452095
+      CHECK(target->IsHeapObject() == old_target->IsHeapObject());
       rinfo->set_target_address(Code::cast(target)->instruction_start());
     }
   }
@@ -2770,6 +2914,8 @@ class PointersUpdatingVisitor : public ObjectVisitor {
     DCHECK(stub != NULL);
     VisitPointer(&stub);
     if (stub != rinfo->code_age_stub()) {
+      // TODO(jochen): Remove again after fixing http://crbug.com/452095
+      CHECK(stub->IsHeapObject() == rinfo->code_age_stub()->IsHeapObject());
       rinfo->set_code_age_stub(Code::cast(stub));
     }
   }
@@ -2781,6 +2927,9 @@ class PointersUpdatingVisitor : public ObjectVisitor {
             rinfo->IsPatchedDebugBreakSlotSequence()));
     Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
     VisitPointer(&target);
+    // TODO(jochen): Remove again after fixing http://crbug.com/452095
+    CHECK(target->IsCode() &&
+          HAS_SMI_TAG(Code::cast(target)->instruction_start()));
     rinfo->set_call_address(Code::cast(target)->instruction_start());
   }
 
@@ -2794,12 +2943,14 @@ class PointersUpdatingVisitor : public ObjectVisitor {
 
 // TODO(ishell): remove, once crbug/454297 is caught.
 #if V8_TARGET_ARCH_64_BIT
+#ifndef V8_OS_AIX  // no point checking on AIX as full 64 range is supported
     const uintptr_t kBoundary = V8_UINT64_C(1) << 48;
     STATIC_ASSERT(kBoundary > 0);
     if (reinterpret_cast<uintptr_t>(heap_obj->address()) >= kBoundary) {
       CheckLayoutDescriptorAndDie(heap, slot);
     }
 #endif
+#endif
     MapWord map_word = heap_obj->map_word();
     if (map_word.IsForwardingAddress()) {
       DCHECK(heap->InFromSpace(heap_obj) ||
@@ -2852,11 +3003,9 @@ void PointersUpdatingVisitor::CheckLayoutDescriptorAndDie(Heap* heap,
     space_owner_id = 6;
   } else if (heap->cell_space()->ContainsSafe(slot_address)) {
     space_owner_id = 7;
-  } else if (heap->property_cell_space()->ContainsSafe(slot_address)) {
-    space_owner_id = 8;
   } else {
     // Lo space or other.
-    space_owner_id = 9;
+    space_owner_id = 8;
   }
   data[index++] = space_owner_id;
   data[index++] = 0x20aaaaaaaaUL;
@@ -2918,19 +3067,18 @@ void PointersUpdatingVisitor::CheckLayoutDescriptorAndDie(Heap* heap,
 
 
 static void UpdatePointer(HeapObject** address, HeapObject* object) {
-  Address new_addr = Memory::Address_at(object->address());
-
-  // The new space sweep will overwrite the map word of dead objects
-  // with NULL. In this case we do not need to transfer this entry to
-  // the store buffer which we are rebuilding.
-  // We perform the pointer update with a no barrier compare-and-swap. The
-  // compare and swap may fail in the case where the pointer update tries to
-  // update garbage memory which was concurrently accessed by the sweeper.
-  if (new_addr != NULL) {
-    base::NoBarrier_CompareAndSwap(
-        reinterpret_cast<base::AtomicWord*>(address),
-        reinterpret_cast<base::AtomicWord>(object),
-        reinterpret_cast<base::AtomicWord>(HeapObject::FromAddress(new_addr)));
+  MapWord map_word = object->map_word();
+  // The store buffer can still contain stale pointers in dead large objects.
+  // Ignore these pointers here.
+  DCHECK(map_word.IsForwardingAddress() ||
+         object->GetHeap()->lo_space()->FindPage(
+             reinterpret_cast<Address>(address)) != NULL);
+  if (map_word.IsForwardingAddress()) {
+    // TODO(jochen): Remove again after fixing http://crbug.com/452095
+    CHECK((*address)->IsHeapObject() ==
+          map_word.ToForwardingAddress()->IsHeapObject());
+    // Update the corresponding slot.
+    *address = map_word.ToForwardingAddress();
   }
 }
 
@@ -2967,6 +3115,162 @@ bool MarkCompactCollector::TryPromoteObject(HeapObject* object,
 }
 
 
+bool MarkCompactCollector::IsSlotInBlackObject(Page* p, Address slot,
+                                               HeapObject** out_object) {
+  // This function does not support large objects right now.
+  Space* owner = p->owner();
+  if (owner == heap_->lo_space() || owner == NULL) {
+    *out_object = NULL;
+    return true;
+  }
+
+  uint32_t mark_bit_index = p->AddressToMarkbitIndex(slot);
+  unsigned int start_index = mark_bit_index >> Bitmap::kBitsPerCellLog2;
+  MarkBit::CellType index_in_cell = 1U
+                                    << (mark_bit_index & Bitmap::kBitIndexMask);
+  MarkBit::CellType* cells = p->markbits()->cells();
+  Address cell_base = p->area_start();
+  unsigned int cell_base_start_index = Bitmap::IndexToCell(
+      Bitmap::CellAlignIndex(p->AddressToMarkbitIndex(cell_base)));
+
+  // Check if the slot points to the start of an object. This can happen e.g.
+  // when we left trim a fixed array. Such slots are invalid and we can remove
+  // them.
+  if ((cells[start_index] & index_in_cell) != 0) {
+    return false;
+  }
+
+  // Check if the object is in the current cell.
+  MarkBit::CellType slot_mask;
+  if ((cells[start_index] == 0) ||
+      (base::bits::CountTrailingZeros32(cells[start_index]) >
+       base::bits::CountTrailingZeros32(cells[start_index] | index_in_cell))) {
+    // If we are already in the first cell, there is no live object.
+    if (start_index == cell_base_start_index) return false;
+
+    // If not, find a cell in a preceding cell slot that has a mark bit set.
+    do {
+      start_index--;
+    } while (start_index > cell_base_start_index && cells[start_index] == 0);
+
+    // The slot must be in a dead object if there are no preceding cells that
+    // have mark bits set.
+    if (cells[start_index] == 0) {
+      return false;
+    }
+
+    // The object is in a preceding cell. Set the mask to find any object.
+    slot_mask = 0xffffffff;
+  } else {
+    // The object start is before the the slot index. Hence, in this case the
+    // slot index can not be at the beginning of the cell.
+    CHECK(index_in_cell > 1);
+    // We are interested in object mark bits right before the slot.
+    slot_mask = index_in_cell - 1;
+  }
+
+  MarkBit::CellType current_cell = cells[start_index];
+  CHECK(current_cell != 0);
+
+  // Find the last live object in the cell.
+  unsigned int leading_zeros =
+      base::bits::CountLeadingZeros32(current_cell & slot_mask);
+  CHECK(leading_zeros != 32);
+  unsigned int offset = Bitmap::kBitIndexMask - leading_zeros;
+
+  cell_base += (start_index - cell_base_start_index) * 32 * kPointerSize;
+  Address address = cell_base + offset * kPointerSize;
+  HeapObject* object = HeapObject::FromAddress(address);
+  CHECK(object->address() < reinterpret_cast<Address>(slot));
+  if (object->address() <= slot &&
+      (object->address() + object->Size()) > slot) {
+    // If the slot is within the last found object in the cell, the slot is
+    // in a live object.
+    *out_object = object;
+    return true;
+  }
+  return false;
+}
+
+
+bool MarkCompactCollector::IsSlotInBlackObjectSlow(Page* p, Address slot) {
+  // This function does not support large objects right now.
+  Space* owner = p->owner();
+  if (owner == heap_->lo_space() || owner == NULL) return true;
+
+  for (MarkBitCellIterator it(p); !it.Done(); it.Advance()) {
+    Address cell_base = it.CurrentCellBase();
+    MarkBit::CellType* cell = it.CurrentCell();
+
+    MarkBit::CellType current_cell = *cell;
+    if (current_cell == 0) continue;
+
+    int offset = 0;
+    while (current_cell != 0) {
+      int trailing_zeros = base::bits::CountTrailingZeros32(current_cell);
+      current_cell >>= trailing_zeros;
+      offset += trailing_zeros;
+      Address address = cell_base + offset * kPointerSize;
+
+      HeapObject* object = HeapObject::FromAddress(address);
+      int size = object->Size();
+
+      if (object->address() > slot) return false;
+      if (object->address() <= slot && slot < (object->address() + size)) {
+        return true;
+      }
+
+      offset++;
+      current_cell >>= 1;
+    }
+  }
+  return false;
+}
+
+
+bool MarkCompactCollector::IsSlotInLiveObject(Address slot) {
+  HeapObject* object = NULL;
+  // The target object is black but we don't know if the source slot is black.
+  // The source object could have died and the slot could be part of a free
+  // space. Find out based on mark bits if the slot is part of a live object.
+  if (!IsSlotInBlackObject(Page::FromAddress(slot), slot, &object)) {
+    return false;
+  }
+
+#if V8_DOUBLE_FIELDS_UNBOXING
+  // |object| is NULL only when the slot belongs to large object space.
+  DCHECK(object != NULL ||
+         Page::FromAnyPointerAddress(heap_, slot)->owner() ==
+             heap_->lo_space());
+  // We don't need to check large objects' layout descriptor since it can't
+  // contain in-object fields anyway.
+  if (object != NULL) {
+    // Filter out slots that happens to point to unboxed double fields.
+    LayoutDescriptorHelper helper(object->map());
+    bool has_only_tagged_fields = helper.all_fields_tagged();
+    if (!has_only_tagged_fields &&
+        !helper.IsTagged(static_cast<int>(slot - object->address()))) {
+      return false;
+    }
+  }
+#endif
+
+  return true;
+}
+
+
+void MarkCompactCollector::VerifyIsSlotInLiveObject(Address slot,
+                                                    HeapObject* object) {
+  // The target object has to be black.
+  CHECK(Marking::IsBlack(Marking::MarkBitFrom(object)));
+
+  // The target object is black but we don't know if the source slot is black.
+  // The source object could have died and the slot could be part of a free
+  // space. Use the mark bit iterator to find out about liveness of the slot.
+  CHECK(IsSlotInBlackObjectSlow(Page::FromAddress(slot), slot));
+}
+
+
 void MarkCompactCollector::EvacuateNewSpace() {
   // There are soft limits in the allocation code, designed trigger a mark
   // sweep collection by failing allocations.  But since we are already in
@@ -3050,6 +3354,7 @@ void MarkCompactCollector::EvacuateLiveObjectsFromPage(Page* p) {
 
 void MarkCompactCollector::EvacuatePages() {
   int npages = evacuation_candidates_.length();
+  int abandoned_pages = 0;
   for (int i = 0; i < npages; i++) {
     Page* p = evacuation_candidates_[i];
     DCHECK(p->IsEvacuationCandidate() ||
@@ -3060,12 +3365,13 @@ void MarkCompactCollector::EvacuatePages() {
     // Allocate emergency memory for the case when compaction fails due to out
     // of memory.
     if (!space->HasEmergencyMemory()) {
-      space->CreateEmergencyMemory();
+      space->CreateEmergencyMemory();  // If the OS lets us.
     }
     if (p->IsEvacuationCandidate()) {
-      // During compaction we might have to request a new page. Check that we
-      // have an emergency page and the space still has room for that.
-      if (space->HasEmergencyMemory() && space->CanExpand()) {
+      // During compaction we might have to request a new page in order to free
+      // up a page.  Check that we actually got an emergency page above so we
+      // can guarantee that this succeeds.
+      if (space->HasEmergencyMemory()) {
         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
@@ -3081,6 +3387,7 @@ void MarkCompactCollector::EvacuatePages() {
           page->ClearEvacuationCandidate();
           page->SetFlag(Page::RESCAN_ON_EVACUATION);
         }
+        abandoned_pages = npages - i;
         break;
       }
     }
@@ -3094,6 +3401,16 @@ void MarkCompactCollector::EvacuatePages() {
         space->FreeEmergencyMemory();
       }
     }
+    if (FLAG_trace_fragmentation) {
+      if (abandoned_pages != 0) {
+        PrintF(
+            "  Abandon %d out of %d page defragmentations due to lack of "
+            "memory\n",
+            abandoned_pages, npages);
+      } else {
+        PrintF("  Defragmented %d pages\n", npages);
+      }
+    }
   }
 }
 
@@ -3218,11 +3535,6 @@ static int Sweep(PagedSpace* space, FreeList* free_list, Page* p,
         }
         freed_bytes = Free<parallelism>(space, free_list, free_start, size);
         max_freed_bytes = Max(freed_bytes, max_freed_bytes);
-#ifdef ENABLE_GDB_JIT_INTERFACE
-        if (FLAG_gdbjit && space->identity() == CODE_SPACE) {
-          GDBJITInterface::RemoveCodeRange(free_start, free_end);
-        }
-#endif
       }
       HeapObject* live_object = HeapObject::FromAddress(free_end);
       DCHECK(Marking::IsBlack(Marking::MarkBitFrom(live_object)));
@@ -3252,11 +3564,6 @@ static int Sweep(PagedSpace* space, FreeList* free_list, Page* p,
     }
     freed_bytes = Free<parallelism>(space, free_list, free_start, size);
     max_freed_bytes = Max(freed_bytes, max_freed_bytes);
-#ifdef ENABLE_GDB_JIT_INTERFACE
-    if (FLAG_gdbjit && space->identity() == CODE_SPACE) {
-      GDBJITInterface::RemoveCodeRange(free_start, p->area_end());
-    }
-#endif
   }
   p->ResetLiveBytes();
 
@@ -3439,8 +3746,7 @@ void MarkCompactCollector::EvacuateNewSpaceAndCandidates() {
                              GCTracer::Scope::MC_UPDATE_OLD_TO_NEW_POINTERS);
     StoreBufferRebuildScope scope(heap_, heap_->store_buffer(),
                                   &Heap::ScavengeStoreBufferCallback);
-    heap_->store_buffer()->IteratePointersToNewSpaceAndClearMaps(
-        &UpdatePointer);
+    heap_->store_buffer()->IteratePointersToNewSpace(&UpdatePointer);
   }
 
   {
@@ -3448,7 +3754,7 @@ void MarkCompactCollector::EvacuateNewSpaceAndCandidates() {
                              GCTracer::Scope::MC_UPDATE_POINTERS_TO_EVACUATED);
     SlotsBuffer::UpdateSlotsRecordedIn(heap_, migration_slots_buffer_,
                                        code_slots_filtering_required);
-    if (FLAG_trace_fragmentation) {
+    if (FLAG_trace_fragmentation_verbose) {
       PrintF("  migration slots buffer: %d\n",
              SlotsBuffer::SizeOfChain(migration_slots_buffer_));
     }
@@ -3483,7 +3789,7 @@ void MarkCompactCollector::EvacuateNewSpaceAndCandidates() {
       if (p->IsEvacuationCandidate()) {
         SlotsBuffer::UpdateSlotsRecordedIn(heap_, p->slots_buffer(),
                                            code_slots_filtering_required);
-        if (FLAG_trace_fragmentation) {
+        if (FLAG_trace_fragmentation_verbose) {
           PrintF("  page %p slots buffer: %d\n", reinterpret_cast<void*>(p),
                  SlotsBuffer::SizeOfChain(p->slots_buffer()));
         }
@@ -3543,15 +3849,6 @@ void MarkCompactCollector::EvacuateNewSpaceAndCandidates() {
     }
   }
 
-  HeapObjectIterator js_global_property_cell_iterator(
-      heap_->property_cell_space());
-  for (HeapObject* cell = js_global_property_cell_iterator.Next(); cell != NULL;
-       cell = js_global_property_cell_iterator.Next()) {
-    if (cell->IsPropertyCell()) {
-      PropertyCell::BodyDescriptor::IterateBody(cell, &updating_visitor);
-    }
-  }
-
   heap_->string_table()->Iterate(&updating_visitor);
 
   // Update pointers from external string table.
@@ -4159,7 +4456,7 @@ void MarkCompactCollector::SweepSpaces() {
       SweepSpace(heap()->old_data_space(), CONCURRENT_SWEEPING);
     }
     sweeping_in_progress_ = true;
-    if (FLAG_concurrent_sweeping) {
+    if (heap()->concurrent_sweeping_enabled()) {
       StartSweeperThreads();
     }
   }
@@ -4175,12 +4472,11 @@ void MarkCompactCollector::SweepSpaces() {
     GCTracer::Scope sweep_scope(heap()->tracer(),
                                 GCTracer::Scope::MC_SWEEP_CELL);
     SweepSpace(heap()->cell_space(), SEQUENTIAL_SWEEPING);
-    SweepSpace(heap()->property_cell_space(), SEQUENTIAL_SWEEPING);
   }
 
   EvacuateNewSpaceAndCandidates();
 
-  // ClearNonLiveTransitions depends on precise sweeping of map space to
+  // ClearNonLiveReferences depends on precise sweeping of map space to
   // detect whether unmarked map became dead in this collection or in one
   // of the previous ones.
   {
@@ -4291,6 +4587,63 @@ bool SlotsBuffer::AddTo(SlotsBufferAllocator* allocator,
 }
 
 
+void SlotsBuffer::RemoveInvalidSlots(Heap* heap, SlotsBuffer* buffer) {
+  // Remove entries by replacing them with an old-space slot containing a smi
+  // that is located in an unmovable page.
+  const ObjectSlot kRemovedEntry = HeapObject::RawField(
+      heap->empty_fixed_array(), FixedArrayBase::kLengthOffset);
+  DCHECK(Page::FromAddress(reinterpret_cast<Address>(kRemovedEntry))
+             ->NeverEvacuate());
+
+  while (buffer != NULL) {
+    SlotsBuffer::ObjectSlot* slots = buffer->slots_;
+    intptr_t slots_count = buffer->idx_;
+
+    for (int slot_idx = 0; slot_idx < slots_count; ++slot_idx) {
+      ObjectSlot slot = slots[slot_idx];
+      if (!IsTypedSlot(slot)) {
+        Object* object = *slot;
+        if (object->IsHeapObject()) {
+          if (heap->InNewSpace(object) ||
+              !heap->mark_compact_collector()->IsSlotInLiveObject(
+                  reinterpret_cast<Address>(slot))) {
+            slots[slot_idx] = kRemovedEntry;
+          }
+        }
+      } else {
+        ++slot_idx;
+        DCHECK(slot_idx < slots_count);
+      }
+    }
+    buffer = buffer->next();
+  }
+}
+
+
+void SlotsBuffer::VerifySlots(Heap* heap, SlotsBuffer* buffer) {
+  while (buffer != NULL) {
+    SlotsBuffer::ObjectSlot* slots = buffer->slots_;
+    intptr_t slots_count = buffer->idx_;
+
+    for (int slot_idx = 0; slot_idx < slots_count; ++slot_idx) {
+      ObjectSlot slot = slots[slot_idx];
+      if (!IsTypedSlot(slot)) {
+        Object* object = *slot;
+        if (object->IsHeapObject()) {
+          CHECK(!heap->InNewSpace(object));
+          CHECK(heap->mark_compact_collector()->IsSlotInLiveObject(
+              reinterpret_cast<Address>(slot)));
+        }
+      } else {
+        ++slot_idx;
+        DCHECK(slot_idx < slots_count);
+      }
+    }
+    buffer = buffer->next();
+  }
+}
+
+
 static inline SlotsBuffer::SlotType SlotTypeForRMode(RelocInfo::Mode rmode) {
   if (RelocInfo::IsCodeTarget(rmode)) {
     return SlotsBuffer::CODE_TARGET_SLOT;
index 589bebf..3ffeeed 100644 (file)
@@ -16,6 +16,9 @@ namespace internal {
 // to the first live object in the page (only used for old and map objects).
 typedef bool (*IsAliveFunction)(HeapObject* obj, int* size, int* offset);
 
+// Callback function to mark an object in a given heap.
+typedef void (*MarkObjectFunction)(Heap* heap, HeapObject* object);
+
 // Forward declarations.
 class CodeFlusher;
 class MarkCompactCollector;
@@ -360,6 +363,15 @@ class SlotsBuffer {
                     SlotsBuffer** buffer_address, SlotType type, Address addr,
                     AdditionMode mode);
 
+  // Eliminates all stale entries from the slots buffer, i.e., slots that
+  // are not part of live objects anymore. This method must be called after
+  // marking, when the whole transitive closure is known and must be called
+  // before sweeping when mark bits are still intact.
+  static void RemoveInvalidSlots(Heap* heap, SlotsBuffer* buffer);
+
+  // Ensures that there are no invalid slots in the chain of slots buffers.
+  static void VerifySlots(Heap* heap, SlotsBuffer* buffer);
+
   static const int kNumberOfElements = 1021;
 
  private:
@@ -547,6 +559,7 @@ class MarkCompactCollector {
   static const uint32_t kMultiFreeEncoding = 1;
 
   static inline bool IsMarked(Object* obj);
+  static bool IsUnmarkedHeapObjectWithHeap(Heap* heap, Object** p);
 
   inline Heap* heap() const { return heap_; }
   inline Isolate* isolate() const;
@@ -660,6 +673,10 @@ class MarkCompactCollector {
   // to artificially keep AllocationSites alive for a time.
   void MarkAllocationSite(AllocationSite* site);
 
+  // Mark objects in implicit references groups if their parent object
+  // is marked.
+  void MarkImplicitRefGroups(MarkObjectFunction mark_object);
+
   MarkingDeque* marking_deque() { return &marking_deque_; }
 
   void EnsureMarkingDequeIsCommittedAndInitialize();
@@ -668,7 +685,13 @@ class MarkCompactCollector {
 
   void UncommitMarkingDeque();
 
-  void OverApproximateWeakClosure();
+  // The following four methods can just be called after marking, when the
+  // whole transitive closure is known. They must be called before sweeping
+  // when mark bits are still intact.
+  bool IsSlotInBlackObject(Page* p, Address slot, HeapObject** out_object);
+  bool IsSlotInBlackObjectSlow(Page* p, Address slot);
+  bool IsSlotInLiveObject(Address slot);
+  void VerifyIsSlotInLiveObject(Address slot, HeapObject* object);
 
  private:
   class SweeperTask;
@@ -680,6 +703,8 @@ class MarkCompactCollector {
   bool WillBeDeoptimized(Code* code);
   void RemoveDeadInvalidatedCode();
   void ProcessInvalidatedCode(ObjectVisitor* visitor);
+  void ClearInvalidSlotsBufferEntries(PagedSpace* space);
+  void ClearInvalidStoreAndSlotsBufferEntries();
 
   void StartSweeperThreads();
 
@@ -765,10 +790,6 @@ class MarkCompactCollector {
   // the string table are weak.
   void MarkStringTable(RootMarkingVisitor* visitor);
 
-  // Mark objects in implicit references groups if their parent object
-  // is marked.
-  void MarkImplicitRefGroups();
-
   // Mark objects reachable (transitively) from objects in the marking stack
   // or overflowed in the heap.
   void ProcessMarkingDeque();
@@ -787,6 +808,10 @@ class MarkCompactCollector {
   // otherwise a map can die and deoptimize the code.
   void ProcessTopOptimizedFrame(ObjectVisitor* visitor);
 
+  // Retain dying maps for <FLAG_retain_maps_for_n_gc> garbage collections to
+  // increase chances of reusing of map transition tree in future.
+  void RetainMaps();
+
   // Mark objects reachable (transitively) from objects in the marking
   // stack.  This function empties the marking stack, but may leave
   // overflowed objects in the heap, in which case the marking stack's
@@ -801,14 +826,13 @@ class MarkCompactCollector {
   // Callback function for telling whether the object *p is an unmarked
   // heap object.
   static bool IsUnmarkedHeapObject(Object** p);
-  static bool IsUnmarkedHeapObjectWithHeap(Heap* heap, Object** p);
 
   // Map transitions from a live map to a dead map must be killed.
   // We replace them with a null descriptor, with the same key.
   void ClearNonLiveReferences();
   void ClearNonLivePrototypeTransitions(Map* map);
   void ClearNonLiveMapTransitions(Map* map, MarkBit map_mark);
-  void ClearMapTransitions(Map* map);
+  void ClearMapTransitions(Map* map, Map* dead_transition);
   bool ClearMapBackPointer(Map* map);
   void TrimDescriptorArray(Map* map, DescriptorArray* descriptors,
                            int number_of_own_descriptors);
index 58afeae..872b2dd 100644 (file)
@@ -584,18 +584,13 @@ void StaticMarkingVisitor<StaticVisitor>::VisitJSDataView(Map* map,
 template <typename StaticVisitor>
 void StaticMarkingVisitor<StaticVisitor>::MarkMapContents(Heap* heap,
                                                           Map* map) {
-  // Make sure that the back pointer stored either in the map itself or
-  // inside its transitions array is marked. Skip recording the back
-  // pointer slot since map space is not compacted.
-  StaticVisitor::MarkObject(heap, HeapObject::cast(map->GetBackPointer()));
-
-  // Treat pointers in the transitions array as weak and also mark that
-  // array to prevent visiting it later. Skip recording the transition
-  // array slot, since it will be implicitly recorded when the pointer
-  // fields of this map are visited.
-  if (map->HasTransitionArray()) {
-    TransitionArray* transitions = map->transitions();
-    MarkTransitionArray(heap, transitions);
+  Object* raw_transitions = map->raw_transitions();
+  if (TransitionArray::IsSimpleTransition(raw_transitions)) {
+    StaticVisitor::VisitPointer(
+        heap, HeapObject::RawField(map, Map::kTransitionsOffset));
+  }
+  if (TransitionArray::IsFullTransitionArray(raw_transitions)) {
+    MarkTransitionArray(heap, TransitionArray::cast(raw_transitions));
   }
 
   // Since descriptor arrays are potentially shared, ensure that only the
@@ -631,20 +626,18 @@ void StaticMarkingVisitor<StaticVisitor>::MarkTransitionArray(
     Heap* heap, TransitionArray* transitions) {
   if (!StaticVisitor::MarkObjectWithoutPush(heap, transitions)) return;
 
-  // Simple transitions do not have keys nor prototype transitions.
-  if (transitions->IsSimpleTransition()) return;
-
   if (transitions->HasPrototypeTransitions()) {
     // Mark prototype transitions array but do not push it onto marking
     // stack, this will make references from it weak. We will clean dead
-    // prototype transitions in ClearNonLiveTransitions.
+    // prototype transitions in ClearNonLiveReferences.
     Object** slot = transitions->GetPrototypeTransitionsSlot();
     HeapObject* obj = HeapObject::cast(*slot);
     heap->mark_compact_collector()->RecordSlot(slot, slot, obj);
     StaticVisitor::MarkObjectWithoutPush(heap, obj);
   }
 
-  for (int i = 0; i < transitions->number_of_transitions(); ++i) {
+  int num_transitions = TransitionArray::NumberOfTransitions(transitions);
+  for (int i = 0; i < num_transitions; ++i) {
     StaticVisitor::VisitPointer(heap, transitions->GetKeySlot(i));
   }
 }
@@ -849,6 +842,8 @@ void Code::CodeIterateBody(ObjectVisitor* v) {
                   RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
                   RelocInfo::ModeMask(RelocInfo::CELL) |
                   RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
+                  RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
+                  RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
                   RelocInfo::ModeMask(RelocInfo::JS_RETURN) |
                   RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
                   RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
@@ -876,6 +871,8 @@ void Code::CodeIterateBody(Heap* heap) {
                   RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
                   RelocInfo::ModeMask(RelocInfo::CELL) |
                   RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
+                  RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
+                  RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
                   RelocInfo::ModeMask(RelocInfo::JS_RETURN) |
                   RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
                   RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
index 7b2e2d9..520e539 100644 (file)
@@ -191,15 +191,18 @@ struct WeakListVisitor;
 
 
 template <class T>
-Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer) {
+Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer,
+                      bool stop_after_young) {
   Object* undefined = heap->undefined_value();
   Object* head = undefined;
   T* tail = NULL;
   MarkCompactCollector* collector = heap->mark_compact_collector();
   bool record_slots = MustRecordSlots(heap);
+
   while (list != undefined) {
     // Check whether to keep the candidate in the list.
     T* candidate = reinterpret_cast<T*>(list);
+
     Object* retained = retainer->RetainAs(list);
     if (retained != NULL) {
       if (head == undefined) {
@@ -220,9 +223,9 @@ Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer) {
       candidate = reinterpret_cast<T*>(retained);
       tail = candidate;
 
-
       // tail is a live object, visit it.
       WeakListVisitor<T>::VisitLiveObject(heap, tail, retainer);
+
     } else {
       WeakListVisitor<T>::VisitPhantomObject(heap, candidate);
     }
@@ -239,6 +242,56 @@ Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer) {
 }
 
 
+Object* VisitNewArrayBufferViewsWeakList(Heap* heap, Object* list,
+                                         WeakObjectRetainer* retainer) {
+  Object* undefined = heap->undefined_value();
+  Object* previous = undefined;
+  Object* head = undefined;
+  Object* next;
+  MarkCompactCollector* collector = heap->mark_compact_collector();
+  bool record_slots = MustRecordSlots(heap);
+
+  for (Object* o = list; o != undefined;) {
+    JSArrayBufferView* view = JSArrayBufferView::cast(o);
+    next = view->weak_next();
+    if (!heap->InNewSpace(view)) {
+      if (previous != undefined) {
+        // We are in the middle of the list, skip the old space element.
+        JSArrayBufferView* previous_view = JSArrayBufferView::cast(previous);
+        previous_view->set_weak_next(next);
+        if (record_slots) {
+          Object** next_slot = HeapObject::RawField(
+              previous_view, JSArrayBufferView::kWeakNextOffset);
+          collector->RecordSlot(next_slot, next_slot, next);
+        }
+      }
+      JSArrayBuffer* buffer = JSArrayBuffer::cast(view->buffer());
+      view->set_weak_next(buffer->weak_first_view());
+      if (record_slots) {
+        Object** next_slot =
+            HeapObject::RawField(view, JSArrayBufferView::kWeakNextOffset);
+        collector->RecordSlot(next_slot, next_slot, buffer->weak_first_view());
+      }
+      buffer->set_weak_first_view(view);
+      if (record_slots) {
+        Object** slot =
+            HeapObject::RawField(buffer, JSArrayBuffer::kWeakFirstViewOffset);
+        heap->mark_compact_collector()->RecordSlot(slot, slot, view);
+      }
+    } else {
+      // We found a valid new space view, remember it.
+      previous = view;
+      if (head == undefined) {
+        // We are at the list head.
+        head = view;
+      }
+    }
+    o = next;
+  }
+  return head;
+}
+
+
 template <class T>
 static void ClearWeakList(Heap* heap, Object* list) {
   Object* undefined = heap->undefined_value();
@@ -316,7 +369,8 @@ struct WeakListVisitor<Context> {
   static void DoWeakList(Heap* heap, Context* context,
                          WeakObjectRetainer* retainer, int index) {
     // Visit the weak list, removing dead intermediate elements.
-    Object* list_head = VisitWeakList<T>(heap, context->get(index), retainer);
+    Object* list_head =
+        VisitWeakList<T>(heap, context->get(index), retainer, false);
 
     // Update the list head.
     context->set(index, list_head, UPDATE_WRITE_BARRIER);
@@ -368,7 +422,7 @@ struct WeakListVisitor<JSArrayBuffer> {
   static void VisitLiveObject(Heap* heap, JSArrayBuffer* array_buffer,
                               WeakObjectRetainer* retainer) {
     Object* typed_array_obj = VisitWeakList<JSArrayBufferView>(
-        heap, array_buffer->weak_first_view(), retainer);
+        heap, array_buffer->weak_first_view(), retainer, false);
     array_buffer->set_weak_first_view(typed_array_obj);
     if (typed_array_obj != heap->undefined_value() && MustRecordSlots(heap)) {
       Object** slot = HeapObject::RawField(array_buffer,
@@ -399,23 +453,21 @@ struct WeakListVisitor<AllocationSite> {
 };
 
 
-template Object* VisitWeakList<Code>(Heap* heap, Object* list,
-                                     WeakObjectRetainer* retainer);
-
-
-template Object* VisitWeakList<JSFunction>(Heap* heap, Object* list,
-                                           WeakObjectRetainer* retainer);
-
-
 template Object* VisitWeakList<Context>(Heap* heap, Object* list,
-                                        WeakObjectRetainer* retainer);
+                                        WeakObjectRetainer* retainer,
+                                        bool stop_after_young);
 
 
 template Object* VisitWeakList<JSArrayBuffer>(Heap* heap, Object* list,
-                                              WeakObjectRetainer* retainer);
+                                              WeakObjectRetainer* retainer,
+                                              bool stop_after_young);
 
+template Object* VisitWeakList<JSArrayBufferView>(Heap* heap, Object* list,
+                                                  WeakObjectRetainer* retainer,
+                                                  bool stop_after_young);
 
 template Object* VisitWeakList<AllocationSite>(Heap* heap, Object* list,
-                                               WeakObjectRetainer* retainer);
+                                               WeakObjectRetainer* retainer,
+                                               bool stop_after_young);
 }
 }  // namespace v8::internal
index a442867..2bc9045 100644 (file)
@@ -413,6 +413,7 @@ class StaticMarkingVisitor : public StaticVisitorBase {
   INLINE(static void VisitCodeTarget(Heap* heap, RelocInfo* rinfo));
   INLINE(static void VisitCodeAgeSequence(Heap* heap, RelocInfo* rinfo));
   INLINE(static void VisitExternalReference(RelocInfo* rinfo)) {}
+  INLINE(static void VisitInternalReference(RelocInfo* rinfo)) {}
   INLINE(static void VisitRuntimeEntry(RelocInfo* rinfo)) {}
   // Skip the weak next code link in a code object.
   INLINE(static void VisitNextCodeLink(Heap* heap, Object** slot)) {}
@@ -489,7 +490,10 @@ class WeakObjectRetainer;
 // pointers. The template parameter T is a WeakListVisitor that defines how to
 // access the next-element pointers.
 template <class T>
-Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer);
+Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer,
+                      bool stop_after_young);
+Object* VisitNewArrayBufferViewsWeakList(Heap* heap, Object* list,
+                                         WeakObjectRetainer* retainer);
 }
 }  // namespace v8::internal
 
index c2ce5fc..a1c3180 100644 (file)
@@ -10,7 +10,7 @@
 #include "src/heap/mark-compact.h"
 #include "src/macro-assembler.h"
 #include "src/msan.h"
-#include "src/snapshot.h"
+#include "src/snapshot/snapshot.h"
 
 namespace v8 {
 namespace internal {
@@ -45,7 +45,6 @@ HeapObjectIterator::HeapObjectIterator(Page* page,
          owner == page->heap()->old_data_space() ||
          owner == page->heap()->map_space() ||
          owner == page->heap()->cell_space() ||
-         owner == page->heap()->property_cell_space() ||
          owner == page->heap()->code_space());
   Initialize(reinterpret_cast<PagedSpace*>(owner), page->area_start(),
              page->area_end(), kOnePageOnly, size_func);
@@ -935,9 +934,6 @@ 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);
 
@@ -1021,13 +1017,14 @@ Object* PagedSpace::FindObject(Address addr) {
 
 bool PagedSpace::CanExpand() {
   DCHECK(max_capacity_ % AreaSize() == 0);
-
-  if (Capacity() == max_capacity_) return false;
-
-  DCHECK(Capacity() < max_capacity_);
+  DCHECK(heap()->mark_compact_collector()->is_compacting() ||
+         Capacity() <= heap()->MaxOldGenerationSize());
+  DCHECK(heap()->CommittedOldGenerationMemory() <=
+         heap()->MaxOldGenerationSize() +
+             PagedSpace::MaxEmergencyMemoryAllocated());
 
   // Are we going to exceed capacity for this space?
-  if ((Capacity() + Page::kPageSize) > max_capacity_) return false;
+  if (!heap()->CanExpandOldGeneration(Page::kPageSize)) return false;
 
   return true;
 }
@@ -1039,7 +1036,7 @@ bool PagedSpace::Expand() {
   intptr_t size = AreaSize();
 
   if (anchor_.next_page() == &anchor_) {
-    size = Snapshot::SizeOfFirstPage(identity());
+    size = Snapshot::SizeOfFirstPage(heap()->isolate(), identity());
   }
 
   Page* p = heap()->isolate()->memory_allocator()->AllocatePage(size, this,
@@ -1049,7 +1046,10 @@ bool PagedSpace::Expand() {
   // Pages created during bootstrapping may contain immortal immovable objects.
   if (!heap()->deserialization_complete()) p->MarkNeverEvacuate();
 
-  DCHECK(Capacity() <= max_capacity_);
+  DCHECK(Capacity() <= heap()->MaxOldGenerationSize());
+  DCHECK(heap()->CommittedOldGenerationMemory() <=
+         heap()->MaxOldGenerationSize() +
+             PagedSpace::MaxEmergencyMemoryAllocated());
 
   p->InsertAfter(anchor_.prev_page());
 
@@ -1131,6 +1131,15 @@ void PagedSpace::ReleasePage(Page* page) {
 }
 
 
+intptr_t PagedSpace::MaxEmergencyMemoryAllocated() {
+  // New space and large object space.
+  static const int spaces_without_emergency_memory = 2;
+  static const int spaces_with_emergency_memory =
+      LAST_SPACE - FIRST_SPACE + 1 - spaces_without_emergency_memory;
+  return Page::kPageSize * spaces_with_emergency_memory;
+}
+
+
 void PagedSpace::CreateEmergencyMemory() {
   if (identity() == CODE_SPACE) {
     // Make the emergency block available to the allocator.
@@ -1156,6 +1165,11 @@ void PagedSpace::FreeEmergencyMemory() {
 
 
 void PagedSpace::UseEmergencyMemory() {
+  // Page::Initialize makes the chunk into a real page and adds it to the
+  // accounting for this space.  Unlike PagedSpace::Expand, we don't check
+  // CanExpand first, so we can go over the limits a little here.  That's OK,
+  // because we are in the process of compacting which will free up at least as
+  // much memory as it allocates.
   Page* page = Page::Initialize(heap(), emergency_memory_, executable(), this);
   page->InsertAfter(anchor_.prev_page());
   emergency_memory_ = NULL;
@@ -2621,7 +2635,7 @@ HeapObject* PagedSpace::SlowAllocateRaw(int size_in_bytes) {
     // If sweeper threads are active, wait for them at that point and steal
     // elements form their free-lists.
     HeapObject* object = WaitForSweeperThreadsAndRetryAllocation(size_in_bytes);
-    if (object != NULL) return object;
+    return object;
   }
 
   // Try to expand the space and allocate in the new next page.
@@ -2794,7 +2808,7 @@ void MapSpace::VerifyObject(HeapObject* object) { CHECK(object->IsMap()); }
 
 
 // -----------------------------------------------------------------------------
-// CellSpace and PropertyCellSpace implementation
+// CellSpace implementation
 // TODO(mvstanton): this is weird...the compiler can't make a vtable unless
 // there is at least one non-inlined virtual function. I would prefer to hide
 // the VerifyObject definition behind VERIFY_HEAP.
@@ -2802,11 +2816,6 @@ void MapSpace::VerifyObject(HeapObject* object) { CHECK(object->IsMap()); }
 void CellSpace::VerifyObject(HeapObject* object) { CHECK(object->IsCell()); }
 
 
-void PropertyCellSpace::VerifyObject(HeapObject* object) {
-  CHECK(object->IsPropertyCell());
-}
-
-
 // -----------------------------------------------------------------------------
 // LargeObjectIterator
 
index 2eae029..0272d59 100644 (file)
@@ -385,6 +385,12 @@ class MemoryChunk {
     // to grey transition is performed in the value.
     HAS_PROGRESS_BAR,
 
+    // This flag is intended to be used for testing. Works only when both
+    // FLAG_stress_compaction and FLAG_manual_evacuation_candidates_selection
+    // are set. It forces the page to become an evacuation candidate at next
+    // candidates selection cycle.
+    FORCE_EVACUATION_CANDIDATE_FOR_TESTING,
+
     // Last flag, keep at bottom.
     NUM_MEMORY_CHUNK_FLAGS
   };
@@ -1871,6 +1877,7 @@ class PagedSpace : public Space {
   void CreateEmergencyMemory();
   void FreeEmergencyMemory();
   void UseEmergencyMemory();
+  intptr_t MaxEmergencyMemoryAllocated();
 
   bool HasEmergencyMemory() { return emergency_memory_ != NULL; }
 
@@ -2685,31 +2692,6 @@ class CellSpace : public PagedSpace {
 
 
 // -----------------------------------------------------------------------------
-// Old space for all global object property cell objects
-
-class PropertyCellSpace : public PagedSpace {
- public:
-  // Creates a property cell space object with a maximum capacity.
-  PropertyCellSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id)
-      : PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE) {}
-
-  virtual int RoundSizeDownToObjectAlignment(int size) {
-    if (base::bits::IsPowerOfTwo32(PropertyCell::kSize)) {
-      return RoundDown(size, PropertyCell::kSize);
-    } else {
-      return (size / PropertyCell::kSize) * PropertyCell::kSize;
-    }
-  }
-
- protected:
-  virtual void VerifyObject(HeapObject* obj);
-
- public:
-  TRACK_MEMORY("PropertyCellSpace")
-};
-
-
-// -----------------------------------------------------------------------------
 // Large objects ( > Page::kMaxHeapObjectSize ) are allocated and managed by
 // the large object space. A large object is allocated from OS heap with
 // extra padding bytes (Page::kPageSize + Page::kObjectStartOffset).
index 1606465..ccbe339 100644 (file)
@@ -49,14 +49,6 @@ void StoreBuffer::EnterDirectlyIntoStoreBuffer(Address addr) {
     }
   }
 }
-
-
-void StoreBuffer::ClearDeadObject(HeapObject* object) {
-  Address& map_field = Memory::Address_at(object->address());
-  if (heap_->map_space()->Contains(map_field)) {
-    map_field = NULL;
-  }
-}
 }
 }  // namespace v8::internal
 
index 591d28f..6bf3188 100644 (file)
@@ -6,7 +6,6 @@
 
 #include "src/v8.h"
 
-#include "src/base/atomicops.h"
 #include "src/counters.h"
 #include "src/heap/store-buffer-inl.h"
 
@@ -108,26 +107,6 @@ void StoreBuffer::StoreBufferOverflow(Isolate* isolate) {
 }
 
 
-void StoreBuffer::Uniq() {
-  // Remove adjacent duplicates and cells that do not point at new space.
-  Address previous = NULL;
-  Address* write = old_start_;
-  DCHECK(may_move_store_buffer_entries_);
-  for (Address* read = old_start_; read < old_top_; read++) {
-    Address current = *read;
-    if (current != previous) {
-      Object* object = reinterpret_cast<Object*>(
-          base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(current)));
-      if (heap_->InNewSpace(object)) {
-        *write++ = current;
-      }
-    }
-    previous = current;
-  }
-  old_top_ = write;
-}
-
-
 bool StoreBuffer::SpaceAvailable(intptr_t space_needed) {
   return old_limit_ - old_top_ >= space_needed;
 }
@@ -247,20 +226,6 @@ void StoreBuffer::Filter(int flag) {
 }
 
 
-void StoreBuffer::SortUniq() {
-  Compact();
-  if (old_buffer_is_sorted_) return;
-  std::sort(old_start_, old_top_);
-  Uniq();
-
-  old_buffer_is_sorted_ = true;
-
-  // Filtering hash sets are inconsistent with the store buffer after this
-  // operation.
-  ClearFilteringHashSets();
-}
-
-
 bool StoreBuffer::PrepareForIteration() {
   Compact();
   PointerChunkIterator it(heap_);
@@ -285,41 +250,6 @@ bool StoreBuffer::PrepareForIteration() {
 }
 
 
-#ifdef DEBUG
-void StoreBuffer::Clean() {
-  ClearFilteringHashSets();
-  Uniq();  // Also removes things that no longer point to new space.
-  EnsureSpace(kStoreBufferSize / 2);
-}
-
-
-static Address* in_store_buffer_1_element_cache = NULL;
-
-
-bool StoreBuffer::CellIsInStoreBuffer(Address cell_address) {
-  if (!FLAG_enable_slow_asserts) return true;
-  if (in_store_buffer_1_element_cache != NULL &&
-      *in_store_buffer_1_element_cache == cell_address) {
-    return true;
-  }
-  Address* top = reinterpret_cast<Address*>(heap_->store_buffer_top());
-  for (Address* current = top - 1; current >= start_; current--) {
-    if (*current == cell_address) {
-      in_store_buffer_1_element_cache = current;
-      return true;
-    }
-  }
-  for (Address* current = old_top_ - 1; current >= old_start_; current--) {
-    if (*current == cell_address) {
-      in_store_buffer_1_element_cache = current;
-      return true;
-    }
-  }
-  return false;
-}
-#endif
-
-
 void StoreBuffer::ClearFilteringHashSets() {
   if (!hash_sets_are_empty_) {
     memset(reinterpret_cast<void*>(hash_set_1_), 0,
@@ -350,8 +280,7 @@ void StoreBuffer::VerifyPointers(LargeObjectSpace* space) {
         // When we are not in GC the Heap::InNewSpace() predicate
         // checks that pointers which satisfy predicate point into
         // the active semispace.
-        Object* object = reinterpret_cast<Object*>(
-            base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
+        Object* object = *slot;
         heap_->InNewSpace(object);
         slot_address += kPointerSize;
       }
@@ -378,33 +307,40 @@ void StoreBuffer::GCEpilogue() {
 }
 
 
+void StoreBuffer::ProcessOldToNewSlot(Address slot_address,
+                                      ObjectSlotCallback slot_callback) {
+  Object** slot = reinterpret_cast<Object**>(slot_address);
+  Object* object = *slot;
+
+  // If the object is not in from space, it must be a duplicate store buffer
+  // entry and the slot was already updated.
+  if (heap_->InFromSpace(object)) {
+    HeapObject* heap_object = reinterpret_cast<HeapObject*>(object);
+    DCHECK(heap_object->IsHeapObject());
+    slot_callback(reinterpret_cast<HeapObject**>(slot), heap_object);
+    object = *slot;
+    // If the object was in from space before and is after executing the
+    // callback in to space, the object is still live.
+    // Unfortunately, we do not know about the slot. It could be in a
+    // just freed free space object.
+    if (heap_->InToSpace(object)) {
+      EnterDirectlyIntoStoreBuffer(reinterpret_cast<Address>(slot));
+    }
+  }
+}
+
+
 void StoreBuffer::FindPointersToNewSpaceInRegion(
-    Address start, Address end, ObjectSlotCallback slot_callback,
-    bool clear_maps) {
+    Address start, Address end, ObjectSlotCallback slot_callback) {
   for (Address slot_address = start; slot_address < end;
        slot_address += kPointerSize) {
-    Object** slot = reinterpret_cast<Object**>(slot_address);
-    Object* object = reinterpret_cast<Object*>(
-        base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
-    if (heap_->InNewSpace(object)) {
-      HeapObject* heap_object = reinterpret_cast<HeapObject*>(object);
-      DCHECK(heap_object->IsHeapObject());
-      // The new space object was not promoted if it still contains a map
-      // pointer. Clear the map field now lazily.
-      if (clear_maps) ClearDeadObject(heap_object);
-      slot_callback(reinterpret_cast<HeapObject**>(slot), heap_object);
-      object = reinterpret_cast<Object*>(
-          base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
-      if (heap_->InNewSpace(object)) {
-        EnterDirectlyIntoStoreBuffer(slot_address);
-      }
-    }
+    ProcessOldToNewSlot(slot_address, slot_callback);
   }
 }
 
 
-void StoreBuffer::IteratePointersInStoreBuffer(ObjectSlotCallback slot_callback,
-                                               bool clear_maps) {
+void StoreBuffer::IteratePointersInStoreBuffer(
+    ObjectSlotCallback slot_callback) {
   Address* limit = old_top_;
   old_top_ = old_start_;
   {
@@ -413,40 +349,57 @@ void StoreBuffer::IteratePointersInStoreBuffer(ObjectSlotCallback slot_callback,
 #ifdef DEBUG
       Address* saved_top = old_top_;
 #endif
-      Object** slot = reinterpret_cast<Object**>(*current);
-      Object* object = reinterpret_cast<Object*>(
-          base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
-      if (heap_->InFromSpace(object)) {
-        HeapObject* heap_object = reinterpret_cast<HeapObject*>(object);
-        // The new space object was not promoted if it still contains a map
-        // pointer. Clear the map field now lazily.
-        if (clear_maps) ClearDeadObject(heap_object);
-        slot_callback(reinterpret_cast<HeapObject**>(slot), heap_object);
-        object = reinterpret_cast<Object*>(
-            base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
-        if (heap_->InNewSpace(object)) {
-          EnterDirectlyIntoStoreBuffer(reinterpret_cast<Address>(slot));
-        }
-      }
+      ProcessOldToNewSlot(*current, slot_callback);
       DCHECK(old_top_ == saved_top + 1 || old_top_ == saved_top);
     }
   }
 }
 
 
-void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback) {
-  IteratePointersToNewSpace(slot_callback, false);
+void StoreBuffer::ClearInvalidStoreBufferEntries() {
+  Compact();
+  Address* new_top = old_start_;
+  for (Address* current = old_start_; current < old_top_; current++) {
+    Address addr = *current;
+    Object** slot = reinterpret_cast<Object**>(addr);
+    Object* object = *slot;
+    if (heap_->InNewSpace(object) && object->IsHeapObject()) {
+      // If the target object is not black, the source slot must be part
+      // of a non-black (dead) object.
+      HeapObject* heap_object = HeapObject::cast(object);
+      if (Marking::IsBlack(Marking::MarkBitFrom(heap_object)) &&
+          heap_->mark_compact_collector()->IsSlotInLiveObject(addr)) {
+        *new_top++ = addr;
+      }
+    }
+  }
+  old_top_ = new_top;
+  ClearFilteringHashSets();
+
+  // Don't scan on scavenge dead large objects.
+  LargeObjectIterator it(heap_->lo_space());
+  for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
+    MemoryChunk* chunk = MemoryChunk::FromAddress(object->address());
+    if (chunk->scan_on_scavenge() && !Marking::MarkBitFrom(object).Get()) {
+      chunk->set_scan_on_scavenge(false);
+    }
+  }
 }
 
 
-void StoreBuffer::IteratePointersToNewSpaceAndClearMaps(
-    ObjectSlotCallback slot_callback) {
-  IteratePointersToNewSpace(slot_callback, true);
+void StoreBuffer::VerifyValidStoreBufferEntries() {
+  for (Address* current = old_start_; current < old_top_; current++) {
+    Object** slot = reinterpret_cast<Object**>(*current);
+    Object* object = *slot;
+    CHECK(object->IsHeapObject());
+    CHECK(heap_->InNewSpace(object));
+    heap_->mark_compact_collector()->VerifyIsSlotInLiveObject(
+        reinterpret_cast<Address>(slot), HeapObject::cast(object));
+  }
 }
 
 
-void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback,
-                                            bool clear_maps) {
+void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback) {
   // We do not sort or remove duplicated entries from the store buffer because
   // we expect that callback will rebuild the store buffer thus removing
   // all duplicates and pointers to old space.
@@ -455,7 +408,7 @@ void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback,
   // TODO(gc): we want to skip slots on evacuation candidates
   // but we can't simply figure that out from slot address
   // because slot can belong to a large object.
-  IteratePointersInStoreBuffer(slot_callback, clear_maps);
+  IteratePointersInStoreBuffer(slot_callback);
 
   // We are done scanning all the pointers that were in the store buffer, but
   // there may be some pages marked scan_on_scavenge that have pointers to new
@@ -484,7 +437,7 @@ void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback,
           DCHECK(array->IsFixedArray());
           Address start = array->address();
           Address end = start + array->Size();
-          FindPointersToNewSpaceInRegion(start, end, slot_callback, clear_maps);
+          FindPointersToNewSpaceInRegion(start, end, slot_callback);
         } else {
           Page* page = reinterpret_cast<Page*>(chunk);
           PagedSpace* owner = reinterpret_cast<PagedSpace*>(page->owner());
@@ -499,7 +452,7 @@ void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback,
                 FindPointersToNewSpaceInRegion(
                     heap_object->address() + Map::kPointerFieldsBeginOffset,
                     heap_object->address() + Map::kPointerFieldsEndOffset,
-                    slot_callback, clear_maps);
+                    slot_callback);
               }
             }
           } else {
@@ -534,8 +487,7 @@ void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback,
                                         &end_of_region_offset)) {
                       FindPointersToNewSpaceInRegion(
                           obj_address + offset,
-                          obj_address + end_of_region_offset, slot_callback,
-                          clear_maps);
+                          obj_address + end_of_region_offset, slot_callback);
                     }
                     offset = end_of_region_offset;
                   }
@@ -545,7 +497,7 @@ void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback,
                   Address end_address = obj_address + end_offset;
                   // Object has only tagged fields.
                   FindPointersToNewSpaceInRegion(start_address, end_address,
-                                                 slot_callback, clear_maps);
+                                                 slot_callback);
 #if V8_DOUBLE_FIELDS_UNBOXING
                 }
 #endif
index 5efd692..6c571fc 100644 (file)
@@ -20,8 +20,7 @@ class StoreBuffer;
 typedef void (*ObjectSlotCallback)(HeapObject** from, HeapObject* to);
 
 typedef void (StoreBuffer::*RegionCallback)(Address start, Address end,
-                                            ObjectSlotCallback slot_callback,
-                                            bool clear_maps);
+                                            ObjectSlotCallback slot_callback);
 
 // Used to implement the write barrier by collecting addresses of pointers
 // between spaces.
@@ -60,10 +59,6 @@ class StoreBuffer {
   // surviving old-to-new pointers into the store buffer to rebuild it.
   void IteratePointersToNewSpace(ObjectSlotCallback callback);
 
-  // Same as IteratePointersToNewSpace but additonally clears maps in objects
-  // referenced from the store buffer that do not contain a forwarding pointer.
-  void IteratePointersToNewSpaceAndClearMaps(ObjectSlotCallback callback);
-
   static const int kStoreBufferOverflowBit = 1 << (14 + kPointerSizeLog2);
   static const int kStoreBufferSize = kStoreBufferOverflowBit;
   static const int kStoreBufferLength = kStoreBufferSize / sizeof(Address);
@@ -88,23 +83,20 @@ class StoreBuffer {
   bool old_buffer_is_sorted() { return old_buffer_is_sorted_; }
   bool old_buffer_is_filtered() { return old_buffer_is_filtered_; }
 
-  // Goes through the store buffer removing pointers to things that have
-  // been promoted.  Rebuilds the store buffer completely if it overflowed.
-  void SortUniq();
-
   void EnsureSpace(intptr_t space_needed);
   void Verify();
 
   bool PrepareForIteration();
 
-#ifdef DEBUG
-  void Clean();
-  // Slow, for asserts only.
-  bool CellIsInStoreBuffer(Address cell);
-#endif
-
   void Filter(int flag);
 
+  // Eliminates all stale store buffer entries from the store buffer, i.e.,
+  // slots that are not part of live objects anymore. This method must be
+  // called after marking, when the whole transitive closure is known and
+  // must be called before sweeping when mark bits are still intact.
+  void ClearInvalidStoreBufferEntries();
+  void VerifyValidStoreBufferEntries();
+
  private:
   Heap* heap_;
 
@@ -142,17 +134,13 @@ class StoreBuffer {
   void ClearFilteringHashSets();
 
   bool SpaceAvailable(intptr_t space_needed);
-  void Uniq();
   void ExemptPopularPages(int prime_sample_step, int threshold);
 
-  // Set the map field of the object to NULL if contains a map.
-  inline void ClearDeadObject(HeapObject* object);
-
-  void IteratePointersToNewSpace(ObjectSlotCallback callback, bool clear_maps);
+  void ProcessOldToNewSlot(Address slot_address,
+                           ObjectSlotCallback slot_callback);
 
   void FindPointersToNewSpaceInRegion(Address start, Address end,
-                                      ObjectSlotCallback slot_callback,
-                                      bool clear_maps);
+                                      ObjectSlotCallback slot_callback);
 
   // For each region of pointers on a page in use from an old space call
   // visit_pointer_region callback.
@@ -163,8 +151,7 @@ class StoreBuffer {
                              RegionCallback region_callback,
                              ObjectSlotCallback slot_callback);
 
-  void IteratePointersInStoreBuffer(ObjectSlotCallback slot_callback,
-                                    bool clear_maps);
+  void IteratePointersInStoreBuffer(ObjectSlotCallback slot_callback);
 
 #ifdef VERIFY_HEAP
   void VerifyPointers(LargeObjectSpace* space);
index 3bf8e9f..9d634a8 100644 (file)
@@ -380,7 +380,7 @@ BoundsCheckBbData* HBoundsCheckEliminationPhase::PreProcessBlock(
     if (!i->IsBoundsCheck()) continue;
 
     HBoundsCheck* check = HBoundsCheck::cast(i);
-    int32_t offset;
+    int32_t offset = 0;
     BoundsCheckKey* key =
         BoundsCheckKey::Create(zone(), check, &offset);
     if (key == NULL) continue;
index da986e3..2ada897 100644 (file)
@@ -346,17 +346,20 @@ SideEffects SideEffectsTracker::ComputeChanges(HInstruction* instr) {
   int index;
   SideEffects result(instr->ChangesFlags());
   if (result.ContainsFlag(kGlobalVars)) {
-    if (instr->IsStoreGlobalCell() &&
-        ComputeGlobalVar(HStoreGlobalCell::cast(instr)->cell(), &index)) {
-      result.RemoveFlag(kGlobalVars);
-      result.AddSpecial(GlobalVar(index));
-    } else {
-      for (index = 0; index < kNumberOfGlobalVars; ++index) {
+    if (instr->IsStoreNamedField()) {
+      HStoreNamedField* store = HStoreNamedField::cast(instr);
+      HConstant* target = HConstant::cast(store->object());
+      if (ComputeGlobalVar(Unique<PropertyCell>::cast(target->GetUnique()),
+                           &index)) {
+        result.RemoveFlag(kGlobalVars);
         result.AddSpecial(GlobalVar(index));
+        return result;
       }
     }
-  }
-  if (result.ContainsFlag(kInobjectFields)) {
+    for (index = 0; index < kNumberOfGlobalVars; ++index) {
+      result.AddSpecial(GlobalVar(index));
+    }
+  } else if (result.ContainsFlag(kInobjectFields)) {
     if (instr->IsStoreNamedField() &&
         ComputeInobjectField(HStoreNamedField::cast(instr)->access(), &index)) {
       result.RemoveFlag(kInobjectFields);
@@ -375,17 +378,20 @@ SideEffects SideEffectsTracker::ComputeDependsOn(HInstruction* instr) {
   int index;
   SideEffects result(instr->DependsOnFlags());
   if (result.ContainsFlag(kGlobalVars)) {
-    if (instr->IsLoadGlobalCell() &&
-        ComputeGlobalVar(HLoadGlobalCell::cast(instr)->cell(), &index)) {
-      result.RemoveFlag(kGlobalVars);
-      result.AddSpecial(GlobalVar(index));
-    } else {
-      for (index = 0; index < kNumberOfGlobalVars; ++index) {
+    if (instr->IsLoadNamedField()) {
+      HLoadNamedField* load = HLoadNamedField::cast(instr);
+      HConstant* target = HConstant::cast(load->object());
+      if (ComputeGlobalVar(Unique<PropertyCell>::cast(target->GetUnique()),
+                           &index)) {
+        result.RemoveFlag(kGlobalVars);
         result.AddSpecial(GlobalVar(index));
+        return result;
       }
     }
-  }
-  if (result.ContainsFlag(kInobjectFields)) {
+    for (index = 0; index < kNumberOfGlobalVars; ++index) {
+      result.AddSpecial(GlobalVar(index));
+    }
+  } else if (result.ContainsFlag(kInobjectFields)) {
     if (instr->IsLoadNamedField() &&
         ComputeInobjectField(HLoadNamedField::cast(instr)->access(), &index)) {
       result.RemoveFlag(kInobjectFields);
@@ -439,7 +445,8 @@ GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
 }
 
 
-bool SideEffectsTracker::ComputeGlobalVar(Unique<Cell> cell, int* index) {
+bool SideEffectsTracker::ComputeGlobalVar(Unique<PropertyCell> cell,
+                                          int* index) {
   for (int i = 0; i < num_global_vars_; ++i) {
     if (cell == global_vars_[i]) {
       *index = i;
index d04a6eb..542bc8a 100644 (file)
@@ -70,7 +70,7 @@ class SideEffectsTracker FINAL BASE_EMBEDDED {
 
  private:
   friend std::ostream& operator<<(std::ostream& os, const TrackedEffects& f);
-  bool ComputeGlobalVar(Unique<Cell> cell, int* index);
+  bool ComputeGlobalVar(Unique<PropertyCell> cell, int* index);
   bool ComputeInobjectField(HObjectAccess access, int* index);
 
   static int GlobalVar(int index) {
@@ -86,7 +86,7 @@ class SideEffectsTracker FINAL BASE_EMBEDDED {
 
   // Track up to four global vars.
   static const int kNumberOfGlobalVars = 4;
-  Unique<Cell> global_vars_[kNumberOfGlobalVars];
+  Unique<PropertyCell> global_vars_[kNumberOfGlobalVars];
   int num_global_vars_;
 
   // Track up to n inobject fields.
index b89bcc4..245c7c0 100644 (file)
@@ -871,7 +871,6 @@ bool HInstruction::CanDeoptimize() {
     case HValue::kInvokeFunction:
     case HValue::kLoadContextSlot:
     case HValue::kLoadFunctionPrototype:
-    case HValue::kLoadGlobalCell:
     case HValue::kLoadKeyed:
     case HValue::kLoadKeyedGeneric:
     case HValue::kMathFloorOfDiv:
@@ -887,7 +886,6 @@ bool HInstruction::CanDeoptimize() {
     case HValue::kSimulate:
     case HValue::kStackCheck:
     case HValue::kStoreContextSlot:
-    case HValue::kStoreGlobalCell:
     case HValue::kStoreKeyedGeneric:
     case HValue::kStringAdd:
     case HValue::kStringCompareAndBranch:
@@ -2946,7 +2944,7 @@ Maybe<HConstant*> HConstant::CopyToTruncatedInt32(Zone* zone) {
         HConstant(DoubleToInt32(double_value_), Representation::Integer32(),
                   NotInNewSpace(), object_);
   }
-  return Maybe<HConstant*>(res != NULL, res);
+  return res != NULL ? Just(res) : Nothing<HConstant*>();
 }
 
 
@@ -2962,7 +2960,7 @@ Maybe<HConstant*> HConstant::CopyToTruncatedNumber(Isolate* isolate,
   } else if (handle->IsNull()) {
     res = new(zone) HConstant(0);
   }
-  return Maybe<HConstant*>(res != NULL, res);
+  return res != NULL ? Just(res) : Nothing<HConstant*>();
 }
 
 
@@ -3624,24 +3622,6 @@ std::ostream& HTransitionElementsKind::PrintDataTo(
 }
 
 
-std::ostream& HLoadGlobalCell::PrintDataTo(std::ostream& os) const {  // NOLINT
-  os << "[" << *cell().handle() << "]";
-  if (details_.IsConfigurable()) os << " (configurable)";
-  if (details_.IsReadOnly()) os << " (read-only)";
-  return os;
-}
-
-
-bool HLoadGlobalCell::RequiresHoleCheck() const {
-  if (!details_.IsConfigurable()) return false;
-  for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
-    HValue* use = it.value();
-    if (!use->IsChange()) return true;
-  }
-  return false;
-}
-
-
 std::ostream& HLoadGlobalGeneric::PrintDataTo(
     std::ostream& os) const {  // NOLINT
   return os << name()->ToCString().get() << " ";
@@ -3655,14 +3635,6 @@ std::ostream& HInnerAllocatedObject::PrintDataTo(
 }
 
 
-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)";
-  return os;
-}
-
-
 std::ostream& HLoadContextSlot::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(value()) << "[" << slot_index() << "]";
 }
@@ -3788,12 +3760,12 @@ bool HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
     }
   }
 
-  DCHECK((IsNewSpaceAllocation() &&
-         dominator_allocate->IsNewSpaceAllocation()) ||
-         (IsOldDataSpaceAllocation() &&
-         dominator_allocate->IsOldDataSpaceAllocation()) ||
-         (IsOldPointerSpaceAllocation() &&
-         dominator_allocate->IsOldPointerSpaceAllocation()));
+  DCHECK(
+      (IsNewSpaceAllocation() && dominator_allocate->IsNewSpaceAllocation()) ||
+      (IsOldDataSpaceAllocation() &&
+       dominator_allocate->IsOldDataSpaceAllocation()) ||
+      (IsOldPointerSpaceAllocation() &&
+       dominator_allocate->IsOldPointerSpaceAllocation()));
 
   // First update the size of the dominator allocate instruction.
   dominator_size = dominator_allocate->size();
@@ -3889,8 +3861,8 @@ HAllocate* HAllocate::GetFoldableDominator(HAllocate* dominator) {
     // We cannot hoist old space allocations over new space allocations.
     if (IsNewSpaceAllocation() || dominator->IsNewSpaceAllocation()) {
       if (FLAG_trace_allocation_folding) {
-        PrintF("#%d (%s) cannot fold into #%d (%s), new space hoisting\n",
-            id(), Mnemonic(), dominator->id(), dominator->Mnemonic());
+        PrintF("#%d (%s) cannot fold into #%d (%s), new space hoisting\n", id(),
+               Mnemonic(), dominator->id(), dominator->Mnemonic());
       }
       return NULL;
     }
@@ -3903,8 +3875,8 @@ HAllocate* HAllocate::GetFoldableDominator(HAllocate* dominator) {
     if (dominator_dominator == NULL) {
       dominating_allocate_ = dominator;
       if (FLAG_trace_allocation_folding) {
-        PrintF("#%d (%s) cannot fold into #%d (%s), different spaces\n",
-            id(), Mnemonic(), dominator->id(), dominator->Mnemonic());
+        PrintF("#%d (%s) cannot fold into #%d (%s), different spaces\n", id(),
+               Mnemonic(), dominator->id(), dominator->Mnemonic());
       }
       return NULL;
     }
@@ -3917,16 +3889,16 @@ HAllocate* HAllocate::GetFoldableDominator(HAllocate* dominator) {
     if (block()->block_id() != dominator_dominator->block()->block_id()) {
       if (FLAG_trace_allocation_folding) {
         PrintF("#%d (%s) cannot fold into #%d (%s), different basic blocks\n",
-            id(), Mnemonic(), dominator_dominator->id(),
-            dominator_dominator->Mnemonic());
+               id(), Mnemonic(), dominator_dominator->id(),
+               dominator_dominator->Mnemonic());
       }
       return NULL;
     }
 
     DCHECK((IsOldDataSpaceAllocation() &&
-           dominator_dominator->IsOldDataSpaceAllocation()) ||
+            dominator_dominator->IsOldDataSpaceAllocation()) ||
            (IsOldPointerSpaceAllocation() &&
-           dominator_dominator->IsOldPointerSpaceAllocation()));
+            dominator_dominator->IsOldPointerSpaceAllocation()));
 
     int32_t current_size = HConstant::cast(size())->GetInteger32Constant();
     HStoreNamedField* dominator_free_space_size =
@@ -4695,12 +4667,6 @@ HObjectAccess HObjectAccess::ForField(Handle<Map> map, int index,
 }
 
 
-HObjectAccess HObjectAccess::ForCellPayload(Isolate* isolate) {
-  return HObjectAccess(kInobject, Cell::kValueOffset, Representation::Tagged(),
-                       isolate->factory()->cell_value_string());
-}
-
-
 void HObjectAccess::SetGVNFlags(HValue *instr, PropertyAccessType access_type) {
   // set the appropriate GVN flags for a given load or store instruction
   if (access_type == STORE) {
index 8fd2aed..2461ee4 100644 (file)
@@ -117,7 +117,6 @@ class LChunkBuilder;
   V(LoadContextSlot)                          \
   V(LoadFieldByIndex)                         \
   V(LoadFunctionPrototype)                    \
-  V(LoadGlobalCell)                           \
   V(LoadGlobalGeneric)                        \
   V(LoadKeyed)                                \
   V(LoadKeyedGeneric)                         \
@@ -146,7 +145,6 @@ class LChunkBuilder;
   V(StoreCodeEntry)                           \
   V(StoreContextSlot)                         \
   V(StoreFrameContext)                        \
-  V(StoreGlobalCell)                          \
   V(StoreKeyed)                               \
   V(StoreKeyedGeneric)                        \
   V(StoreNamedField)                          \
@@ -982,7 +980,7 @@ class HPositionInfo {
     if (has_operand_positions()) {
       return operand_positions()[kInstructionPosIndex];
     }
-    return SourcePosition(static_cast<int>(UntagPosition(data_)));
+    return SourcePosition::FromRaw(static_cast<int>(UntagPosition(data_)));
   }
 
   void set_position(SourcePosition pos) {
@@ -1961,6 +1959,8 @@ class HEnterInlined FINAL : public HTemplateInstruction<0> {
   FunctionLiteral* function() const { return function_; }
   InliningKind inlining_kind() const { return inlining_kind_; }
   BailoutId ReturnId() const { return return_id_; }
+  int inlining_id() const { return inlining_id_; }
+  void set_inlining_id(int inlining_id) { inlining_id_ = inlining_id; }
 
   Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
@@ -1984,6 +1984,7 @@ class HEnterInlined FINAL : public HTemplateInstruction<0> {
         arguments_pushed_(false),
         function_(function),
         inlining_kind_(inlining_kind),
+        inlining_id_(0),
         arguments_var_(arguments_var),
         arguments_object_(arguments_object),
         return_targets_(2, zone) {}
@@ -1995,6 +1996,7 @@ class HEnterInlined FINAL : public HTemplateInstruction<0> {
   bool arguments_pushed_;
   FunctionLiteral* function_;
   InliningKind inlining_kind_;
+  int inlining_id_;
   Variable* arguments_var_;
   HArgumentsObject* arguments_object_;
   ZoneList<HBasicBlock*> return_targets_;
@@ -2572,7 +2574,9 @@ class HUnaryMathOperation FINAL : public HTemplateInstruction<2> {
   // Math.round.
   bool SupportsFlexibleFloorAndRound() const {
 #ifdef V8_TARGET_ARCH_ARM64
-    return true;
+    // TODO(rmcilroy): Re-enable this for Arm64 once http://crbug.com/476477 is
+    // fixed.
+    return false;
 #else
     return false;
 #endif
@@ -3497,7 +3501,7 @@ class HConstant FINAL : public HTemplateInstruction<0> {
 
   bool IsCell() const {
     InstanceType instance_type = GetInstanceType();
-    return instance_type == CELL_TYPE || instance_type == PROPERTY_CELL_TYPE;
+    return instance_type == CELL_TYPE;
   }
 
   Representation RequiredInputRepresentation(int index) OVERRIDE {
@@ -5410,46 +5414,6 @@ class HUnknownOSRValue FINAL : public HTemplateInstruction<0> {
 };
 
 
-class HLoadGlobalCell FINAL : public HTemplateInstruction<0> {
- public:
-  DECLARE_INSTRUCTION_FACTORY_P2(HLoadGlobalCell, Handle<Cell>,
-                                 PropertyDetails);
-
-  Unique<Cell> cell() const { return cell_; }
-  bool RequiresHoleCheck() const;
-
-  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
-
-  intptr_t Hashcode() OVERRIDE { return cell_.Hashcode(); }
-
-  void FinalizeUniqueness() OVERRIDE { cell_ = Unique<Cell>(cell_.handle()); }
-
-  Representation RequiredInputRepresentation(int index) OVERRIDE {
-    return Representation::None();
-  }
-
-  DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell)
-
- protected:
-  bool DataEquals(HValue* other) OVERRIDE {
-    return cell_ == HLoadGlobalCell::cast(other)->cell_;
-  }
-
- private:
-  HLoadGlobalCell(Handle<Cell> cell, PropertyDetails details)
-    : cell_(Unique<Cell>::CreateUninitialized(cell)), details_(details) {
-    set_representation(Representation::Tagged());
-    SetFlag(kUseGVN);
-    SetDependsOnFlag(kGlobalVars);
-  }
-
-  bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
-
-  Unique<Cell> cell_;
-  PropertyDetails details_;
-};
-
-
 class HLoadGlobalGeneric FINAL : public HTemplateInstruction<2> {
  public:
   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*,
@@ -5623,9 +5587,10 @@ class HAllocate FINAL : public HTemplateInstruction<2> {
   static Flags ComputeFlags(PretenureFlag pretenure_flag,
                             InstanceType instance_type) {
     Flags flags = pretenure_flag == TENURED
-        ? (Heap::TargetSpaceId(instance_type) == OLD_POINTER_SPACE
-            ? ALLOCATE_IN_OLD_POINTER_SPACE : ALLOCATE_IN_OLD_DATA_SPACE)
-        : ALLOCATE_IN_NEW_SPACE;
+                      ? (Heap::TargetSpaceId(instance_type) == OLD_POINTER_SPACE
+                             ? ALLOCATE_IN_OLD_POINTER_SPACE
+                             : ALLOCATE_IN_OLD_DATA_SPACE)
+                      : ALLOCATE_IN_NEW_SPACE;
     if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
       flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
     }
@@ -5667,8 +5632,9 @@ class HAllocate FINAL : public HTemplateInstruction<2> {
 
   bool IsFoldable(HAllocate* allocate) {
     return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
-        (IsOldDataSpaceAllocation() && allocate->IsOldDataSpaceAllocation()) ||
-        (IsOldPointerSpaceAllocation() &&
+           (IsOldDataSpaceAllocation() &&
+            allocate->IsOldDataSpaceAllocation()) ||
+           (IsOldPointerSpaceAllocation() &&
             allocate->IsOldPointerSpaceAllocation());
   }
 
@@ -5801,43 +5767,6 @@ inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
 }
 
 
-class HStoreGlobalCell FINAL : public HUnaryOperation {
- public:
-  DECLARE_INSTRUCTION_FACTORY_P3(HStoreGlobalCell, HValue*,
-                                 Handle<PropertyCell>, PropertyDetails);
-
-  Unique<PropertyCell> cell() const { return cell_; }
-  bool RequiresHoleCheck() { return details_.IsConfigurable(); }
-  bool NeedsWriteBarrier() {
-    return StoringValueNeedsWriteBarrier(value());
-  }
-
-  void FinalizeUniqueness() OVERRIDE {
-    cell_ = Unique<PropertyCell>(cell_.handle());
-  }
-
-  Representation RequiredInputRepresentation(int index) OVERRIDE {
-    return Representation::Tagged();
-  }
-  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
-
-  DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell)
-
- private:
-  HStoreGlobalCell(HValue* value,
-                   Handle<PropertyCell> cell,
-                   PropertyDetails details)
-      : HUnaryOperation(value),
-        cell_(Unique<PropertyCell>::CreateUninitialized(cell)),
-        details_(details) {
-    SetChangesFlag(kGlobalVars);
-  }
-
-  Unique<PropertyCell> cell_;
-  PropertyDetails details_;
-};
-
-
 class HLoadContextSlot FINAL : public HUnaryOperation {
  public:
   enum Mode {
@@ -6222,9 +6151,6 @@ class HObjectAccess FINAL {
                                 Representation representation,
                                 Handle<String> name);
 
-  // Create an access for the payload of a Cell or JSGlobalPropertyCell.
-  static HObjectAccess ForCellPayload(Isolate* isolate);
-
   static HObjectAccess ForJSTypedArrayLength() {
     return HObjectAccess::ForObservableJSObjectOffset(
         JSTypedArray::kLengthOffset);
@@ -6509,13 +6435,16 @@ class HLoadNamedField FINAL : public HTemplateInstruction<2> {
 
 class HLoadNamedGeneric FINAL : public HTemplateInstruction<2> {
  public:
-  DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadNamedGeneric, HValue*,
-                                              Handle<Object>);
+  DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadNamedGeneric, HValue*,
+                                              Handle<Object>, InlineCacheState);
 
   HValue* context() const { return OperandAt(0); }
   HValue* object() const { return OperandAt(1); }
   Handle<Object> name() const { return name_; }
 
+  InlineCacheState initialization_state() const {
+    return initialization_state_;
+  }
   FeedbackVectorICSlot slot() const { return slot_; }
   Handle<TypeFeedbackVector> feedback_vector() const {
     return feedback_vector_;
@@ -6537,8 +6466,11 @@ class HLoadNamedGeneric FINAL : public HTemplateInstruction<2> {
   DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
 
  private:
-  HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
-      : name_(name), slot_(FeedbackVectorICSlot::Invalid()) {
+  HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name,
+                    InlineCacheState initialization_state)
+      : name_(name),
+        slot_(FeedbackVectorICSlot::Invalid()),
+        initialization_state_(initialization_state) {
     SetOperandAt(0, context);
     SetOperandAt(1, object);
     set_representation(Representation::Tagged());
@@ -6548,6 +6480,7 @@ class HLoadNamedGeneric FINAL : public HTemplateInstruction<2> {
   Handle<Object> name_;
   Handle<TypeFeedbackVector> feedback_vector_;
   FeedbackVectorICSlot slot_;
+  InlineCacheState initialization_state_;
 };
 
 
@@ -6787,11 +6720,14 @@ class HLoadKeyed FINAL
 
 class HLoadKeyedGeneric FINAL : public HTemplateInstruction<3> {
  public:
-  DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadKeyedGeneric, HValue*,
-                                              HValue*);
+  DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadKeyedGeneric, HValue*,
+                                              HValue*, InlineCacheState);
   HValue* object() const { return OperandAt(0); }
   HValue* key() const { return OperandAt(1); }
   HValue* context() const { return OperandAt(2); }
+  InlineCacheState initialization_state() const {
+    return initialization_state_;
+  }
   FeedbackVectorICSlot slot() const { return slot_; }
   Handle<TypeFeedbackVector> feedback_vector() const {
     return feedback_vector_;
@@ -6816,8 +6752,10 @@ class HLoadKeyedGeneric FINAL : public HTemplateInstruction<3> {
   DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
 
  private:
-  HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key)
-      : slot_(FeedbackVectorICSlot::Invalid()) {
+  HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key,
+                    InlineCacheState initialization_state)
+      : slot_(FeedbackVectorICSlot::Invalid()),
+        initialization_state_(initialization_state) {
     set_representation(Representation::Tagged());
     SetOperandAt(0, obj);
     SetOperandAt(1, key);
@@ -6827,6 +6765,7 @@ class HLoadKeyedGeneric FINAL : public HTemplateInstruction<3> {
 
   Handle<TypeFeedbackVector> feedback_vector_;
   FeedbackVectorICSlot slot_;
+  InlineCacheState initialization_state_;
 };
 
 
@@ -6915,14 +6854,6 @@ class HStoreNamedField FINAL : public HTemplateInstruction<3> {
     SetChangesFlag(kMaps);
   }
 
-  void MarkReceiverAsCell() {
-    bit_field_ = ReceiverIsCellField::update(bit_field_, true);
-  }
-
-  bool receiver_is_cell() const {
-    return ReceiverIsCellField::decode(bit_field_);
-  }
-
   bool NeedsWriteBarrier() const {
     DCHECK(!field_representation().IsDouble() ||
            (FLAG_unbox_double_fields && access_.IsInobject()) ||
@@ -6931,7 +6862,6 @@ class HStoreNamedField FINAL : public HTemplateInstruction<3> {
     if (field_representation().IsSmi()) return false;
     if (field_representation().IsInteger32()) return false;
     if (field_representation().IsExternal()) return false;
-    if (receiver_is_cell()) return false;
     return StoringValueNeedsWriteBarrier(value()) &&
         ReceiverObjectNeedsWriteBarrier(object(), value(), dominator());
   }
@@ -6991,7 +6921,6 @@ class HStoreNamedField FINAL : public HTemplateInstruction<3> {
 
   class HasTransitionField : public BitField<bool, 0, 1> {};
   class StoreModeField : public BitField<StoreFieldOrKeyedMode, 1, 1> {};
-  class ReceiverIsCellField : public BitField<bool, 2, 1> {};
 
   HObjectAccess access_;
   HValue* dominator_;
@@ -7001,14 +6930,17 @@ class HStoreNamedField FINAL : public HTemplateInstruction<3> {
 
 class HStoreNamedGeneric FINAL : public HTemplateInstruction<3> {
  public:
-  DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreNamedGeneric, HValue*,
+  DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreNamedGeneric, HValue*,
                                               Handle<String>, HValue*,
-                                              LanguageMode);
+                                              LanguageMode, InlineCacheState);
   HValue* object() const { return OperandAt(0); }
   HValue* value() const { return OperandAt(1); }
   HValue* context() const { return OperandAt(2); }
   Handle<String> name() const { return name_; }
   LanguageMode language_mode() const { return language_mode_; }
+  InlineCacheState initialization_state() const {
+    return initialization_state_;
+  }
 
   std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
@@ -7020,8 +6952,11 @@ class HStoreNamedGeneric FINAL : public HTemplateInstruction<3> {
 
  private:
   HStoreNamedGeneric(HValue* context, HValue* object, Handle<String> name,
-                     HValue* value, LanguageMode language_mode)
-      : name_(name), language_mode_(language_mode) {
+                     HValue* value, LanguageMode language_mode,
+                     InlineCacheState initialization_state)
+      : name_(name),
+        language_mode_(language_mode),
+        initialization_state_(initialization_state) {
     SetOperandAt(0, object);
     SetOperandAt(1, value);
     SetOperandAt(2, context);
@@ -7030,6 +6965,7 @@ class HStoreNamedGeneric FINAL : public HTemplateInstruction<3> {
 
   Handle<String> name_;
   LanguageMode language_mode_;
+  InlineCacheState initialization_state_;
 };
 
 
@@ -7219,14 +7155,18 @@ class HStoreKeyed FINAL
 
 class HStoreKeyedGeneric FINAL : public HTemplateInstruction<4> {
  public:
-  DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreKeyedGeneric, HValue*,
-                                              HValue*, HValue*, LanguageMode);
+  DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreKeyedGeneric, HValue*,
+                                              HValue*, HValue*, LanguageMode,
+                                              InlineCacheState);
 
   HValue* object() const { return OperandAt(0); }
   HValue* key() const { return OperandAt(1); }
   HValue* value() const { return OperandAt(2); }
   HValue* context() const { return OperandAt(3); }
   LanguageMode language_mode() const { return language_mode_; }
+  InlineCacheState initialization_state() const {
+    return initialization_state_;
+  }
 
   Representation RequiredInputRepresentation(int index) OVERRIDE {
     // tagged[tagged] = tagged
@@ -7239,8 +7179,10 @@ class HStoreKeyedGeneric FINAL : public HTemplateInstruction<4> {
 
  private:
   HStoreKeyedGeneric(HValue* context, HValue* object, HValue* key,
-                     HValue* value, LanguageMode language_mode)
-      : language_mode_(language_mode) {
+                     HValue* value, LanguageMode language_mode,
+                     InlineCacheState initialization_state)
+      : language_mode_(language_mode),
+        initialization_state_(initialization_state) {
     SetOperandAt(0, object);
     SetOperandAt(1, key);
     SetOperandAt(2, value);
@@ -7249,6 +7191,7 @@ class HStoreKeyedGeneric FINAL : public HTemplateInstruction<4> {
   }
 
   LanguageMode language_mode_;
+  InlineCacheState initialization_state_;
 };
 
 
@@ -7562,11 +7505,11 @@ class HFunctionLiteral FINAL : public HTemplateInstruction<1> {
 
   bool IsDeletable() const OVERRIDE { return true; }
 
-  class FunctionKindField : public BitField<FunctionKind, 0, 6> {};
-  class PretenureField : public BitField<bool, 6, 1> {};
-  class HasNoLiteralsField : public BitField<bool, 7, 1> {};
+  class FunctionKindField : public BitField<FunctionKind, 0, 8> {};
+  class PretenureField : public BitField<bool, 8, 1> {};
+  class HasNoLiteralsField : public BitField<bool, 9, 1> {};
   STATIC_ASSERT(LANGUAGE_END == 3);
-  class LanguageModeField : public BitField<LanguageMode, 8, 2> {};
+  class LanguageModeField : public BitField<LanguageMode, 10, 2> {};
 
   Handle<SharedFunctionInfo> shared_info_;
   uint32_t bit_field_;
index bfc8271..33adf5a 100644 (file)
@@ -29,7 +29,7 @@ void HRepresentationChangesPhase::InsertRepresentationChangeForUse(
     // Try to create a new copy of the constant with the new representation.
     if (is_truncating_to_int && to.IsInteger32()) {
       Maybe<HConstant*> res = constant->CopyToTruncatedInt32(graph()->zone());
-      if (res.has_value) new_value = res.value;
+      if (res.IsJust()) new_value = res.FromJust();
     } else {
       new_value = constant->CopyToRepresentation(to, graph()->zone());
     }
index 8551b10..ae717e4 100644 (file)
@@ -1751,8 +1751,7 @@ HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver,
     details_index->ClearFlag(HValue::kCanOverflow);
     HValue* details =
         Add<HLoadKeyed>(elements, details_index, nullptr, FAST_ELEMENTS);
-    int details_mask = PropertyDetails::TypeField::kMask |
-                       PropertyDetails::DeletedField::kMask;
+    int details_mask = PropertyDetails::TypeField::kMask;
     details = AddUncasted<HBitwise>(Token::BIT_AND, details,
                                     Add<HConstant>(details_mask));
     IfBuilder details_compare(this);
@@ -2320,10 +2319,8 @@ HValue* HGraphBuilder::BuildUncheckedStringAdd(
     {
       // Fallback to the runtime to add the two strings.
       Add<HPushArguments>(left, right);
-      Push(Add<HCallRuntime>(
-            isolate()->factory()->empty_string(),
-            Runtime::FunctionForId(Runtime::kStringAdd),
-            2));
+      Push(Add<HCallRuntime>(isolate()->factory()->empty_string(),
+                             Runtime::FunctionForId(Runtime::kStringAddRT), 2));
     }
     if_sameencodingandsequential.End();
   }
@@ -3350,7 +3347,7 @@ HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info)
   // to know it's the initial state.
   function_state_ = &initial_function_state_;
   InitializeAstVisitor(info->isolate(), info->zone());
-  if (FLAG_hydrogen_track_positions) {
+  if (top_info()->is_tracking_positions()) {
     SetSourcePosition(info->shared_info()->start_position());
   }
 }
@@ -3443,6 +3440,7 @@ HGraph::HGraph(CompilationInfo* info)
       info_(info),
       zone_(info->zone()),
       is_recursive_(false),
+      this_has_uses_(false),
       use_optimistic_licm_(false),
       depends_on_empty_array_proto_elements_(false),
       type_change_checksum_(0),
@@ -3455,7 +3453,10 @@ HGraph::HGraph(CompilationInfo* info)
     start_environment_ = new (zone_)
         HEnvironment(zone_, descriptor.GetEnvironmentParameterCount());
   } else {
-    info->TraceInlinedFunction(info->shared_info(), SourcePosition::Unknown());
+    if (info->is_tracking_positions()) {
+      info->TraceInlinedFunction(info->shared_info(), SourcePosition::Unknown(),
+                                 InlinedFunctionInfo::kNoParentId);
+    }
     start_environment_ =
         new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_);
   }
@@ -3484,13 +3485,9 @@ void HGraph::FinalizeUniqueness() {
 
 
 int HGraph::SourcePositionToScriptPosition(SourcePosition pos) {
-  if (!FLAG_hydrogen_track_positions || pos.IsUnknown()) {
-    return pos.raw();
-  }
-
-  const int id = info()->inlining_id_to_function_id()->at(pos.inlining_id());
-  return info()->inlined_function_infos()->at(id).start_position() +
-         pos.position();
+  return (FLAG_hydrogen_track_positions && !pos.IsUnknown())
+             ? info()->start_position_for(pos.inlining_id()) + pos.position()
+             : pos.raw();
 }
 
 
@@ -3914,7 +3911,7 @@ FunctionState::FunctionState(HOptimizedGraphBuilder* owner,
   // Push on the state stack.
   owner->set_function_state(this);
 
-  if (FLAG_hydrogen_track_positions) {
+  if (compilation_info_->is_tracking_positions()) {
     outer_source_position_ = owner->source_position();
     owner->EnterInlinedSource(
       info->shared_info()->start_position(),
@@ -3928,7 +3925,7 @@ FunctionState::~FunctionState() {
   delete test_context_;
   owner_->set_function_state(outer_);
 
-  if (FLAG_hydrogen_track_positions) {
+  if (compilation_info_->is_tracking_positions()) {
     owner_->set_source_position(outer_source_position_);
     owner_->EnterInlinedSource(
       outer_->compilation_info()->shared_info()->start_position(),
@@ -5267,6 +5264,7 @@ HOptimizedGraphBuilder::LookupGlobalProperty(Variable* var, LookupIterator* it,
     case LookupIterator::ACCESSOR:
     case LookupIterator::ACCESS_CHECK:
     case LookupIterator::INTERCEPTOR:
+    case LookupIterator::INTEGER_INDEXED_EXOTIC:
     case LookupIterator::NOT_FOUND:
       return kUseGeneric;
     case LookupIterator::DATA:
@@ -5296,7 +5294,7 @@ HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
 
 void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
   if (expr->is_this()) {
-    current_info()->set_this_has_uses(true);
+    graph()->MarkThisHasUses();
   }
 
   DCHECK(!HasStackOverflow());
@@ -5320,7 +5318,8 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
 
       Handle<GlobalObject> global(current_info()->global_object());
 
-      if (FLAG_harmony_scoping) {
+      // Lookup in script contexts.
+      {
         Handle<ScriptContextTable> script_contexts(
             global->native_context()->script_context_table());
         ScriptContextTable::LookupResult lookup;
@@ -5329,7 +5328,7 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
           Handle<Context> script_context = ScriptContextTable::GetContext(
               script_contexts, lookup.context_index);
           Handle<Object> current_value =
-              FixedArray::get(script_context, lookup.context_index);
+              FixedArray::get(script_context, lookup.slot_index);
 
           // If the values is not the hole, it will stay initialized,
           // so no need to generate a check.
@@ -5349,9 +5348,9 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
 
       if (type == kUseCell) {
         Handle<PropertyCell> cell = it.GetPropertyCell();
-        if (cell->type()->IsConstant()) {
-          PropertyCell::AddDependentCompilationInfo(cell, top_info());
-          Handle<Object> constant_object = cell->type()->AsConstant()->Value();
+        PropertyCell::AddDependentCompilationInfo(cell, top_info());
+        if (it.property_details().cell_type() == PropertyCellType::kConstant) {
+          Handle<Object> constant_object(cell->value(), isolate());
           if (constant_object->IsConsString()) {
             constant_object =
                 String::Flatten(Handle<String>::cast(constant_object));
@@ -5359,8 +5358,11 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
           HConstant* constant = New<HConstant>(constant_object);
           return ast_context()->ReturnInstruction(constant, expr->id());
         } else {
-          HLoadGlobalCell* instr =
-              New<HLoadGlobalCell>(cell, it.property_details());
+          HConstant* cell_constant = Add<HConstant>(cell);
+          HLoadNamedField* instr = New<HLoadNamedField>(
+              cell_constant, nullptr, HObjectAccess::ForPropertyCellValue());
+          instr->ClearDependsOnFlag(kInobjectFields);
+          instr->SetDependsOnFlag(kGlobalVars);
           return ast_context()->ReturnInstruction(instr, expr->id());
         }
       } else {
@@ -5445,9 +5447,10 @@ void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
 static bool CanInlinePropertyAccess(Handle<Map> map) {
   if (map->instance_type() == HEAP_NUMBER_TYPE) return true;
   if (map->instance_type() < FIRST_NONSTRING_TYPE) return true;
-  return map->IsJSObjectMap() &&
-      !map->is_dictionary_map() &&
-      !map->has_named_interceptor();
+  return map->IsJSObjectMap() && !map->is_dictionary_map() &&
+         !map->has_named_interceptor() &&
+         // TODO(verwaest): Whitelist contexts to which we have access.
+         !map->is_access_check_needed();
 }
 
 
@@ -5963,7 +5966,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible(
 
 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() {
   if (!map_->IsJSObjectMap()) return true;
-  lookup_.LookupDescriptor(*map_, *name_);
+  LookupDescriptor(*map_, *name_);
   return LoadResult(map_);
 }
 
@@ -5979,7 +5982,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
     access_ = HObjectAccess::ForField(map, index, representation(), name_);
 
     // Load field map for heap objects.
-    LoadFieldMaps(map);
+    return LoadFieldMaps(map);
   } else if (IsAccessorConstant()) {
     Handle<Object> accessors = GetAccessorsFromMap(map);
     if (!accessors->IsAccessorPair()) return false;
@@ -6005,7 +6008,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
 }
 
 
-void HOptimizedGraphBuilder::PropertyAccessInfo::LoadFieldMaps(
+bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadFieldMaps(
     Handle<Map> map) {
   // Clear any previously collected field maps/type.
   field_maps_.Clear();
@@ -6016,19 +6019,26 @@ void HOptimizedGraphBuilder::PropertyAccessInfo::LoadFieldMaps(
 
   // Collect the (stable) maps from the field type.
   int num_field_maps = field_type->NumClasses();
-  if (num_field_maps == 0) return;
-  DCHECK(access_.representation().IsHeapObject());
-  field_maps_.Reserve(num_field_maps, zone());
-  HeapType::Iterator<Map> it = field_type->Classes();
-  while (!it.Done()) {
-    Handle<Map> field_map = it.Current();
-    if (!field_map->is_stable()) {
-      field_maps_.Clear();
-      return;
+  if (num_field_maps > 0) {
+    DCHECK(access_.representation().IsHeapObject());
+    field_maps_.Reserve(num_field_maps, zone());
+    HeapType::Iterator<Map> it = field_type->Classes();
+    while (!it.Done()) {
+      Handle<Map> field_map = it.Current();
+      if (!field_map->is_stable()) {
+        field_maps_.Clear();
+        break;
+      }
+      field_maps_.Add(field_map, zone());
+      it.Advance();
     }
-    field_maps_.Add(field_map, zone());
-    it.Advance();
   }
+
+  if (field_maps_.is_empty()) {
+    // Store is not safe if the field map was cleared.
+    return IsLoad() || !field_type->Is(HeapType::None());
+  }
+
   field_maps_.Sort();
   DCHECK_EQ(num_field_maps, field_maps_.length());
 
@@ -6039,6 +6049,7 @@ void HOptimizedGraphBuilder::PropertyAccessInfo::LoadFieldMaps(
   // Add dependency on the map that introduced the field.
   Map::AddDependentCompilationInfo(GetFieldOwnerFromMap(map),
                                    DependentCode::kFieldTypeGroup, top_info());
+  return true;
 }
 
 
@@ -6052,17 +6063,23 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
     }
     map = Handle<Map>(holder_->map());
     if (!CanInlinePropertyAccess(map)) {
-      lookup_.NotFound();
+      NotFound();
       return false;
     }
-    lookup_.LookupDescriptor(*map, *name_);
+    LookupDescriptor(*map, *name_);
     if (IsFound()) return LoadResult(map);
   }
-  lookup_.NotFound();
+  NotFound();
   return true;
 }
 
 
+bool HOptimizedGraphBuilder::PropertyAccessInfo::IsIntegerIndexedExotic() {
+  InstanceType instance_type = map_->instance_type();
+  return instance_type == JS_TYPED_ARRAY_TYPE && IsNonArrayIndexInteger(*name_);
+}
+
+
 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
   if (!CanInlinePropertyAccess(map_)) return false;
   if (IsJSObjectFieldAccessor()) return IsLoad();
@@ -6072,12 +6089,13 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
   }
   if (!LookupDescriptor()) return false;
   if (IsFound()) return IsLoad() || !IsReadOnly();
+  if (IsIntegerIndexedExotic()) return false;
   if (!LookupInPrototypes()) return false;
   if (IsLoad()) return true;
 
   if (IsAccessorConstant()) return true;
-  lookup_.LookupTransition(*map_, *name_, NONE);
-  if (lookup_.IsTransitionToData() && map_->unused_property_fields() > 0) {
+  LookupTransition(*map_, *name_, NONE);
+  if (IsTransitionToData() && map_->unused_property_fields() > 0) {
     // Construct the object field access.
     int descriptor = transition()->LastAdded();
     int index =
@@ -6089,8 +6107,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
     access_ = HObjectAccess::ForField(map_, index, representation, name_);
 
     // Load field map for heap objects.
-    LoadFieldMaps(transition());
-    return true;
+    return LoadFieldMaps(transition());
   }
   return false;
 }
@@ -6464,7 +6481,8 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
     BailoutId ast_id) {
   Handle<GlobalObject> global(current_info()->global_object());
 
-  if (FLAG_harmony_scoping) {
+  // Lookup in script contexts.
+  {
     Handle<ScriptContextTable> script_contexts(
         global->native_context()->script_context_table());
     ScriptContextTable::LookupResult lookup;
@@ -6474,6 +6492,16 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
       }
       Handle<Context> script_context =
           ScriptContextTable::GetContext(script_contexts, lookup.context_index);
+
+      Handle<Object> current_value =
+          FixedArray::get(script_context, lookup.slot_index);
+
+      // If the values is not the hole, it will stay initialized,
+      // so no need to generate a check.
+      if (*current_value == *isolate()->factory()->the_hole_value()) {
+        return Bailout(kReferenceToUninitializedVariable);
+      }
+
       HStoreNamedField* instr = Add<HStoreNamedField>(
           Add<HConstant>(script_context),
           HObjectAccess::ForContextSlot(lookup.slot_index), value);
@@ -6488,8 +6516,9 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
   GlobalPropertyAccess type = LookupGlobalProperty(var, &it, STORE);
   if (type == kUseCell) {
     Handle<PropertyCell> cell = it.GetPropertyCell();
-    if (cell->type()->IsConstant()) {
-      Handle<Object> constant = cell->type()->AsConstant()->Value();
+    PropertyCell::AddDependentCompilationInfo(cell, top_info());
+    if (it.property_details().cell_type() == PropertyCellType::kConstant) {
+      Handle<Object> constant(cell->value(), isolate());
       if (value->IsConstant()) {
         HConstant* c_value = HConstant::cast(value);
         if (!constant.is_identical_to(c_value->handle(isolate()))) {
@@ -6511,8 +6540,11 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
         builder.End();
       }
     }
-    HInstruction* instr =
-        Add<HStoreGlobalCell>(value, cell, it.property_details());
+    HConstant* cell_constant = Add<HConstant>(cell);
+    HInstruction* instr = Add<HStoreNamedField>(
+        cell_constant, HObjectAccess::ForPropertyCellValue(), value);
+    instr->ClearChangesFlag(kInobjectFields);
+    instr->SetChangesFlag(kGlobalVars);
     if (instr->HasObservableSideEffects()) {
       Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
     }
@@ -6520,8 +6552,9 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
     HValue* global_object = Add<HLoadNamedField>(
         context(), nullptr,
         HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
-    HStoreNamedGeneric* instr = Add<HStoreNamedGeneric>(
-        global_object, var->name(), value, function_language_mode());
+    HStoreNamedGeneric* instr =
+        Add<HStoreNamedGeneric>(global_object, var->name(), value,
+                                function_language_mode(), PREMONOMORPHIC);
     USE(instr);
     DCHECK(instr->HasObservableSideEffects());
     Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
@@ -6778,7 +6811,7 @@ void HOptimizedGraphBuilder::VisitThrow(Throw* expr) {
   CHECK_ALIVE(VisitForValue(expr->exception()));
 
   HValue* value = environment()->Pop();
-  if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
+  if (!top_info()->is_tracking_positions()) SetSourcePosition(expr->position());
   Add<HPushArguments>(value);
   Add<HCallRuntime>(isolate()->factory()->empty_string(),
                     Runtime::FunctionForId(Runtime::kThrow), 1);
@@ -6819,19 +6852,16 @@ HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) {
 
 
 HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric(
-    PropertyAccessType access_type,
-    Expression* expr,
-    HValue* object,
-    Handle<String> name,
-    HValue* value,
-    bool is_uninitialized) {
+    PropertyAccessType access_type, Expression* expr, HValue* object,
+    Handle<String> name, HValue* value, bool is_uninitialized) {
   if (is_uninitialized) {
     Add<HDeoptimize>(
         Deoptimizer::kInsufficientTypeFeedbackForGenericNamedAccess,
         Deoptimizer::SOFT);
   }
   if (access_type == LOAD) {
-    HLoadNamedGeneric* result = New<HLoadNamedGeneric>(object, name);
+    HLoadNamedGeneric* result =
+        New<HLoadNamedGeneric>(object, name, PREMONOMORPHIC);
     if (FLAG_vector_ics) {
       Handle<SharedFunctionInfo> current_shared =
           function_state()->compilation_info()->shared_info();
@@ -6843,7 +6873,7 @@ HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric(
     return result;
   } else {
     return New<HStoreNamedGeneric>(object, name, value,
-                                   function_language_mode());
+                                   function_language_mode(), PREMONOMORPHIC);
   }
 }
 
@@ -6856,7 +6886,8 @@ HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric(
     HValue* key,
     HValue* value) {
   if (access_type == LOAD) {
-    HLoadKeyedGeneric* result = New<HLoadKeyedGeneric>(object, key);
+    HLoadKeyedGeneric* result =
+        New<HLoadKeyedGeneric>(object, key, PREMONOMORPHIC);
     if (FLAG_vector_ics) {
       Handle<SharedFunctionInfo> current_shared =
           function_state()->compilation_info()->shared_info();
@@ -6867,8 +6898,8 @@ HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric(
     }
     return result;
   } else {
-    return New<HStoreKeyedGeneric>(object, key, value,
-                                   function_language_mode());
+    return New<HStoreKeyedGeneric>(object, key, value, function_language_mode(),
+                                   PREMONOMORPHIC);
   }
 }
 
@@ -6926,7 +6957,7 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
 
 static bool CanInlineElementAccess(Handle<Map> map) {
   return map->IsJSObjectMap() && !map->has_slow_elements_kind() &&
-         !map->has_indexed_interceptor();
+         !map->has_indexed_interceptor() && !map->is_access_check_needed();
 }
 
 
@@ -7785,8 +7816,11 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
                                        int arguments_count,
                                        HValue* implicit_return_value,
                                        BailoutId ast_id, BailoutId return_id,
-                                       InliningKind inlining_kind,
-                                       SourcePosition position) {
+                                       InliningKind inlining_kind) {
+  if (target->context()->native_context() !=
+      top_info()->closure()->context()->native_context()) {
+    return false;
+  }
   int nodes_added = InliningAstSize(target);
   if (nodes_added == kNotInlinable) return false;
 
@@ -7830,12 +7864,16 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
   }
 
   // Parse and allocate variables.
-  CompilationInfo target_info(target, zone());
   // Use the same AstValueFactory for creating strings in the sub-compilation
   // step, but don't transfer ownership to target_info.
-  target_info.SetAstValueFactory(top_info()->ast_value_factory(), false);
+  ParseInfo parse_info(zone(), target);
+  parse_info.set_ast_value_factory(
+      top_info()->parse_info()->ast_value_factory());
+  parse_info.set_ast_value_factory_owned(false);
+
+  CompilationInfo target_info(&parse_info);
   Handle<SharedFunctionInfo> target_shared(target->shared());
-  if (!Compiler::ParseAndAnalyze(&target_info)) {
+  if (!Compiler::ParseAndAnalyze(target_info.parse_info())) {
     if (target_info.isolate()->has_pending_exception()) {
       // Parse or scope error, never optimize this function.
       SetStackOverflow();
@@ -7898,13 +7936,17 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
   DCHECK(target_shared->has_deoptimization_support());
   AstTyper::Run(&target_info);
 
-  int function_id = top_info()->TraceInlinedFunction(target_shared, position);
+  int inlining_id = 0;
+  if (top_info()->is_tracking_positions()) {
+    inlining_id = top_info()->TraceInlinedFunction(
+        target_shared, source_position(), function_state()->inlining_id());
+  }
 
   // Save the pending call context. Set up new one for the inlined function.
   // The function state is new-allocated because we need to delete it
   // in two different places.
-  FunctionState* target_state = new FunctionState(
-      this, &target_info, inlining_kind, function_id);
+  FunctionState* target_state =
+      new FunctionState(this, &target_info, inlining_kind, inlining_id);
 
   HConstant* undefined = graph()->GetConstantUndefined();
 
@@ -7947,6 +7989,9 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
       Add<HEnterInlined>(return_id, target, context, arguments_count, function,
                          function_state()->inlining_kind(),
                          function->scope()->arguments(), arguments_object);
+  if (top_info()->is_tracking_positions()) {
+    enter_inlined->set_inlining_id(inlining_id);
+  }
   function_state()->set_entry(enter_inlined);
 
   VisitDeclarations(target_info.scope()->declarations());
@@ -8054,25 +8099,16 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
 
 
 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) {
-  return TryInline(expr->target(),
-                   expr->arguments()->length(),
-                   NULL,
-                   expr->id(),
-                   expr->ReturnId(),
-                   NORMAL_RETURN,
-                   ScriptPositionToSourcePosition(expr->position()));
+  return TryInline(expr->target(), expr->arguments()->length(), NULL,
+                   expr->id(), expr->ReturnId(), NORMAL_RETURN);
 }
 
 
 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr,
                                                 HValue* implicit_return_value) {
-  return TryInline(expr->target(),
-                   expr->arguments()->length(),
-                   implicit_return_value,
-                   expr->id(),
-                   expr->ReturnId(),
-                   CONSTRUCT_CALL_RETURN,
-                   ScriptPositionToSourcePosition(expr->position()));
+  return TryInline(expr->target(), expr->arguments()->length(),
+                   implicit_return_value, expr->id(), expr->ReturnId(),
+                   CONSTRUCT_CALL_RETURN);
 }
 
 
@@ -8081,13 +8117,7 @@ bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter,
                                              BailoutId ast_id,
                                              BailoutId return_id) {
   if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true;
-  return TryInline(getter,
-                   0,
-                   NULL,
-                   ast_id,
-                   return_id,
-                   GETTER_CALL_RETURN,
-                   source_position());
+  return TryInline(getter, 0, NULL, ast_id, return_id, GETTER_CALL_RETURN);
 }
 
 
@@ -8097,25 +8127,16 @@ bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter,
                                              BailoutId assignment_id,
                                              HValue* implicit_return_value) {
   if (TryInlineApiSetter(setter, receiver_map, id)) return true;
-  return TryInline(setter,
-                   1,
-                   implicit_return_value,
-                   id, assignment_id,
-                   SETTER_CALL_RETURN,
-                   source_position());
+  return TryInline(setter, 1, implicit_return_value, id, assignment_id,
+                   SETTER_CALL_RETURN);
 }
 
 
 bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function,
                                                    Call* expr,
                                                    int arguments_count) {
-  return TryInline(function,
-                   arguments_count,
-                   NULL,
-                   expr->id(),
-                   expr->ReturnId(),
-                   NORMAL_RETURN,
-                   ScriptPositionToSourcePosition(expr->position()));
+  return TryInline(function, arguments_count, NULL, expr->id(),
+                   expr->ReturnId(), NORMAL_RETURN);
 }
 
 
@@ -8164,11 +8185,12 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) {
 bool HOptimizedGraphBuilder::IsReadOnlyLengthDescriptor(
     Handle<Map> jsarray_map) {
   DCHECK(!jsarray_map->is_dictionary_map());
-  LookupResult lookup;
   Isolate* isolate = jsarray_map->GetIsolate();
   Handle<Name> length_string = isolate->factory()->length_string();
-  lookup.LookupDescriptor(*jsarray_map, *length_string);
-  return lookup.IsReadOnly();
+  DescriptorArray* descriptors = jsarray_map->instance_descriptors();
+  int number = descriptors->SearchWithCache(*length_string, *jsarray_map);
+  DCHECK_NE(DescriptorArray::kNotFound, number);
+  return descriptors->GetDetails(number).IsReadOnly();
 }
 
 
@@ -8625,9 +8647,18 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function,
                                                int argc,
                                                BailoutId ast_id,
                                                ApiCallType call_type) {
+  if (function->context()->native_context() !=
+      top_info()->closure()->context()->native_context()) {
+    return false;
+  }
   CallOptimization optimization(function);
   if (!optimization.is_simple_api_call()) return false;
   Handle<Map> holder_map;
+  for (int i = 0; i < receiver_maps->length(); ++i) {
+    auto map = receiver_maps->at(i);
+    // Don't inline calls to receivers requiring accesschecks.
+    if (map->is_access_check_needed()) return false;
+  }
   if (call_type == kCallApiFunction) {
     // Cannot embed a direct reference to the global proxy map
     // as it maybe dropped on deserialization.
@@ -9079,10 +9110,10 @@ bool HOptimizedGraphBuilder::TryHandleArrayCallNew(CallNew* expr,
     return false;
   }
 
-  BuildArrayCall(expr,
-                 expr->arguments()->length(),
-                 function,
-                 expr->allocation_site());
+  Handle<AllocationSite> site = expr->allocation_site();
+  if (site.is_null()) return false;
+
+  BuildArrayCall(expr, expr->arguments()->length(), function, site);
   return true;
 }
 
@@ -9132,8 +9163,6 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
     CHECK_ALIVE(PushLoad(prop, receiver, key));
     HValue* function = Pop();
 
-    if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
-
     if (function->IsConstant() &&
         HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
       // Push the function under the receiver.
@@ -9206,58 +9235,21 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
     // evaluation of the arguments.
     CHECK_ALIVE(VisitForValue(expr->expression()));
     HValue* function = Top();
-    if (expr->global_call()) {
-      Variable* var = proxy->var();
-      bool known_global_function = false;
-      // If there is a global property cell for the name at compile time and
-      // access check is not enabled we assume that the function will not change
-      // and generate optimized code for calling the function.
-      Handle<GlobalObject> global(current_info()->global_object());
-      LookupIterator it(global, var->name(),
-                        LookupIterator::OWN_SKIP_INTERCEPTOR);
-      GlobalPropertyAccess type = LookupGlobalProperty(var, &it, LOAD);
-      if (type == kUseCell) {
-        known_global_function = expr->ComputeGlobalTarget(global, &it);
-      }
-      if (known_global_function) {
-        Add<HCheckValue>(function, expr->target());
-
-        // Placeholder for the receiver.
-        Push(graph()->GetConstantUndefined());
-        CHECK_ALIVE(VisitExpressions(expr->arguments()));
-
-        // Patch the global object on the stack by the expected receiver.
-        HValue* receiver = ImplicitReceiverFor(function, expr->target());
-        const int receiver_index = argument_count - 1;
-        environment()->SetExpressionStackAt(receiver_index, receiver);
-
-        if (TryInlineBuiltinFunctionCall(expr)) {
-          if (FLAG_trace_inlining) {
-            PrintF("Inlining builtin ");
-            expr->target()->ShortPrint();
-            PrintF("\n");
-          }
-          return;
-        }
-        if (TryInlineApiFunctionCall(expr, receiver)) return;
-        if (TryHandleArrayCall(expr, function)) return;
-        if (TryInlineCall(expr)) return;
+    if (function->IsConstant() &&
+        HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
+      Handle<Object> constant = HConstant::cast(function)->handle(isolate());
+      Handle<JSFunction> target = Handle<JSFunction>::cast(constant);
+      expr->SetKnownGlobalTarget(target);
+    }
 
-        PushArgumentsFromEnvironment(argument_count);
-        call = BuildCallConstantFunction(expr->target(), argument_count);
-      } else {
-        Push(graph()->GetConstantUndefined());
-        CHECK_ALIVE(VisitExpressions(expr->arguments()));
-        PushArgumentsFromEnvironment(argument_count);
-        call = New<HCallFunction>(function, argument_count);
-      }
+    // Placeholder for the receiver.
+    Push(graph()->GetConstantUndefined());
+    CHECK_ALIVE(VisitExpressions(expr->arguments()));
 
-    } else if (expr->IsMonomorphic()) {
+    if (expr->IsMonomorphic()) {
       Add<HCheckValue>(function, expr->target());
 
-      Push(graph()->GetConstantUndefined());
-      CHECK_ALIVE(VisitExpressions(expr->arguments()));
-
+      // Patch the global object on the stack by the expected receiver.
       HValue* receiver = ImplicitReceiverFor(function, expr->target());
       const int receiver_index = argument_count - 1;
       environment()->SetExpressionStackAt(receiver_index, receiver);
@@ -9271,15 +9263,12 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
         return;
       }
       if (TryInlineApiFunctionCall(expr, receiver)) return;
-
+      if (TryHandleArrayCall(expr, function)) return;
       if (TryInlineCall(expr)) return;
 
-      call = PreProcessCall(New<HInvokeFunction>(
-          function, expr->target(), argument_count));
-
+      PushArgumentsFromEnvironment(argument_count);
+      call = BuildCallConstantFunction(expr->target(), argument_count);
     } else {
-      Push(graph()->GetConstantUndefined());
-      CHECK_ALIVE(VisitExpressions(expr->arguments()));
       PushArgumentsFromEnvironment(argument_count);
       HCallFunction* call_function =
           New<HCallFunction>(function, argument_count);
@@ -9408,7 +9397,7 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
   DCHECK(!HasStackOverflow());
   DCHECK(current_block() != NULL);
   DCHECK(current_block()->HasPredecessor());
-  if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
+  if (!top_info()->is_tracking_positions()) SetSourcePosition(expr->position());
   int argument_count = expr->arguments()->length() + 1;  // Plus constructor.
   Factory* factory = isolate()->factory();
 
@@ -9418,6 +9407,12 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
   HValue* function = Top();
   CHECK_ALIVE(VisitExpressions(expr->arguments()));
 
+  if (function->IsConstant() &&
+      HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
+    Handle<Object> constant = HConstant::cast(function)->handle(isolate());
+    expr->SetKnownGlobalTarget(Handle<JSFunction>::cast(constant));
+  }
+
   if (FLAG_inline_construct &&
       expr->IsMonomorphic() &&
       IsAllocationInlineable(expr->target())) {
@@ -9521,22 +9516,6 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
 }
 
 
-// Support for generating inlined runtime functions.
-
-// Lookup table for generators for runtime calls that are generated inline.
-// Elements of the table are member pointers to functions of
-// HOptimizedGraphBuilder.
-#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize)  \
-    &HOptimizedGraphBuilder::Generate##Name,
-
-const HOptimizedGraphBuilder::InlineFunctionGenerator
-    HOptimizedGraphBuilder::kInlineFunctionGenerators[] = {
-        INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
-        INLINE_OPTIMIZED_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
-};
-#undef INLINE_FUNCTION_GENERATOR_ADDRESS
-
-
 template <class ViewClass>
 void HGraphBuilder::BuildArrayBufferViewInitialization(
     HValue* obj,
@@ -9915,30 +9894,21 @@ void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
 
   const Runtime::Function* function = expr->function();
   DCHECK(function != NULL);
-
-  if (function->intrinsic_type == Runtime::INLINE ||
-      function->intrinsic_type == Runtime::INLINE_OPTIMIZED) {
-    DCHECK(expr->name()->length() > 0);
-    DCHECK(expr->name()->Get(0) == '_');
-    // Call to an inline function.
-    int lookup_index = static_cast<int>(function->function_id) -
-        static_cast<int>(Runtime::kFirstInlineFunction);
-    DCHECK(lookup_index >= 0);
-    DCHECK(static_cast<size_t>(lookup_index) <
-           arraysize(kInlineFunctionGenerators));
-    InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index];
-
-    // Call the inline code generator using the pointer-to-member.
-    (this->*generator)(expr);
-  } else {
-    DCHECK(function->intrinsic_type == Runtime::RUNTIME);
-    Handle<String> name = expr->name();
-    int argument_count = expr->arguments()->length();
-    CHECK_ALIVE(VisitExpressions(expr->arguments()));
-    PushArgumentsFromEnvironment(argument_count);
-    HCallRuntime* call = New<HCallRuntime>(name, function,
-                                           argument_count);
-    return ast_context()->ReturnInstruction(call, expr->id());
+  switch (function->function_id) {
+#define CALL_INTRINSIC_GENERATOR(Name) \
+  case Runtime::kInline##Name:         \
+    return Generate##Name(expr);
+
+    FOR_EACH_HYDROGEN_INTRINSIC(CALL_INTRINSIC_GENERATOR)
+#undef CALL_INTRINSIC_GENERATOR
+    default: {
+      Handle<String> name = expr->name();
+      int argument_count = expr->arguments()->length();
+      CHECK_ALIVE(VisitExpressions(expr->arguments()));
+      PushArgumentsFromEnvironment(argument_count);
+      HCallRuntime* call = New<HCallRuntime>(name, function, argument_count);
+      return ast_context()->ReturnInstruction(call, expr->id());
+    }
   }
 }
 
@@ -10112,7 +10082,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
   DCHECK(!HasStackOverflow());
   DCHECK(current_block() != NULL);
   DCHECK(current_block()->HasPredecessor());
-  if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
+  if (!top_info()->is_tracking_positions()) SetSourcePosition(expr->position());
   Expression* target = expr->expression();
   VariableProxy* proxy = target->AsVariableProxy();
   Property* prop = target->AsProperty();
@@ -10321,9 +10291,9 @@ HValue* HGraphBuilder::TruncateToNumber(HValue* value, Type** expected) {
     HConstant* constant = HConstant::cast(value);
     Maybe<HConstant*> number =
         constant->CopyToTruncatedNumber(isolate(), zone());
-    if (number.has_value) {
+    if (number.IsJust()) {
       *expected = Type::Number(zone());
-      return AddInstruction(number.value);
+      return AddInstruction(number.FromJust());
     }
   }
 
@@ -10468,16 +10438,21 @@ HValue* HGraphBuilder::BuildBinaryOperation(
       return AddUncasted<HInvokeFunction>(function, 2);
     }
 
-    // Fast path for empty constant strings.
-    if (left->IsConstant() &&
-        HConstant::cast(left)->HasStringValue() &&
-        HConstant::cast(left)->StringValue()->length() == 0) {
-      return right;
-    }
-    if (right->IsConstant() &&
-        HConstant::cast(right)->HasStringValue() &&
-        HConstant::cast(right)->StringValue()->length() == 0) {
-      return left;
+    // Fast paths for empty constant strings.
+    Handle<String> left_string =
+        left->IsConstant() && HConstant::cast(left)->HasStringValue()
+            ? HConstant::cast(left)->StringValue()
+            : Handle<String>();
+    Handle<String> right_string =
+        right->IsConstant() && HConstant::cast(right)->HasStringValue()
+            ? HConstant::cast(right)->StringValue()
+            : Handle<String>();
+    if (!left_string.is_null() && left_string->length() == 0) return right;
+    if (!right_string.is_null() && right_string->length() == 0) return left;
+    if (!left_string.is_null() && !right_string.is_null()) {
+      return AddUncasted<HStringAdd>(
+          left, right, allocation_mode.GetPretenureMode(),
+          STRING_ADD_CHECK_NONE, allocation_mode.feedback_site());
     }
 
     // Register the dependent code with the allocation site.
@@ -10539,10 +10514,10 @@ HValue* HGraphBuilder::BuildBinaryOperation(
         instr = AddUncasted<HMul>(left, right);
         break;
       case Token::MOD: {
-        if (fixed_right_arg.has_value &&
-            !right->EqualsInteger32Constant(fixed_right_arg.value)) {
-          HConstant* fixed_right = Add<HConstant>(
-              static_cast<int>(fixed_right_arg.value));
+        if (fixed_right_arg.IsJust() &&
+            !right->EqualsInteger32Constant(fixed_right_arg.FromJust())) {
+          HConstant* fixed_right =
+              Add<HConstant>(static_cast<int>(fixed_right_arg.FromJust()));
           IfBuilder if_same(this);
           if_same.If<HCompareNumericAndBranch>(right, fixed_right, Token::EQ);
           if_same.Then();
@@ -10763,7 +10738,7 @@ void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) {
       BuildBinaryOperation(expr, left, right,
           ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE
                                     : PUSH_BEFORE_SIMULATE);
-  if (FLAG_hydrogen_track_positions && result->IsBinaryOperation()) {
+  if (top_info()->is_tracking_positions() && result->IsBinaryOperation()) {
     HBinaryOperation::cast(result)->SetOperandPositions(
         zone(),
         ScriptPositionToSourcePosition(expr->left()->position()),
@@ -10801,7 +10776,7 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
   DCHECK(current_block() != NULL);
   DCHECK(current_block()->HasPredecessor());
 
-  if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
+  if (!top_info()->is_tracking_positions()) SetSourcePosition(expr->position());
 
   // Check for a few fast cases. The AST visiting behavior must be in sync
   // with the full codegen: We don't push both left and right values onto
@@ -10836,8 +10811,6 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
   CHECK_ALIVE(VisitForValue(expr->left()));
   CHECK_ALIVE(VisitForValue(expr->right()));
 
-  if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
-
   HValue* right = Pop();
   HValue* left = Pop();
   Token::Value op = expr->op();
@@ -10945,7 +10918,7 @@ HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
         AddCheckMap(operand_to_check, map);
         HCompareObjectEqAndBranch* result =
             New<HCompareObjectEqAndBranch>(left, right);
-        if (FLAG_hydrogen_track_positions) {
+        if (top_info()->is_tracking_positions()) {
           result->set_operand_position(zone(), 0, left_position);
           result->set_operand_position(zone(), 1, right_position);
         }
@@ -11011,7 +10984,7 @@ HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
       HCompareNumericAndBranch* result =
           New<HCompareNumericAndBranch>(left, right, op);
       result->set_observed_input_representation(left_rep, right_rep);
-      if (FLAG_hydrogen_track_positions) {
+      if (top_info()->is_tracking_positions()) {
         result->SetOperandPositions(zone(), left_position, right_position);
       }
       return result;
@@ -11027,7 +11000,7 @@ void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
   DCHECK(current_block() != NULL);
   DCHECK(current_block()->HasPredecessor());
   DCHECK(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT);
-  if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
+  if (!top_info()->is_tracking_positions()) SetSourcePosition(expr->position());
   CHECK_ALIVE(VisitForValue(sub_expr));
   HValue* value = Pop();
   if (expr->op() == Token::EQ_STRICT) {
@@ -11625,11 +11598,6 @@ void HOptimizedGraphBuilder::GenerateHasFastPackedElements(CallRuntime* call) {
 }
 
 
-void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
-  return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi);
-}
-
-
 void HOptimizedGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
   DCHECK(call->arguments()->length() == 1);
   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
@@ -11639,12 +11607,6 @@ void HOptimizedGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
 }
 
 
-void HOptimizedGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
-    CallRuntime* call) {
-  return Bailout(kInlinedRuntimeFunctionIsStringWrapperSafeForDefaultValueOf);
-}
-
-
 // Support for construct call checks.
 void HOptimizedGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
   DCHECK(call->arguments()->length() == 0);
@@ -11703,14 +11665,6 @@ void HOptimizedGraphBuilder::GenerateArguments(CallRuntime* call) {
 }
 
 
-// Support for accessing the class and value fields of an object.
-void HOptimizedGraphBuilder::GenerateClassOf(CallRuntime* call) {
-  // The special form detected by IsClassOfTest is detected before we get here
-  // and does not cause a bailout.
-  return Bailout(kInlinedRuntimeFunctionClassOf);
-}
-
-
 void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) {
   DCHECK(call->arguments()->length() == 1);
   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
@@ -11739,6 +11693,17 @@ void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) {
 }
 
 
+void HOptimizedGraphBuilder::GenerateJSValueGetValue(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* value = Pop();
+  HInstruction* result = Add<HLoadNamedField>(
+      value, nullptr,
+      HObjectAccess::ForObservableJSObjectOffset(JSValue::kValueOffset));
+  return ast_context()->ReturnInstruction(result, call->id());
+}
+
+
 void HOptimizedGraphBuilder::GenerateDateField(CallRuntime* call) {
   DCHECK(call->arguments()->length() == 2);
   DCHECK_NOT_NULL(call->arguments()->at(1)->AsLiteral());
@@ -11900,6 +11865,15 @@ void HOptimizedGraphBuilder::GenerateStringCompare(CallRuntime* call) {
 }
 
 
+void HOptimizedGraphBuilder::GenerateStringGetLength(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* string = Pop();
+  HInstruction* result = AddLoadStringLength(string);
+  return ast_context()->ReturnInstruction(result, call->id());
+}
+
+
 // Support for direct calls from JavaScript to native RegExp code.
 void HOptimizedGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
   DCHECK_EQ(4, call->arguments()->length());
@@ -12015,12 +11989,6 @@ void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) {
 }
 
 
-void HOptimizedGraphBuilder::GenerateDefaultConstructorCallSuper(
-    CallRuntime* call) {
-  return Bailout(kSuperReference);
-}
-
-
 // Fast call to math functions.
 void HOptimizedGraphBuilder::GenerateMathPow(CallRuntime* call) {
   DCHECK_EQ(2, call->arguments()->length());
@@ -12033,6 +12001,24 @@ void HOptimizedGraphBuilder::GenerateMathPow(CallRuntime* call) {
 }
 
 
+void HOptimizedGraphBuilder::GenerateMathClz32(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* value = Pop();
+  HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathClz32);
+  return ast_context()->ReturnInstruction(result, call->id());
+}
+
+
+void HOptimizedGraphBuilder::GenerateMathFloor(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* value = Pop();
+  HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathFloor);
+  return ast_context()->ReturnInstruction(result, call->id());
+}
+
+
 void HOptimizedGraphBuilder::GenerateMathLogRT(CallRuntime* call) {
   DCHECK(call->arguments()->length() == 1);
   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
@@ -12042,7 +12028,7 @@ void HOptimizedGraphBuilder::GenerateMathLogRT(CallRuntime* call) {
 }
 
 
-void HOptimizedGraphBuilder::GenerateMathSqrtRT(CallRuntime* call) {
+void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
   DCHECK(call->arguments()->length() == 1);
   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
   HValue* value = Pop();
@@ -12705,21 +12691,15 @@ void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
 
 
 void HOptimizedGraphBuilder::GenerateFastOneByteArrayJoin(CallRuntime* call) {
+  // Simply returning undefined here would be semantically correct and even
+  // avoid the bailout. Nevertheless, some ancient benchmarks like SunSpider's
+  // string-fasta would tank, because fullcode contains an optimized version.
+  // Obviously the fullcode => Crankshaft => bailout => fullcode dance is
+  // faster... *sigh*
   return Bailout(kInlinedRuntimeFunctionFastOneByteArrayJoin);
 }
 
 
-// Support for generators.
-void HOptimizedGraphBuilder::GenerateGeneratorNext(CallRuntime* call) {
-  return Bailout(kInlinedRuntimeFunctionGeneratorNext);
-}
-
-
-void HOptimizedGraphBuilder::GenerateGeneratorThrow(CallRuntime* call) {
-  return Bailout(kInlinedRuntimeFunctionGeneratorThrow);
-}
-
-
 void HOptimizedGraphBuilder::GenerateDebugBreakInOptimizedCode(
     CallRuntime* call) {
   Add<HDebugBreak>();
@@ -13210,9 +13190,8 @@ void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
         PrintIndent();
         std::ostringstream os;
         os << "0 " << uses << " " << NameOf(instruction) << " " << *instruction;
-        if (FLAG_hydrogen_track_positions &&
-            instruction->has_position() &&
-            instruction->position().raw() != 0) {
+        if (graph->info()->is_tracking_positions() &&
+            instruction->has_position() && instruction->position().raw() != 0) {
           const SourcePosition pos = instruction->position();
           os << " pos:";
           if (pos.inlining_id() != 0) os << pos.inlining_id() << "_";
index 8411b6d..5fded82 100644 (file)
@@ -407,13 +407,11 @@ class HGraph FINAL : public ZoneObject {
     use_optimistic_licm_ = value;
   }
 
-  void MarkRecursive() {
-    is_recursive_ = true;
-  }
+  void MarkRecursive() { is_recursive_ = true; }
+  bool is_recursive() const { return is_recursive_; }
 
-  bool is_recursive() const {
-    return is_recursive_;
-  }
+  void MarkThisHasUses() { this_has_uses_ = true; }
+  bool this_has_uses() const { return this_has_uses_; }
 
   void MarkDependsOnEmptyArrayProtoElements() {
     // Add map dependency if not already added.
@@ -499,6 +497,7 @@ class HGraph FINAL : public ZoneObject {
   Zone* zone_;
 
   bool is_recursive_;
+  bool this_has_uses_;
   bool use_optimistic_licm_;
   bool depends_on_empty_array_proto_elements_;
   int type_change_checksum_;
@@ -1869,12 +1868,14 @@ class HGraphBuilder {
 
  protected:
   void SetSourcePosition(int position) {
-    DCHECK(position != RelocInfo::kNoPosition);
-    position_.set_position(position - start_position_);
+    if (position != RelocInfo::kNoPosition) {
+      position_.set_position(position - start_position_);
+    }
+    // Otherwise position remains unknown.
   }
 
   void EnterInlinedSource(int start_position, int id) {
-    if (FLAG_hydrogen_track_positions) {
+    if (top_info()->is_tracking_positions()) {
       start_position_ = start_position;
       position_.set_inlining_id(id);
     }
@@ -2118,15 +2119,9 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
   DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
 
  protected:
-  // Type of a member function that generates inline code for a native function.
-  typedef void (HOptimizedGraphBuilder::*InlineFunctionGenerator)
-      (CallRuntime* call);
-
   // Forward declarations for inner scope classes.
   class SubgraphScope;
 
-  static const InlineFunctionGenerator kInlineFunctionGenerators[];
-
   static const int kMaxCallPolymorphism = 4;
   static const int kMaxLoadPolymorphism = 4;
   static const int kMaxStorePolymorphism = 4;
@@ -2168,13 +2163,85 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
     return function_state()->compilation_info()->language_mode();
   }
 
-  // Generators for inline runtime functions.
-#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize)      \
-  void Generate##Name(CallRuntime* call);
-
-  INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
-  INLINE_OPTIMIZED_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
-#undef INLINE_FUNCTION_GENERATOR_DECLARATION
+#define FOR_EACH_HYDROGEN_INTRINSIC(F) \
+  F(IsSmi)                             \
+  F(IsArray)                           \
+  F(IsRegExp)                          \
+  F(IsJSProxy)                         \
+  F(IsConstructCall)                   \
+  F(CallFunction)                      \
+  F(ArgumentsLength)                   \
+  F(Arguments)                         \
+  F(ValueOf)                           \
+  F(SetValueOf)                        \
+  F(DateField)                         \
+  F(StringCharFromCode)                \
+  F(StringCharAt)                      \
+  F(OneByteSeqStringSetChar)           \
+  F(TwoByteSeqStringSetChar)           \
+  F(ObjectEquals)                      \
+  F(IsObject)                          \
+  F(IsFunction)                        \
+  F(IsUndetectableObject)              \
+  F(IsSpecObject)                      \
+  F(MathPow)                           \
+  F(IsMinusZero)                       \
+  F(HasCachedArrayIndex)               \
+  F(GetCachedArrayIndex)               \
+  F(FastOneByteArrayJoin)              \
+  F(DebugBreakInOptimizedCode)         \
+  F(StringCharCodeAt)                  \
+  F(StringAdd)                         \
+  F(SubString)                         \
+  F(StringCompare)                     \
+  F(RegExpExec)                        \
+  F(RegExpConstructResult)             \
+  F(GetFromCache)                      \
+  F(NumberToString)                    \
+  F(DebugIsActive)                     \
+  /* Typed Arrays */                   \
+  F(TypedArrayInitialize)              \
+  F(DataViewInitialize)                \
+  F(MaxSmi)                            \
+  F(TypedArrayMaxSizeInHeap)           \
+  F(ArrayBufferViewGetByteLength)      \
+  F(ArrayBufferViewGetByteOffset)      \
+  F(TypedArrayGetLength)               \
+  /* ArrayBuffer */                    \
+  F(ArrayBufferGetByteLength)          \
+  /* Maths */                          \
+  F(ConstructDouble)                   \
+  F(DoubleHi)                          \
+  F(DoubleLo)                          \
+  F(MathClz32)                         \
+  F(MathFloor)                         \
+  F(MathSqrt)                          \
+  F(MathLogRT)                         \
+  /* ES6 Collections */                \
+  F(MapClear)                          \
+  F(MapDelete)                         \
+  F(MapGet)                            \
+  F(MapGetSize)                        \
+  F(MapHas)                            \
+  F(MapInitialize)                     \
+  F(MapSet)                            \
+  F(SetAdd)                            \
+  F(SetClear)                          \
+  F(SetDelete)                         \
+  F(SetGetSize)                        \
+  F(SetHas)                            \
+  F(SetInitialize)                     \
+  /* Arrays */                         \
+  F(HasFastPackedElements)             \
+  F(GetPrototype)                      \
+  /* Strings */                        \
+  F(StringGetLength)                   \
+  /* JSValue */                        \
+  F(JSValueGetValue)
+
+#define GENERATOR_DECLARATION(Name) void Generate##Name(CallRuntime* call);
+  FOR_EACH_HYDROGEN_INTRINSIC(GENERATOR_DECLARATION)
+#undef GENERATOR_DECLARATION
 
   void VisitDelete(UnaryOperation* expr);
   void VisitVoid(UnaryOperation* expr);
@@ -2319,8 +2386,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
   int InliningAstSize(Handle<JSFunction> target);
   bool TryInline(Handle<JSFunction> target, int arguments_count,
                  HValue* implicit_return_value, BailoutId ast_id,
-                 BailoutId return_id, InliningKind inlining_kind,
-                 SourcePosition position);
+                 BailoutId return_id, InliningKind inlining_kind);
 
   bool TryInlineCall(Call* expr);
   bool TryInlineConstruct(CallNew* expr, HValue* implicit_return_value);
@@ -2430,121 +2496,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
   void BuildInlinedCallArray(Expression* expression, int argument_count,
                              Handle<AllocationSite> site);
 
-  class LookupResult FINAL BASE_EMBEDDED {
-   public:
-    LookupResult()
-        : lookup_type_(NOT_FOUND),
-          details_(NONE, DATA, Representation::None()) {}
-
-    void LookupDescriptor(Map* map, Name* name) {
-      DescriptorArray* descriptors = map->instance_descriptors();
-      int number = descriptors->SearchWithCache(name, map);
-      if (number == DescriptorArray::kNotFound) return NotFound();
-      lookup_type_ = DESCRIPTOR_TYPE;
-      details_ = descriptors->GetDetails(number);
-      number_ = number;
-    }
-
-    void LookupTransition(Map* map, Name* name, PropertyAttributes attributes) {
-      int transition_index = map->SearchTransition(kData, name, attributes);
-      if (transition_index == TransitionArray::kNotFound) return NotFound();
-      lookup_type_ = TRANSITION_TYPE;
-      transition_ = handle(map->GetTransition(transition_index));
-      number_ = transition_->LastAdded();
-      details_ = transition_->instance_descriptors()->GetDetails(number_);
-    }
-
-    void NotFound() {
-      lookup_type_ = NOT_FOUND;
-      details_ = PropertyDetails(NONE, DATA, 0);
-    }
-
-    Representation representation() const {
-      DCHECK(IsFound());
-      return details_.representation();
-    }
-
-    // Property callbacks does not include transitions to callbacks.
-    bool IsAccessorConstant() const {
-      return !IsTransition() && details_.type() == ACCESSOR_CONSTANT;
-    }
-
-    bool IsReadOnly() const {
-      DCHECK(IsFound());
-      return details_.IsReadOnly();
-    }
-
-    bool IsData() const {
-      return lookup_type_ == DESCRIPTOR_TYPE && details_.type() == DATA;
-    }
-
-    bool IsDataConstant() const {
-      return lookup_type_ == DESCRIPTOR_TYPE &&
-             details_.type() == DATA_CONSTANT;
-    }
-
-    bool IsConfigurable() const { return details_.IsConfigurable(); }
-    bool IsFound() const { return lookup_type_ != NOT_FOUND; }
-    bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; }
-
-    // Is the result is a property excluding transitions and the null
-    // descriptor?
-    bool IsProperty() const { return IsFound() && !IsTransition(); }
-
-    Handle<Map> GetTransitionTarget() const {
-      DCHECK(IsTransition());
-      return transition_;
-    }
-
-    bool IsTransitionToData() const {
-      return IsTransition() && details_.type() == DATA;
-    }
-
-    int GetLocalFieldIndexFromMap(Map* map) const {
-      return GetFieldIndexFromMap(map) - map->inobject_properties();
-    }
-
-    Object* GetConstantFromMap(Map* map) const {
-      DCHECK(details_.type() == DATA_CONSTANT);
-      return GetValueFromMap(map);
-    }
-
-    Object* GetValueFromMap(Map* map) const {
-      DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
-             lookup_type_ == TRANSITION_TYPE);
-      DCHECK(number_ < map->NumberOfOwnDescriptors());
-      return map->instance_descriptors()->GetValue(number_);
-    }
-
-    int GetFieldIndexFromMap(Map* map) const {
-      DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
-             lookup_type_ == TRANSITION_TYPE);
-      DCHECK(number_ < map->NumberOfOwnDescriptors());
-      return map->instance_descriptors()->GetFieldIndex(number_);
-    }
-
-    HeapType* GetFieldTypeFromMap(Map* map) const {
-      DCHECK_NE(NOT_FOUND, lookup_type_);
-      DCHECK(number_ < map->NumberOfOwnDescriptors());
-      return map->instance_descriptors()->GetFieldType(number_);
-    }
-
-    Map* GetFieldOwnerFromMap(Map* map) const {
-      DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
-             lookup_type_ == TRANSITION_TYPE);
-      DCHECK(number_ < map->NumberOfOwnDescriptors());
-      return map->FindFieldOwner(number_);
-    }
-
-   private:
-    // Where did we find the result;
-    enum { NOT_FOUND, DESCRIPTOR_TYPE, TRANSITION_TYPE } lookup_type_;
-
-    Handle<Map> transition_;
-    int number_;
-    PropertyDetails details_;
-  };
-
   class PropertyAccessInfo {
    public:
     PropertyAccessInfo(HOptimizedGraphBuilder* builder,
@@ -2555,7 +2506,9 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
           map_(map),
           name_(name),
           field_type_(HType::Tagged()),
-          access_(HObjectAccess::ForMap()) {}
+          access_(HObjectAccess::ForMap()),
+          lookup_type_(NOT_FOUND),
+          details_(NONE, DATA, Representation::None()) {}
 
     // Checkes whether this PropertyAccessInfo can be handled as a monomorphic
     // load named. It additionally fills in the fields necessary to generate the
@@ -2604,20 +2557,26 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
     Handle<JSObject> holder() { return holder_; }
     Handle<JSFunction> accessor() { return accessor_; }
     Handle<Object> constant() { return constant_; }
-    Handle<Map> transition() { return lookup_.GetTransitionTarget(); }
+    Handle<Map> transition() { return transition_; }
     SmallMapList* field_maps() { return &field_maps_; }
     HType field_type() const { return field_type_; }
     HObjectAccess access() { return access_; }
 
-    bool IsFound() const { return lookup_.IsFound(); }
-    bool IsProperty() const { return lookup_.IsProperty(); }
-    bool IsData() const { return lookup_.IsData(); }
-    bool IsDataConstant() const { return lookup_.IsDataConstant(); }
-    bool IsAccessorConstant() const { return lookup_.IsAccessorConstant(); }
-    bool IsTransition() const { return lookup_.IsTransition(); }
-
-    bool IsConfigurable() const { return lookup_.IsConfigurable(); }
-    bool IsReadOnly() const { return lookup_.IsReadOnly(); }
+    bool IsFound() const { return lookup_type_ != NOT_FOUND; }
+    bool IsProperty() const { return IsFound() && !IsTransition(); }
+    bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; }
+    bool IsData() const {
+      return lookup_type_ == DESCRIPTOR_TYPE && details_.type() == DATA;
+    }
+    bool IsDataConstant() const {
+      return lookup_type_ == DESCRIPTOR_TYPE &&
+             details_.type() == DATA_CONSTANT;
+    }
+    bool IsAccessorConstant() const {
+      return !IsTransition() && details_.type() == ACCESSOR_CONSTANT;
+    }
+    bool IsConfigurable() const { return details_.IsConfigurable(); }
+    bool IsReadOnly() const { return details_.IsReadOnly(); }
 
     bool IsStringType() { return map_->instance_type() < FIRST_NONSTRING_TYPE; }
     bool IsNumberType() { return map_->instance_type() == HEAP_NUMBER_TYPE; }
@@ -2625,31 +2584,71 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
     bool IsArrayType() { return map_->instance_type() == JS_ARRAY_TYPE; }
 
    private:
-    Handle<Object> GetAccessorsFromMap(Handle<Map> map) const {
-      return handle(lookup_.GetValueFromMap(*map), isolate());
-    }
     Handle<Object> GetConstantFromMap(Handle<Map> map) const {
-      return handle(lookup_.GetConstantFromMap(*map), isolate());
+      DCHECK_EQ(DESCRIPTOR_TYPE, lookup_type_);
+      DCHECK(number_ < map->NumberOfOwnDescriptors());
+      return handle(map->instance_descriptors()->GetValue(number_), isolate());
+    }
+    Handle<Object> GetAccessorsFromMap(Handle<Map> map) const {
+      return GetConstantFromMap(map);
     }
     Handle<HeapType> GetFieldTypeFromMap(Handle<Map> map) const {
-      return handle(lookup_.GetFieldTypeFromMap(*map), isolate());
+      DCHECK(IsFound());
+      DCHECK(number_ < map->NumberOfOwnDescriptors());
+      return handle(map->instance_descriptors()->GetFieldType(number_),
+                    isolate());
     }
     Handle<Map> GetFieldOwnerFromMap(Handle<Map> map) const {
-      return handle(lookup_.GetFieldOwnerFromMap(*map));
+      DCHECK(IsFound());
+      DCHECK(number_ < map->NumberOfOwnDescriptors());
+      return handle(map->FindFieldOwner(number_));
     }
     int GetLocalFieldIndexFromMap(Handle<Map> map) const {
-      return lookup_.GetLocalFieldIndexFromMap(*map);
+      DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
+             lookup_type_ == TRANSITION_TYPE);
+      DCHECK(number_ < map->NumberOfOwnDescriptors());
+      int field_index = map->instance_descriptors()->GetFieldIndex(number_);
+      return field_index - map->inobject_properties();
+    }
+
+    void LookupDescriptor(Map* map, Name* name) {
+      DescriptorArray* descriptors = map->instance_descriptors();
+      int number = descriptors->SearchWithCache(name, map);
+      if (number == DescriptorArray::kNotFound) return NotFound();
+      lookup_type_ = DESCRIPTOR_TYPE;
+      details_ = descriptors->GetDetails(number);
+      number_ = number;
+    }
+    void LookupTransition(Map* map, Name* name, PropertyAttributes attributes) {
+      Map* target =
+          TransitionArray::SearchTransition(map, kData, name, attributes);
+      if (target == NULL) return NotFound();
+      lookup_type_ = TRANSITION_TYPE;
+      transition_ = handle(target);
+      number_ = transition_->LastAdded();
+      details_ = transition_->instance_descriptors()->GetDetails(number_);
+    }
+    void NotFound() {
+      lookup_type_ = NOT_FOUND;
+      details_ = PropertyDetails::Empty();
+    }
+    Representation representation() const {
+      DCHECK(IsFound());
+      return details_.representation();
+    }
+    bool IsTransitionToData() const {
+      return IsTransition() && details_.type() == DATA;
     }
-    Representation representation() const { return lookup_.representation(); }
 
     Zone* zone() { return builder_->zone(); }
     CompilationInfo* top_info() { return builder_->top_info(); }
     CompilationInfo* current_info() { return builder_->current_info(); }
 
     bool LoadResult(Handle<Map> map);
-    void LoadFieldMaps(Handle<Map> map);
+    bool LoadFieldMaps(Handle<Map> map);
     bool LookupDescriptor();
     bool LookupInPrototypes();
+    bool IsIntegerIndexedExotic();
     bool IsCompatible(PropertyAccessInfo* other);
 
     void GeneralizeRepresentation(Representation r) {
@@ -2657,7 +2656,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
           access_.representation().generalize(r));
     }
 
-    LookupResult lookup_;
     HOptimizedGraphBuilder* builder_;
     PropertyAccessType access_type_;
     Handle<Map> map_;
@@ -2669,6 +2667,11 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
     SmallMapList field_maps_;
     HType field_type_;
     HObjectAccess access_;
+
+    enum { NOT_FOUND, DESCRIPTOR_TYPE, TRANSITION_TYPE } lookup_type_;
+    Handle<Map> transition_;
+    int number_;
+    PropertyDetails details_;
   };
 
   HInstruction* BuildMonomorphicAccess(PropertyAccessInfo* info,
@@ -2756,12 +2759,9 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
                                    PropertyAccessType access_type,
                                    bool* has_side_effects);
 
-  HInstruction* BuildNamedGeneric(PropertyAccessType access,
-                                  Expression* expr,
-                                  HValue* object,
-                                  Handle<String> name,
-                                  HValue* value,
-                                  bool is_uninitialized = false);
+  HInstruction* BuildNamedGeneric(PropertyAccessType access, Expression* expr,
+                                  HValue* object, Handle<String> name,
+                                  HValue* value, bool is_uninitialized = false);
 
   HCheckMaps* AddCheckMap(HValue* object, Handle<Map> map);
 
index 69fa9ca..9dfdd63 100644 (file)
@@ -395,8 +395,8 @@ void SetResolvedNumberSettings(Isolate* isolate,
   Handle<String> key =
       factory->NewStringFromStaticChars("minimumSignificantDigits");
   Maybe<bool> maybe = JSReceiver::HasOwnProperty(resolved, key);
-  CHECK(maybe.has_value);
-  if (maybe.value) {
+  CHECK(maybe.IsJust());
+  if (maybe.FromJust()) {
     JSObject::SetProperty(
         resolved, factory->NewStringFromStaticChars("minimumSignificantDigits"),
         factory->NewNumberFromInt(number_format->getMinimumSignificantDigits()),
@@ -405,8 +405,8 @@ void SetResolvedNumberSettings(Isolate* isolate,
 
   key = factory->NewStringFromStaticChars("maximumSignificantDigits");
   maybe = JSReceiver::HasOwnProperty(resolved, key);
-  CHECK(maybe.has_value);
-  if (maybe.value) {
+  CHECK(maybe.IsJust());
+  if (maybe.FromJust()) {
     JSObject::SetProperty(
         resolved, factory->NewStringFromStaticChars("maximumSignificantDigits"),
         factory->NewNumberFromInt(number_format->getMaximumSignificantDigits()),
@@ -725,8 +725,8 @@ icu::SimpleDateFormat* DateFormat::UnpackDateFormat(
   Handle<String> key =
       isolate->factory()->NewStringFromStaticChars("dateFormat");
   Maybe<bool> maybe = JSReceiver::HasOwnProperty(obj, key);
-  CHECK(maybe.has_value);
-  if (maybe.value) {
+  CHECK(maybe.IsJust());
+  if (maybe.FromJust()) {
     return reinterpret_cast<icu::SimpleDateFormat*>(
         obj->GetInternalField(0));
   }
@@ -805,8 +805,8 @@ icu::DecimalFormat* NumberFormat::UnpackNumberFormat(
   Handle<String> key =
       isolate->factory()->NewStringFromStaticChars("numberFormat");
   Maybe<bool> maybe = JSReceiver::HasOwnProperty(obj, key);
-  CHECK(maybe.has_value);
-  if (maybe.value) {
+  CHECK(maybe.IsJust());
+  if (maybe.FromJust()) {
     return reinterpret_cast<icu::DecimalFormat*>(obj->GetInternalField(0));
   }
 
@@ -866,8 +866,8 @@ icu::Collator* Collator::UnpackCollator(Isolate* isolate,
                                         Handle<JSObject> obj) {
   Handle<String> key = isolate->factory()->NewStringFromStaticChars("collator");
   Maybe<bool> maybe = JSReceiver::HasOwnProperty(obj, key);
-  CHECK(maybe.has_value);
-  if (maybe.value) {
+  CHECK(maybe.IsJust());
+  if (maybe.FromJust()) {
     return reinterpret_cast<icu::Collator*>(obj->GetInternalField(0));
   }
 
@@ -931,8 +931,8 @@ icu::BreakIterator* BreakIterator::UnpackBreakIterator(Isolate* isolate,
   Handle<String> key =
       isolate->factory()->NewStringFromStaticChars("breakIterator");
   Maybe<bool> maybe = JSReceiver::HasOwnProperty(obj, key);
-  CHECK(maybe.has_value);
-  if (maybe.value) {
+  CHECK(maybe.IsJust());
+  if (maybe.FromJust()) {
     return reinterpret_cast<icu::BreakIterator*>(obj->GetInternalField(0));
   }
 
index 61e0ac9..c743cad 100644 (file)
@@ -2,20 +2,28 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-"use strict";
-
 // ECMAScript 402 API implementation.
 
 /**
  * Intl object is a single object that has some named properties,
  * all of which are constructors.
  */
-$Object.defineProperty(global, "Intl", { enumerable: false, value: (function() {
+(function() {
 
-var Intl = {};
+"use strict";
+
+%CheckIsBootstrapping();
+
+var GlobalDate = global.Date;
+var GlobalRegExp = global.RegExp;
+var GlobalString = global.String;
 
 var undefined = global.undefined;
 
+var Intl = {};
+
+%AddNamedProperty(global, "Intl", Intl, DONT_ENUM);
+
 var AVAILABLE_SERVICES = ['collator',
                           'numberformat',
                           'dateformat',
@@ -48,7 +56,7 @@ var UNICODE_EXTENSION_RE = undefined;
 
 function GetUnicodeExtensionRE() {
   if (UNICODE_EXTENSION_RE === undefined) {
-    UNICODE_EXTENSION_RE = new $RegExp('-u(-[a-z0-9]{2,8})+', 'g');
+    UNICODE_EXTENSION_RE = new GlobalRegExp('-u(-[a-z0-9]{2,8})+', 'g');
   }
   return UNICODE_EXTENSION_RE;
 }
@@ -60,7 +68,7 @@ var ANY_EXTENSION_RE = undefined;
 
 function GetAnyExtensionRE() {
   if (ANY_EXTENSION_RE === undefined) {
-    ANY_EXTENSION_RE = new $RegExp('-[a-z0-9]{1}-.*', 'g');
+    ANY_EXTENSION_RE = new GlobalRegExp('-[a-z0-9]{1}-.*', 'g');
   }
   return ANY_EXTENSION_RE;
 }
@@ -72,7 +80,7 @@ var QUOTED_STRING_RE = undefined;
 
 function GetQuotedStringRE() {
   if (QUOTED_STRING_RE === undefined) {
-    QUOTED_STRING_RE = new $RegExp("'[^']+'", 'g');
+    QUOTED_STRING_RE = new GlobalRegExp("'[^']+'", 'g');
   }
   return QUOTED_STRING_RE;
 }
@@ -85,7 +93,7 @@ var SERVICE_RE = undefined;
 function GetServiceRE() {
   if (SERVICE_RE === undefined) {
     SERVICE_RE =
-        new $RegExp('^(collator|numberformat|dateformat|breakiterator)$');
+        new GlobalRegExp('^(collator|numberformat|dateformat|breakiterator)$');
   }
   return SERVICE_RE;
 }
@@ -135,7 +143,7 @@ var TIMEZONE_NAME_CHECK_RE = undefined;
 function GetTimezoneNameCheckRE() {
   if (TIMEZONE_NAME_CHECK_RE === undefined) {
     TIMEZONE_NAME_CHECK_RE =
-        new $RegExp('^([A-Za-z]+)/([A-Za-z]+)(?:_([A-Za-z]+))*$');
+        new GlobalRegExp('^([A-Za-z]+)/([A-Za-z]+)(?:_([A-Za-z]+))*$');
   }
   return TIMEZONE_NAME_CHECK_RE;
 }
@@ -283,7 +291,7 @@ function supportedLocalesOf(service, locales, options) {
 
   var matcher = options.localeMatcher;
   if (matcher !== undefined) {
-    matcher = $String(matcher);
+    matcher = GlobalString(matcher);
     if (matcher !== 'lookup' && matcher !== 'best fit') {
       throw new $RangeError('Illegal value for localeMatcher:' + matcher);
     }
@@ -369,7 +377,7 @@ function getGetOption(options, caller) {
           value = $Boolean(value);
           break;
         case 'string':
-          value = $String(value);
+          value = GlobalString(value);
           break;
         case 'number':
           value = $Number(value);
@@ -525,7 +533,7 @@ function setOptions(inOptions, extensionMap, keyValues, getOption, outOptions) {
   var extension = '';
 
   var updateExtension = function updateExtension(key, value) {
-    return '-' + key + '-' + $String(value);
+    return '-' + key + '-' + GlobalString(value);
   }
 
   var updateProperty = function updateProperty(property, type, value) {
@@ -614,7 +622,7 @@ function getOptimalLanguageTag(original, resolved) {
   }
 
   // Preserve extensions of resolved locale, but swap base tags with original.
-  var resolvedBase = new $RegExp('^' + locales[1].base);
+  var resolvedBase = new GlobalRegExp('^' + locales[1].base);
   return resolved.replace(resolvedBase, locales[0].base);
 }
 
@@ -704,7 +712,7 @@ function canonicalizeLanguageTag(localeID) {
     throw new $TypeError('Language ID should be string or object.');
   }
 
-  var localeString = $String(localeID);
+  var localeString = GlobalString(localeID);
 
   if (isValidLanguageTag(localeString) === false) {
     throw new $RangeError('Invalid language tag: ' + localeString);
@@ -833,12 +841,12 @@ function BuildLanguageTagREs() {
   var privateUse = '(x(-' + alphanum + '{1,8})+)';
 
   var singleton = '(' + digit + '|[A-WY-Za-wy-z])';
-  LANGUAGE_SINGLETON_RE = new $RegExp('^' + singleton + '$', 'i');
+  LANGUAGE_SINGLETON_RE = new GlobalRegExp('^' + singleton + '$', 'i');
 
   var extension = '(' + singleton + '(-' + alphanum + '{2,8})+)';
 
   var variant = '(' + alphanum + '{5,8}|(' + digit + alphanum + '{3}))';
-  LANGUAGE_VARIANT_RE = new $RegExp('^' + variant + '$', 'i');
+  LANGUAGE_VARIANT_RE = new GlobalRegExp('^' + variant + '$', 'i');
 
   var region = '(' + alpha + '{2}|' + digit + '{3})';
   var script = '(' + alpha + '{4})';
@@ -850,7 +858,7 @@ function BuildLanguageTagREs() {
 
   var languageTag =
       '^(' + langTag + '|' + privateUse + '|' + grandfathered + ')$';
-  LANGUAGE_TAG_RE = new $RegExp(languageTag, 'i');
+  LANGUAGE_TAG_RE = new GlobalRegExp(languageTag, 'i');
 }
 
 /**
@@ -1023,7 +1031,7 @@ function initializeCollator(collator, locales, options) {
  */
 function compare(collator, x, y) {
   return %InternalCompare(%GetImplFromInitializedIntlObject(collator),
-                          $String(x), $String(y));
+                          GlobalString(x), GlobalString(y));
 };
 
 
@@ -1276,7 +1284,7 @@ function formatNumber(formatter, value) {
  */
 function parseNumber(formatter, value) {
   return %InternalNumberParse(%GetImplFromInitializedIntlObject(formatter),
-                              $String(value));
+                              GlobalString(value));
 }
 
 
@@ -1658,7 +1666,7 @@ function initializeDateTimeFormat(dateFormat, locales, options) {
 function formatDate(formatter, dateValue) {
   var dateMs;
   if (dateValue === undefined) {
-    dateMs = $Date.now();
+    dateMs = GlobalDate.now();
   } else {
     dateMs = $Number(dateValue);
   }
@@ -1668,7 +1676,7 @@ function formatDate(formatter, dateValue) {
   }
 
   return %InternalDateFormat(%GetImplFromInitializedIntlObject(formatter),
-                             new $Date(dateMs));
+                             new GlobalDate(dateMs));
 }
 
 
@@ -1680,7 +1688,7 @@ function formatDate(formatter, dateValue) {
  */
 function parseDate(formatter, value) {
   return %InternalDateParse(%GetImplFromInitializedIntlObject(formatter),
-                            $String(value));
+                            GlobalString(value));
 }
 
 
@@ -1841,7 +1849,7 @@ function initializeBreakIterator(iterator, locales, options) {
  */
 function adoptText(iterator, text) {
   %BreakIteratorAdoptText(%GetImplFromInitializedIntlObject(iterator),
-                          $String(text));
+                          GlobalString(text));
 }
 
 
@@ -1924,8 +1932,7 @@ function cachedOrNewService(service, locales, options, defaults) {
  * Compares this and that, and returns less than 0, 0 or greater than 0 value.
  * Overrides the built-in method.
  */
-ObjectDefineProperty($String.prototype, 'localeCompare', {
-  value: function(that) {
+OverrideFunction(GlobalString.prototype, 'localeCompare', function(that) {
     if (%_IsConstructCall()) {
       throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
     }
@@ -1938,14 +1945,8 @@ ObjectDefineProperty($String.prototype, 'localeCompare', {
     var options = %_Arguments(2);
     var collator = cachedOrNewService('collator', locales, options);
     return compare(collator, this, that);
-  },
-  writable: true,
-  configurable: true,
-  enumerable: false
-});
-%FunctionSetName($String.prototype.localeCompare, 'localeCompare');
-%FunctionRemovePrototype($String.prototype.localeCompare);
-%SetNativeFlag($String.prototype.localeCompare);
+  }
+);
 
 
 /**
@@ -1955,15 +1956,14 @@ ObjectDefineProperty($String.prototype, 'localeCompare', {
  * If the form is not one of "NFC", "NFD", "NFKC", or "NFKD", then throw
  * a RangeError Exception.
  */
-ObjectDefineProperty($String.prototype, 'normalize', {
-  value: function(that) {
+OverrideFunction(GlobalString.prototype, 'normalize', function(that) {
     if (%_IsConstructCall()) {
       throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
     }
 
     CHECK_OBJECT_COERCIBLE(this, "String.prototype.normalize");
 
-    var form = $String(%_Arguments(0) || 'NFC');
+    var form = GlobalString(%_Arguments(0) || 'NFC');
 
     var normalizationForm = NORMALIZATION_FORMS.indexOf(form);
     if (normalizationForm === -1) {
@@ -1972,22 +1972,15 @@ ObjectDefineProperty($String.prototype, 'normalize', {
     }
 
     return %StringNormalize(this, normalizationForm);
-  },
-  writable: true,
-  configurable: true,
-  enumerable: false
-});
-%FunctionSetName($String.prototype.normalize, 'normalize');
-%FunctionRemovePrototype($String.prototype.normalize);
-%SetNativeFlag($String.prototype.normalize);
+  }
+);
 
 
 /**
  * Formats a Number object (this) using locale and options values.
  * If locale or options are omitted, defaults are used.
  */
-ObjectDefineProperty($Number.prototype, 'toLocaleString', {
-  value: function() {
+OverrideFunction($Number.prototype, 'toLocaleString', function() {
     if (%_IsConstructCall()) {
       throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
     }
@@ -2000,21 +1993,15 @@ ObjectDefineProperty($Number.prototype, 'toLocaleString', {
     var options = %_Arguments(1);
     var numberFormat = cachedOrNewService('numberformat', locales, options);
     return formatNumber(numberFormat, this);
-  },
-  writable: true,
-  configurable: true,
-  enumerable: false
-});
-%FunctionSetName($Number.prototype.toLocaleString, 'toLocaleString');
-%FunctionRemovePrototype($Number.prototype.toLocaleString);
-%SetNativeFlag($Number.prototype.toLocaleString);
+  }
+);
 
 
 /**
  * Returns actual formatted date or fails if date parameter is invalid.
  */
 function toLocaleDateTime(date, locales, options, required, defaults, service) {
-  if (!(date instanceof $Date)) {
+  if (!(date instanceof GlobalDate)) {
     throw new $TypeError('Method invoked on an object that is not Date.');
   }
 
@@ -2036,8 +2023,7 @@ function toLocaleDateTime(date, locales, options, required, defaults, service) {
  * If locale or options are omitted, defaults are used - both date and time are
  * present in the output.
  */
-ObjectDefineProperty($Date.prototype, 'toLocaleString', {
-  value: function() {
+OverrideFunction(GlobalDate.prototype, 'toLocaleString', function() {
     if (%_IsConstructCall()) {
       throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
     }
@@ -2046,14 +2032,8 @@ ObjectDefineProperty($Date.prototype, 'toLocaleString', {
     var options = %_Arguments(1);
     return toLocaleDateTime(
         this, locales, options, 'any', 'all', 'dateformatall');
-  },
-  writable: true,
-  configurable: true,
-  enumerable: false
-});
-%FunctionSetName($Date.prototype.toLocaleString, 'toLocaleString');
-%FunctionRemovePrototype($Date.prototype.toLocaleString);
-%SetNativeFlag($Date.prototype.toLocaleString);
+  }
+);
 
 
 /**
@@ -2061,8 +2041,7 @@ ObjectDefineProperty($Date.prototype, 'toLocaleString', {
  * If locale or options are omitted, defaults are used - only date is present
  * in the output.
  */
-ObjectDefineProperty($Date.prototype, 'toLocaleDateString', {
-  value: function() {
+OverrideFunction(GlobalDate.prototype, 'toLocaleDateString', function() {
     if (%_IsConstructCall()) {
       throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
     }
@@ -2071,14 +2050,8 @@ ObjectDefineProperty($Date.prototype, 'toLocaleDateString', {
     var options = %_Arguments(1);
     return toLocaleDateTime(
         this, locales, options, 'date', 'date', 'dateformatdate');
-  },
-  writable: true,
-  configurable: true,
-  enumerable: false
-});
-%FunctionSetName($Date.prototype.toLocaleDateString, 'toLocaleDateString');
-%FunctionRemovePrototype($Date.prototype.toLocaleDateString);
-%SetNativeFlag($Date.prototype.toLocaleDateString);
+  }
+);
 
 
 /**
@@ -2086,8 +2059,7 @@ ObjectDefineProperty($Date.prototype, 'toLocaleDateString', {
  * If locale or options are omitted, defaults are used - only time is present
  * in the output.
  */
-ObjectDefineProperty($Date.prototype, 'toLocaleTimeString', {
-  value: function() {
+OverrideFunction(GlobalDate.prototype, 'toLocaleTimeString', function() {
     if (%_IsConstructCall()) {
       throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
     }
@@ -2096,14 +2068,7 @@ ObjectDefineProperty($Date.prototype, 'toLocaleTimeString', {
     var options = %_Arguments(1);
     return toLocaleDateTime(
         this, locales, options, 'time', 'time', 'dateformattime');
-  },
-  writable: true,
-  configurable: true,
-  enumerable: false
-});
-%FunctionSetName($Date.prototype.toLocaleTimeString, 'toLocaleTimeString');
-%FunctionRemovePrototype($Date.prototype.toLocaleTimeString);
-%SetNativeFlag($Date.prototype.toLocaleTimeString);
-
-return Intl;
-}())});
+  }
+);
+
+})();
index c7ec6d9..0fbd2c5 100644 (file)
@@ -154,12 +154,24 @@ void RelocInfo::set_target_object(Object* target,
 }
 
 
-Address RelocInfo::target_reference() {
+Address RelocInfo::target_external_reference() {
   DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
   return Memory::Address_at(pc_);
 }
 
 
+Address RelocInfo::target_internal_reference() {
+  DCHECK(rmode_ == INTERNAL_REFERENCE);
+  return Memory::Address_at(pc_);
+}
+
+
+Address RelocInfo::target_internal_reference_address() {
+  DCHECK(rmode_ == INTERNAL_REFERENCE);
+  return reinterpret_cast<Address>(pc_);
+}
+
+
 Address RelocInfo::target_runtime_entry(Assembler* origin) {
   DCHECK(IsRuntimeEntry(rmode_));
   return reinterpret_cast<Address>(*reinterpret_cast<int32_t*>(pc_));
@@ -268,7 +280,8 @@ Object** RelocInfo::call_object_address() {
 
 
 void RelocInfo::WipeOut() {
-  if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_)) {
+  if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
+      IsInternalReference(rmode_)) {
     Memory::Address_at(pc_) = NULL;
   } else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
     // Effectively write zero into the relocation.
@@ -300,7 +313,8 @@ void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
     visitor->VisitCell(this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     visitor->VisitExternalReference(this);
-    CpuFeatures::FlushICache(pc_, sizeof(Address));
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
+    visitor->VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     visitor->VisitCodeAgeSequence(this);
   } else if (((RelocInfo::IsJSReturn(mode) &&
@@ -327,7 +341,8 @@ void RelocInfo::Visit(Heap* heap) {
     StaticVisitor::VisitCell(heap, this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     StaticVisitor::VisitExternalReference(this);
-    CpuFeatures::FlushICache(pc_, sizeof(Address));
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
+    StaticVisitor::VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     StaticVisitor::VisitCodeAgeSequence(heap, this);
   } else if (heap->isolate()->debug()->has_break_points() &&
@@ -516,6 +531,12 @@ void Assembler::emit_near_disp(Label* L) {
 }
 
 
+void Assembler::deserialization_set_target_internal_reference_at(
+    Address pc, Address target, RelocInfo::Mode mode) {
+  Memory::Address_at(pc) = target;
+}
+
+
 void Operand::set_modrm(int mod, Register rm) {
   DCHECK((mod & -4) == 0);
   buf_[0] = mod << 6 | rm.code();
index 511b1c8..2a3384d 100644 (file)
@@ -179,17 +179,6 @@ bool RelocInfo::IsInConstantPool() {
 }
 
 
-void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
-  // Patch the code at the current address with the supplied instructions.
-  for (int i = 0; i < instruction_count; i++) {
-    *(pc_ + i) = *(instructions + i);
-  }
-
-  // Indicate that code has changed.
-  CpuFeatures::FlushICache(pc_, instruction_count);
-}
-
-
 // Patch the code at the current PC with a call to the target address.
 // Additional guard int3 instructions can be added if required.
 void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
@@ -2228,6 +2217,42 @@ void Assembler::pcmpeqd(XMMRegister dst, XMMRegister src) {
 }
 
 
+void Assembler::punpckldq(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x62);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::punpckhdq(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x6A);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::maxsd(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xF2);
+  EMIT(0x0F);
+  EMIT(0x5F);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::minsd(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xF2);
+  EMIT(0x0F);
+  EMIT(0x5D);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::cmpltsd(XMMRegister dst, XMMRegister src) {
   EnsureSpace ensure_space(this);
   EMIT(0xF2);
index a17b539..c5894cc 100644 (file)
@@ -40,8 +40,8 @@
 #include <deque>
 
 #include "src/assembler.h"
+#include "src/compiler.h"
 #include "src/isolate.h"
-#include "src/serialize.h"
 
 namespace v8 {
 namespace internal {
@@ -279,6 +279,14 @@ inline Condition CommuteCondition(Condition cc) {
 }
 
 
+enum RoundingMode {
+  kRoundToNearest = 0x0,
+  kRoundDown = 0x1,
+  kRoundUp = 0x2,
+  kRoundToZero = 0x3
+};
+
+
 // -----------------------------------------------------------------------------
 // Machine instruction Immediates
 
@@ -538,6 +546,11 @@ class Assembler : public AssemblerBase {
     set_target_address_at(instruction_payload, code, target);
   }
 
+  // This sets the internal reference at the pc.
+  inline static void deserialization_set_target_internal_reference_at(
+      Address pc, Address target,
+      RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
+
   static const int kSpecialTargetSize = kPointerSize;
 
   // Distance between the address of the code target in the call instruction
@@ -1002,13 +1015,6 @@ class Assembler : public AssemblerBase {
   void ucomisd(XMMRegister dst, XMMRegister src) { ucomisd(dst, Operand(src)); }
   void ucomisd(XMMRegister dst, const Operand& src);
 
-  enum RoundingMode {
-    kRoundToNearest = 0x0,
-    kRoundDown      = 0x1,
-    kRoundUp        = 0x2,
-    kRoundToZero    = 0x3
-  };
-
   void roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode);
 
   void movmskpd(Register dst, XMMRegister src);
@@ -1017,6 +1023,14 @@ class Assembler : public AssemblerBase {
   void cmpltsd(XMMRegister dst, XMMRegister src);
   void pcmpeqd(XMMRegister dst, XMMRegister src);
 
+  void punpckldq(XMMRegister dst, XMMRegister src);
+  void punpckhdq(XMMRegister dst, XMMRegister src);
+
+  void maxsd(XMMRegister dst, XMMRegister src) { maxsd(dst, Operand(src)); }
+  void maxsd(XMMRegister dst, const Operand& src);
+  void minsd(XMMRegister dst, XMMRegister src) { minsd(dst, Operand(src)); }
+  void minsd(XMMRegister dst, const Operand& src);
+
   void movdqa(XMMRegister dst, const Operand& src);
   void movdqa(const Operand& dst, XMMRegister src);
   void movdqu(XMMRegister dst, const Operand& src);
@@ -1241,6 +1255,18 @@ class Assembler : public AssemblerBase {
   void vdivsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
     vsd(0x5e, dst, src1, src2);
   }
+  void vmaxsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vmaxsd(dst, src1, Operand(src2));
+  }
+  void vmaxsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vsd(0x5f, dst, src1, src2);
+  }
+  void vminsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vminsd(dst, src1, Operand(src2));
+  }
+  void vminsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vsd(0x5d, dst, src1, src2);
+  }
   void vsd(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);
 
   // Prefetch src position into cache level.
@@ -1266,7 +1292,7 @@ class Assembler : public AssemblerBase {
 
   // Record a deoptimization reason that can be used by a log or cpu profiler.
   // Use --trace-deopt to enable.
-  void RecordDeoptReason(const int reason, const int raw_position);
+  void RecordDeoptReason(const int reason, const SourcePosition position);
 
   // Writes a single byte or word of data in the code stream.  Used for
   // inline tables, e.g., jump-tables.
index 9aa4e07..ea9b8c9 100644 (file)
@@ -990,42 +990,116 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
 }
 
 
-void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
-  static const int kArgumentsOffset = 2 * kPointerSize;
-  static const int kReceiverOffset = 3 * kPointerSize;
-  static const int kFunctionOffset = 4 * kPointerSize;
+static void Generate_CheckStackOverflow(MacroAssembler* masm,
+                                        const int calleeOffset) {
+  // eax   : the number of items to be pushed to the stack
+  //
+  // 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;
+  ExternalReference real_stack_limit =
+      ExternalReference::address_of_real_stack_limit(masm->isolate());
+  __ mov(edi, Operand::StaticVariable(real_stack_limit));
+  // Make ecx the space we have left. The stack might already be overflowed
+  // here which will cause ecx to become negative.
+  __ mov(ecx, esp);
+  __ sub(ecx, edi);
+  // Make edx the space we need for the array when it is unrolled onto the
+  // stack.
+  __ mov(edx, eax);
+  __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
+  // Check if the arguments will overflow the stack.
+  __ cmp(ecx, edx);
+  __ j(greater, &okay);  // Signed comparison.
+
+  // Out of stack space.
+  __ push(Operand(ebp, calleeOffset));  // push this
+  __ push(eax);
+  __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+
+  __ bind(&okay);
+}
+
+
+static void Generate_PushAppliedArguments(MacroAssembler* masm,
+                                          const int argumentsOffset,
+                                          const int indexOffset,
+                                          const int limitOffset) {
+  // Copy all arguments from the array to the stack.
+  Label entry, loop;
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register key = LoadDescriptor::NameRegister();
+  __ mov(key, Operand(ebp, indexOffset));
+  __ jmp(&entry);
+  __ bind(&loop);
+  __ mov(receiver, Operand(ebp, argumentsOffset));  // load arguments
+
+  if (FLAG_vector_ics) {
+    // 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.
+  }
+
+  // Push the nth argument.
+  __ push(eax);
+
+  // Update the index on the stack and in register key.
+  __ mov(key, Operand(ebp, indexOffset));
+  __ add(key, Immediate(1 << kSmiTagSize));
+  __ mov(Operand(ebp, indexOffset), key);
+
+  __ bind(&entry);
+  __ cmp(key, Operand(ebp, limitOffset));
+  __ j(not_equal, &loop);
+
+  // On exit, the pushed arguments count is in eax, untagged
+  __ Move(eax, key);
+  __ SmiUntag(eax);
+}
+
+
+// Used by FunctionApply and ReflectApply
+static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
+  const int kFormalParameters = targetIsArgument ? 3 : 2;
+  const int kStackSize = kFormalParameters + 1;
+
+  // Stack at entry:
+  // esp     : return address
+  // esp[4]  : arguments
+  // esp[8]  : receiver ("this")
+  // esp[12] : function
   {
     FrameScope frame_scope(masm, StackFrame::INTERNAL);
+    // Stack frame:
+    // ebp     : Old base pointer
+    // ebp[4]  : return address
+    // ebp[8]  : function arguments
+    // ebp[12] : receiver
+    // ebp[16] : function
+    static const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize;
+    static const int kReceiverOffset = kArgumentsOffset + kPointerSize;
+    static const int kFunctionOffset = kReceiverOffset + kPointerSize;
 
     __ push(Operand(ebp, kFunctionOffset));  // push this
     __ push(Operand(ebp, kArgumentsOffset));  // push arguments
-    __ 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;
-    ExternalReference real_stack_limit =
-        ExternalReference::address_of_real_stack_limit(masm->isolate());
-    __ mov(edi, Operand::StaticVariable(real_stack_limit));
-    // Make ecx the space we have left. The stack might already be overflowed
-    // here which will cause ecx to become negative.
-    __ mov(ecx, esp);
-    __ sub(ecx, edi);
-    // Make edx the space we need for the array when it is unrolled onto the
-    // stack.
-    __ mov(edx, eax);
-    __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
-    // Check if the arguments will overflow the stack.
-    __ cmp(ecx, edx);
-    __ j(greater, &okay);  // Signed comparison.
-
-    // Out of stack space.
-    __ push(Operand(ebp, 4 * kPointerSize));  // push this
-    __ push(eax);
-    __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
-    __ bind(&okay);
-    // End of stack check.
+    if (targetIsArgument) {
+      __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION);
+    } else {
+      __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
+    }
+
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
 
     // Push current index and limit.
     const int kLimitOffset =
@@ -1088,55 +1162,20 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
     __ bind(&push_receiver);
     __ push(ebx);
 
-    // Copy all arguments from the array to the stack.
-    Label entry, loop;
-    Register receiver = LoadDescriptor::ReceiverRegister();
-    Register key = LoadDescriptor::NameRegister();
-    __ mov(key, Operand(ebp, kIndexOffset));
-    __ jmp(&entry);
-    __ bind(&loop);
-    __ mov(receiver, Operand(ebp, kArgumentsOffset));  // load arguments
-
-    if (FLAG_vector_ics) {
-      // 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.
-    }
-
-    // Push the nth argument.
-    __ push(eax);
-
-    // Update the index on the stack and in register key.
-    __ mov(key, Operand(ebp, kIndexOffset));
-    __ add(key, Immediate(1 << kSmiTagSize));
-    __ mov(Operand(ebp, kIndexOffset), key);
-
-    __ bind(&entry);
-    __ cmp(key, Operand(ebp, kLimitOffset));
-    __ j(not_equal, &loop);
+    // Loop over the arguments array, pushing each value to the stack
+    Generate_PushAppliedArguments(
+        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
 
     // Call the function.
     Label call_proxy;
     ParameterCount actual(eax);
-    __ Move(eax, key);
-    __ SmiUntag(eax);
     __ mov(edi, Operand(ebp, kFunctionOffset));
     __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
     __ j(not_equal, &call_proxy);
     __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper());
 
     frame_scope.GenerateLeaveFrame();
-    __ ret(3 * kPointerSize);  // remove this, receiver, and arguments
+    __ ret(kStackSize * kPointerSize);  // remove this, receiver, and arguments
 
     // Call the function proxy.
     __ bind(&call_proxy);
@@ -1149,7 +1188,92 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
 
     // Leave internal frame.
   }
-  __ ret(3 * kPointerSize);  // remove this, receiver, and arguments
+  __ ret(kStackSize * kPointerSize);  // remove this, receiver, and arguments
+}
+
+
+// Used by ReflectConstruct
+static void Generate_ConstructHelper(MacroAssembler* masm) {
+  const int kFormalParameters = 3;
+  const int kStackSize = kFormalParameters + 1;
+
+  // Stack at entry:
+  // esp     : return address
+  // esp[4]  : original constructor (new.target)
+  // esp[8]  : arguments
+  // esp[16] : constructor
+  {
+    FrameScope frame_scope(masm, StackFrame::INTERNAL);
+    // Stack frame:
+    // ebp     : Old base pointer
+    // ebp[4]  : return address
+    // ebp[8]  : original constructor (new.target)
+    // ebp[12] : arguments
+    // ebp[16] : constructor
+    static const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize;
+    static const int kArgumentsOffset = kNewTargetOffset + kPointerSize;
+    static const int kFunctionOffset = kArgumentsOffset + kPointerSize;
+
+    // If newTarget is not supplied, set it to constructor
+    Label validate_arguments;
+    __ mov(eax, Operand(ebp, kNewTargetOffset));
+    __ CompareRoot(eax, Heap::kUndefinedValueRootIndex);
+    __ j(not_equal, &validate_arguments, Label::kNear);
+    __ mov(eax, Operand(ebp, kFunctionOffset));
+    __ mov(Operand(ebp, kNewTargetOffset), eax);
+
+    // Validate arguments
+    __ bind(&validate_arguments);
+    __ push(Operand(ebp, kFunctionOffset));
+    __ push(Operand(ebp, kArgumentsOffset));
+    __ push(Operand(ebp, kNewTargetOffset));
+    __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION);
+
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
+
+    // Push current index and limit.
+    const int kLimitOffset =
+        StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
+    const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
+    __ Push(eax);  // limit
+    __ push(Immediate(0));  // index
+    // Push newTarget and callee functions
+    __ push(Operand(ebp, kNewTargetOffset));
+    __ push(Operand(ebp, kFunctionOffset));
+
+    // Loop over the arguments array, pushing each value to the stack
+    Generate_PushAppliedArguments(
+        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
+
+    // Use undefined feedback vector
+    __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
+    __ mov(edi, Operand(ebp, kFunctionOffset));
+
+    // Call the function.
+    CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
+    __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
+
+    __ Drop(1);
+
+    // Leave internal frame.
+  }
+  // remove this, target, arguments, and newTarget
+  __ ret(kStackSize * kPointerSize);
+}
+
+
+void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+  Generate_ApplyHelper(masm, false);
+}
+
+
+void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
+  Generate_ApplyHelper(masm, true);
+}
+
+
+void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
+  Generate_ConstructHelper(masm);
 }
 
 
index 9b7d902..5436eee 100644 (file)
@@ -12,6 +12,7 @@
 #include "src/codegen.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
@@ -729,7 +730,7 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
   __ ret(0);
 
   StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
+  char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&miss);
   PropertyAccessCompiler::TailCallBuiltin(
@@ -1078,8 +1079,15 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
   __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
 
   if (has_new_target()) {
+    // If the constructor was [[Call]]ed, the call will not push a new.target
+    // onto the stack. In that case the arguments array we construct is bogus,
+    // bu we do not care as the constructor throws immediately.
+    __ cmp(ecx, Immediate(Smi::FromInt(0)));
+    Label skip_decrement;
+    __ j(equal, &skip_decrement);
     // Subtract 1 from smi-tagged arguments count.
     __ sub(ecx, Immediate(2));
+    __ bind(&skip_decrement);
   }
 
   __ lea(edx, Operand(edx, ecx, times_2,
@@ -1189,7 +1197,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   // 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);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 #else  // V8_INTERPRETED_REGEXP
 
   // Stack frame on entry.
@@ -1465,22 +1473,9 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   __ mov(eax, Operand::StaticVariable(pending_exception));
   __ cmp(edx, eax);
   __ j(equal, &runtime);
-  // For exception, throw the exception again.
-
-  // Clear the pending exception variable.
-  __ mov(Operand::StaticVariable(pending_exception), edx);
-
-  // Special handling of termination exceptions which are uncatchable
-  // by javascript code.
-  __ cmp(eax, factory->termination_exception());
-  Label throw_termination_exception;
-  __ j(equal, &throw_termination_exception, Label::kNear);
-
-  // Handle normal exception by following handler chain.
-  __ Throw(eax);
 
-  __ bind(&throw_termination_exception);
-  __ ThrowUncatchable(eax);
+  // For exception, throw the exception again.
+  __ TailCallRuntime(Runtime::kRegExpExecReThrow, 4, 1);
 
   __ bind(&failure);
   // For failure to match, return null.
@@ -1572,7 +1567,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
 
   // Do the runtime call to execute the regexp.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 
   // Deferred code for string handling.
   // (7) Not a long external string?  If yes, go to (10).
@@ -2516,15 +2511,14 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   __ cmp(eax, isolate()->factory()->exception());
   __ j(equal, &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) {
     __ push(edx);
     __ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
     Label okay;
+    ExternalReference pending_exception_address(
+        Isolate::kPendingExceptionAddress, isolate());
     __ cmp(edx, Operand::StaticVariable(pending_exception_address));
     // Cannot use check here as it attempts to generate call into runtime.
     __ j(equal, &okay, Label::kNear);
@@ -2540,24 +2534,48 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // Handling of exception.
   __ bind(&exception_returned);
 
-  // Retrieve the pending exception.
-  __ mov(eax, Operand::StaticVariable(pending_exception_address));
-
-  // Clear the pending exception.
-  __ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
-  __ mov(Operand::StaticVariable(pending_exception_address), edx);
-
-  // Special handling of termination exceptions which are uncatchable
-  // by javascript code.
-  Label throw_termination_exception;
-  __ cmp(eax, isolate()->factory()->termination_exception());
-  __ j(equal, &throw_termination_exception);
-
-  // Handle normal exception.
-  __ Throw(eax);
+  ExternalReference pending_handler_context_address(
+      Isolate::kPendingHandlerContextAddress, isolate());
+  ExternalReference pending_handler_code_address(
+      Isolate::kPendingHandlerCodeAddress, isolate());
+  ExternalReference pending_handler_offset_address(
+      Isolate::kPendingHandlerOffsetAddress, isolate());
+  ExternalReference pending_handler_fp_address(
+      Isolate::kPendingHandlerFPAddress, isolate());
+  ExternalReference pending_handler_sp_address(
+      Isolate::kPendingHandlerSPAddress, isolate());
+
+  // Ask the runtime for help to determine the handler. This will set eax to
+  // contain the current pending exception, don't clobber it.
+  ExternalReference find_handler(Runtime::kFindExceptionHandler, isolate());
+  {
+    FrameScope scope(masm, StackFrame::MANUAL);
+    __ PrepareCallCFunction(3, eax);
+    __ mov(Operand(esp, 0 * kPointerSize), Immediate(0));  // argc.
+    __ mov(Operand(esp, 1 * kPointerSize), Immediate(0));  // argv.
+    __ mov(Operand(esp, 2 * kPointerSize),
+           Immediate(ExternalReference::isolate_address(isolate())));
+    __ CallCFunction(find_handler, 3);
+  }
 
-  __ bind(&throw_termination_exception);
-  __ ThrowUncatchable(eax);
+  // Retrieve the handler context, SP and FP.
+  __ mov(esi, Operand::StaticVariable(pending_handler_context_address));
+  __ mov(esp, Operand::StaticVariable(pending_handler_sp_address));
+  __ mov(ebp, Operand::StaticVariable(pending_handler_fp_address));
+
+  // If the handler is a JS frame, restore the context to the frame. Note that
+  // the context will be set to (esi == 0) for non-JS frames.
+  Label skip;
+  __ test(esi, esi);
+  __ j(zero, &skip, Label::kNear);
+  __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
+  __ bind(&skip);
+
+  // Compute the handler entry address and jump to it.
+  __ mov(edi, Operand::StaticVariable(pending_handler_code_address));
+  __ mov(edx, Operand::StaticVariable(pending_handler_offset_address));
+  __ lea(edi, FieldOperand(edi, edx, times_1, Code::kHeaderSize));
+  __ jmp(edi);
 }
 
 
@@ -2607,10 +2625,9 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ mov(eax, Immediate(isolate()->factory()->exception()));
   __ jmp(&exit);
 
-  // Invoke: Link this frame into the handler chain.  There's only one
-  // handler block in this code object, so its index is 0.
+  // Invoke: Link this frame into the handler chain.
   __ bind(&invoke);
-  __ PushTryHandler(StackHandler::JS_ENTRY, 0);
+  __ PushStackHandler();
 
   // Clear any pending exceptions.
   __ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
@@ -2636,7 +2653,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ call(edx);
 
   // Unlink this frame from the handler chain.
-  __ PopTryHandler();
+  __ PopStackHandler();
 
   __ bind(&exit);
   // Check if the current stack frame is marked as the outermost JS frame.
@@ -2924,7 +2941,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
 
 
 void StringCharCodeAtGenerator::GenerateSlow(
-    MacroAssembler* masm,
+    MacroAssembler* masm, EmbedMode embed_mode,
     const RuntimeCallHelper& call_helper) {
   __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
 
@@ -2936,6 +2953,10 @@ void StringCharCodeAtGenerator::GenerateSlow(
               index_not_number_,
               DONT_DO_SMI_CHECK);
   call_helper.BeforeCall(masm);
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ push(VectorLoadICDescriptor::VectorRegister());
+    __ push(VectorLoadICDescriptor::SlotRegister());
+  }
   __ push(object_);
   __ push(index_);  // Consumed by runtime conversion function.
   if (index_flags_ == STRING_INDEX_IS_NUMBER) {
@@ -2951,6 +2972,10 @@ void StringCharCodeAtGenerator::GenerateSlow(
     __ mov(index_, eax);
   }
   __ pop(object_);
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ pop(VectorLoadICDescriptor::SlotRegister());
+    __ pop(VectorLoadICDescriptor::VectorRegister());
+  }
   // Reload the instance type.
   __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
   __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
@@ -3266,7 +3291,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
 
   // Just jump to runtime to create the sub string.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kSubString, 3, 1);
+  __ TailCallRuntime(Runtime::kSubStringRT, 3, 1);
 
   __ bind(&single_char);
   // eax: string
@@ -3489,7 +3514,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
   // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
   // tagged as a small integer.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+  __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
 }
 
 
@@ -3801,7 +3826,7 @@ void CompareICStub::GenerateStrings(MacroAssembler* masm) {
   if (equality) {
     __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
   } else {
-    __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+    __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
   }
 
   __ bind(&miss);
@@ -4381,15 +4406,234 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
 
 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorLoadStub stub(isolate(), state());
-  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawLoadStub stub(isolate(), state());
+  stub.GenerateForTrampoline(masm);
 }
 
 
 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorKeyedLoadStub stub(isolate());
-  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawKeyedLoadStub stub(isolate());
+  stub.GenerateForTrampoline(masm);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+                             Register key, Register vector, Register slot,
+                             Register feedback, bool is_polymorphic,
+                             Label* miss) {
+  // feedback initially contains the feedback array
+  Label next, next_loop, prepare_next;
+  Label load_smi_map, compare_map;
+  Label start_polymorphic;
+
+  __ push(receiver);
+  __ push(vector);
+
+  Register receiver_map = receiver;
+  Register cached_map = vector;
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &load_smi_map);
+  __ mov(receiver_map, FieldOperand(receiver, 0));
+  __ bind(&compare_map);
+  __ mov(cached_map, FieldOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+
+  // A named keyed load might have a 2 element array, all other cases can count
+  // on an array with at least 2 {map, handler} pairs, so they can go right
+  // into polymorphic array handling.
+  __ cmp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
+  __ j(not_equal, is_polymorphic ? &start_polymorphic : &next);
+
+  // found, now call handler.
+  Register handler = feedback;
+  __ mov(handler, FieldOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+  __ pop(vector);
+  __ pop(receiver);
+  __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+
+  if (!is_polymorphic) {
+    __ bind(&next);
+    __ cmp(FieldOperand(feedback, FixedArray::kLengthOffset),
+           Immediate(Smi::FromInt(2)));
+    __ j(not_equal, &start_polymorphic);
+    __ pop(vector);
+    __ pop(receiver);
+    __ jmp(miss);
+  }
+
+  // Polymorphic, we have to loop from 2 to N
+  __ bind(&start_polymorphic);
+  __ push(key);
+  Register counter = key;
+  __ mov(counter, Immediate(Smi::FromInt(2)));
+  __ bind(&next_loop);
+  __ mov(cached_map, FieldOperand(feedback, counter, times_half_pointer_size,
+                                  FixedArray::kHeaderSize));
+  __ cmp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
+  __ j(not_equal, &prepare_next);
+  __ mov(handler, FieldOperand(feedback, counter, times_half_pointer_size,
+                               FixedArray::kHeaderSize + kPointerSize));
+  __ pop(key);
+  __ pop(vector);
+  __ pop(receiver);
+  __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+
+  __ bind(&prepare_next);
+  __ add(counter, Immediate(Smi::FromInt(2)));
+  __ cmp(counter, FieldOperand(feedback, FixedArray::kLengthOffset));
+  __ j(less, &next_loop);
+
+  // We exhausted our array of map handler pairs.
+  __ pop(key);
+  __ pop(vector);
+  __ pop(receiver);
+  __ jmp(miss);
+
+  __ bind(&load_smi_map);
+  __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
+  __ jmp(&compare_map);
+}
+
+
+static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+                                  Register key, Register vector, Register slot,
+                                  Register weak_cell, Label* miss) {
+  // feedback initially contains the feedback array
+  Label compare_smi_map;
+
+  // Move the weak map into the weak_cell register.
+  Register ic_map = weak_cell;
+  __ mov(ic_map, FieldOperand(weak_cell, WeakCell::kValueOffset));
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &compare_smi_map);
+  __ cmp(ic_map, FieldOperand(receiver, 0));
+  __ j(not_equal, miss);
+  Register handler = weak_cell;
+  __ mov(handler, FieldOperand(vector, slot, times_half_pointer_size,
+                               FixedArray::kHeaderSize + kPointerSize));
+  __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+
+  // In microbenchmarks, it made sense to unroll this code so that the call to
+  // the handler is duplicated for a HeapObject receiver and a Smi receiver.
+  __ bind(&compare_smi_map);
+  __ CompareRoot(ic_map, Heap::kHeapNumberMapRootIndex);
+  __ j(not_equal, miss);
+  __ mov(handler, FieldOperand(vector, slot, times_half_pointer_size,
+                               FixedArray::kHeaderSize + kPointerSize));
+  __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+}
+
+
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // edx
+  Register name = VectorLoadICDescriptor::NameRegister();          // ecx
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // ebx
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // eax
+  Register scratch = edi;
+  __ mov(scratch, FieldOperand(vector, slot, times_half_pointer_size,
+                               FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ CompareRoot(FieldOperand(scratch, 0), Heap::kWeakCellMapRootIndex);
+  __ j(not_equal, &try_array);
+  HandleMonomorphicCase(masm, receiver, name, vector, slot, scratch, &miss);
+
+  // Is it a fixed array?
+  __ bind(&try_array);
+  __ CompareRoot(FieldOperand(scratch, 0), Heap::kFixedArrayMapRootIndex);
+  __ j(not_equal, &not_array);
+  HandleArrayCases(masm, receiver, name, vector, slot, scratch, true, &miss);
+
+  __ bind(&not_array);
+  __ CompareRoot(scratch, Heap::kmegamorphic_symbolRootIndex);
+  __ j(not_equal, &miss);
+  __ push(slot);
+  __ push(vector);
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::LOAD_IC, code_flags, false, receiver, name, vector, scratch);
+  __ pop(vector);
+  __ pop(slot);
+
+  __ bind(&miss);
+  LoadIC::GenerateMiss(masm);
+}
+
+
+void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // edx
+  Register key = VectorLoadICDescriptor::NameRegister();           // ecx
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // ebx
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // eax
+  Register feedback = edi;
+  __ mov(feedback, FieldOperand(vector, slot, times_half_pointer_size,
+                                FixedArray::kHeaderSize));
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ CompareRoot(FieldOperand(feedback, 0), Heap::kWeakCellMapRootIndex);
+  __ j(not_equal, &try_array);
+  HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, &miss);
+
+  __ bind(&try_array);
+  // Is it a fixed array?
+  __ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
+  __ j(not_equal, &not_array);
+
+  // We have a polymorphic element handler.
+  Label polymorphic, try_poly_name;
+  __ bind(&polymorphic);
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, true, &miss);
+
+  __ bind(&not_array);
+  // Is it generic?
+  __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+  __ j(not_equal, &try_poly_name);
+  Handle<Code> megamorphic_stub =
+      KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+  __ jmp(megamorphic_stub, RelocInfo::CODE_TARGET);
+
+  __ bind(&try_poly_name);
+  // We might have a name in feedback, and a fixed array in the next slot.
+  __ cmp(key, feedback);
+  __ j(not_equal, &miss);
+  // If the name comparison succeeded, we know we have a fixed array with
+  // at least one map/handler pair.
+  __ mov(feedback, FieldOperand(vector, slot, times_half_pointer_size,
+                                FixedArray::kHeaderSize + kPointerSize));
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, false, &miss);
+
+  __ bind(&miss);
+  KeyedLoadIC::GenerateMiss(masm);
 }
 
 
@@ -4875,7 +5119,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
   __ mov(eax, return_value_operand);
 
   Label promote_scheduled_exception;
-  Label exception_handled;
   Label delete_allocated_handles;
   Label leave_exit_frame;
 
@@ -4887,7 +5130,17 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
   __ Assert(above_equal, kInvalidHandleScopeLevel);
   __ cmp(edi, Operand::StaticVariable(limit_address));
   __ j(not_equal, &delete_allocated_handles);
+
+  // Leave the API exit frame.
   __ bind(&leave_exit_frame);
+  bool restore_context = context_restore_operand != NULL;
+  if (restore_context) {
+    __ mov(esi, *context_restore_operand);
+  }
+  if (stack_space_operand != nullptr) {
+    __ mov(ebx, *stack_space_operand);
+  }
+  __ LeaveApiExitFrame(!restore_context);
 
   // Check if the function scheduled an exception.
   ExternalReference scheduled_exception_address =
@@ -4895,7 +5148,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
   __ cmp(Operand::StaticVariable(scheduled_exception_address),
          Immediate(isolate->factory()->the_hole_value()));
   __ j(not_equal, &promote_scheduled_exception);
-  __ bind(&exception_handled);
 
 #if DEBUG
   // Check if the function returned a valid JavaScript value.
@@ -4932,14 +5184,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
   __ bind(&ok);
 #endif
 
-  bool restore_context = context_restore_operand != NULL;
-  if (restore_context) {
-    __ mov(esi, *context_restore_operand);
-  }
-  if (stack_space_operand != nullptr) {
-    __ mov(ebx, *stack_space_operand);
-  }
-  __ LeaveApiExitFrame(!restore_context);
   if (stack_space_operand != nullptr) {
     DCHECK_EQ(0, stack_space);
     __ pop(ecx);
@@ -4949,12 +5193,9 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
     __ ret(stack_space * kPointerSize);
   }
 
+  // Re-throw by promoting a scheduled exception.
   __ bind(&promote_scheduled_exception);
-  {
-    FrameScope frame(masm, StackFrame::INTERNAL);
-    __ CallRuntime(Runtime::kPromoteScheduledException, 0);
-  }
-  __ jmp(&exception_handled);
+  __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
 
   // HandleScope limit has changed. Delete allocated extensions.
   ExternalReference delete_extensions =
index 34b33b2..6d1c0f6 100644 (file)
 namespace v8 {
 namespace internal {
 
-bool BreakLocationIterator::IsDebugBreakAtReturn() {
-  return Debug::IsDebugBreakAtReturn(rinfo());
-}
 
+// Patch the code at the current PC with a call to the target address.
+// Additional guard int3 instructions can be added if required.
+void PatchCodeWithCall(Address pc, Address target, int guard_bytes) {
+  // Call instruction takes up 5 bytes and int3 takes up one byte.
+  static const int kCallCodeSize = 5;
+  int code_size = kCallCodeSize + guard_bytes;
 
-// Patch the JS frame exit code with a debug break call. See
-// CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-ia32.cc
-// for the precise return instructions sequence.
-void BreakLocationIterator::SetDebugBreakAtReturn() {
-  DCHECK(Assembler::kJSReturnSequenceLength >=
-         Assembler::kCallInstructionLength);
-  rinfo()->PatchCodeWithCall(
-      debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
-      Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
-}
+  // Create a code patcher.
+  CodePatcher patcher(pc, code_size);
 
+// Add a label for checking the size of the code used for returning.
+#ifdef DEBUG
+  Label check_codesize;
+  patcher.masm()->bind(&check_codesize);
+#endif
 
-// Restore the JS frame exit code.
-void BreakLocationIterator::ClearDebugBreakAtReturn() {
-  rinfo()->PatchCode(original_rinfo()->pc(),
-                     Assembler::kJSReturnSequenceLength);
-}
+  // Patch the code.
+  patcher.masm()->call(target, RelocInfo::NONE32);
 
+  // Check that the size of the code generated is as expected.
+  DCHECK_EQ(kCallCodeSize,
+            patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
 
-// 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();
+  // Add the requested number of int3 instructions after the call.
+  DCHECK_GE(guard_bytes, 0);
+  for (int i = 0; i < guard_bytes; i++) {
+    patcher.masm()->int3();
+  }
+
+  CpuFeatures::FlushICache(pc, code_size);
 }
 
 
-bool BreakLocationIterator::IsDebugBreakAtSlot() {
-  DCHECK(IsDebugBreakSlot());
-  // Check whether the debug break slot instructions have been patched.
-  return rinfo()->IsPatchedDebugBreakSlotSequence();
+// Patch the JS frame exit code with a debug break call. See
+// CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-ia32.cc
+// for the precise return instructions sequence.
+void BreakLocation::SetDebugBreakAtReturn() {
+  DCHECK(Assembler::kJSReturnSequenceLength >=
+         Assembler::kCallInstructionLength);
+  PatchCodeWithCall(
+      pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
+      Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
 }
 
 
-void BreakLocationIterator::SetDebugBreakAtSlot() {
+void BreakLocation::SetDebugBreakAtSlot() {
   DCHECK(IsDebugBreakSlot());
   Isolate* isolate = debug_info_->GetIsolate();
-  rinfo()->PatchCodeWithCall(
-      isolate->builtins()->Slot_DebugBreak()->entry(),
+  PatchCodeWithCall(
+      pc(), isolate->builtins()->Slot_DebugBreak()->entry(),
       Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength);
 }
 
 
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
-  DCHECK(IsDebugBreakSlot());
-  rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
-}
-
-
 #define __ ACCESS_MASM(masm)
 
 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
index 27e308d..5fbee32 100644 (file)
@@ -228,7 +228,7 @@ bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
 
 #define __ masm()->
 
-void Deoptimizer::EntryGenerator::Generate() {
+void Deoptimizer::TableEntryGenerator::Generate() {
   GeneratePrologue();
 
   // Save all general purpose registers before messing with them.
index 576c739..f1fba34 100644 (file)
@@ -826,11 +826,21 @@ int DisassemblerIA32::AVXInstruction(byte* data) {
                        NameOfXMMRegister(vvvv));
         current += PrintRightXMMOperand(current);
         break;
+      case 0x5d:
+        AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
       case 0x5e:
         AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
                        NameOfXMMRegister(vvvv));
         current += PrintRightXMMOperand(current);
         break;
+      case 0x5f:
+        AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
       default:
         UnimplementedInstruction();
     }
@@ -1554,6 +1564,20 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
                            NameOfXMMRegister(rm),
                            static_cast<int>(imm8));
             data += 2;
+          } else if (*data == 0x62) {
+            data++;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            AppendToBuffer("punpckldq %s,%s", NameOfXMMRegister(regop),
+                           NameOfXMMRegister(rm));
+            data++;
+          } else if (*data == 0x6A) {
+            data++;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            AppendToBuffer("punpckhdq %s,%s", NameOfXMMRegister(regop),
+                           NameOfXMMRegister(rm));
+            data++;
           } else if (*data == 0x76) {
             data++;
             int mod, regop, rm;
@@ -1744,7 +1768,13 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
               case 0x58: mnem = "addsd"; break;
               case 0x59: mnem = "mulsd"; break;
               case 0x5C: mnem = "subsd"; break;
+              case 0x5D:
+                mnem = "minsd";
+                break;
               case 0x5E: mnem = "divsd"; break;
+              case 0x5F:
+                mnem = "maxsd";
+                break;
             }
             data += 3;
             int mod, regop, rm;
index 1290ad6..f9d804f 100644 (file)
@@ -115,11 +115,6 @@ inline Object* JavaScriptFrame::function_slot_object() const {
 }
 
 
-inline void StackHandler::SetFp(Address slot, Address fp) {
-  Memory::Address_at(slot) = fp;
-}
-
-
 } }  // namespace v8::internal
 
 #endif  // V8_IA32_FRAMES_IA32_H_
index 8596705..1e578b4 100644 (file)
@@ -95,7 +95,8 @@ class JumpPatchSite BASE_EMBEDDED {
 void FullCodeGenerator::Generate() {
   CompilationInfo* info = info_;
   handler_table_ =
-      isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
+      Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray(
+          HandlerTable::LengthForRange(function()->handler_count()), TENURED));
 
   profiling_counter_ = isolate()->factory()->NewCell(
       Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
@@ -188,7 +189,7 @@ void FullCodeGenerator::Generate() {
     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_script_scope()) {
+    if (info->scope()->is_script_scope()) {
       __ push(edi);
       __ Push(info->scope()->GetScopeInfo(info->isolate()));
       __ CallRuntime(Runtime::kNewScriptContext, 2);
@@ -236,6 +237,11 @@ void FullCodeGenerator::Generate() {
     }
   }
 
+  ArgumentsAccessStub::HasNewTarget has_new_target =
+      IsSubclassConstructor(info->function()->kind())
+          ? ArgumentsAccessStub::HAS_NEW_TARGET
+          : ArgumentsAccessStub::NO_NEW_TARGET;
+
   // Possibly allocate RestParameters
   int rest_index;
   Variable* rest_param = scope()->rest_parameter(&rest_index);
@@ -244,6 +250,11 @@ void FullCodeGenerator::Generate() {
 
     int num_parameters = info->scope()->num_parameters();
     int offset = num_parameters * kPointerSize;
+    if (has_new_target == ArgumentsAccessStub::HAS_NEW_TARGET) {
+      --num_parameters;
+      ++rest_index;
+    }
+
     __ lea(edx,
            Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
     __ push(edx);
@@ -284,10 +295,7 @@ void FullCodeGenerator::Generate() {
     } else {
       type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
     }
-    ArgumentsAccessStub::HasNewTarget has_new_target =
-        IsSubclassConstructor(info->function()->kind())
-            ? ArgumentsAccessStub::HAS_NEW_TARGET
-            : ArgumentsAccessStub::NO_NEW_TARGET;
+
     ArgumentsAccessStub stub(isolate(), type, has_new_target);
     __ CallStub(&stub);
 
@@ -1453,7 +1461,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
                Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
       }
-      CallLoadIC(CONTEXTUAL);
+      CallGlobalLoadIC(var->name());
       context()->Plug(eax);
       break;
     }
@@ -2098,7 +2106,6 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
 
       // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
       __ bind(&l_catch);
-      handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
       __ mov(load_name, isolate()->factory()->throw_string());  // "throw"
       __ push(load_name);                                       // "throw"
       __ push(Operand(esp, 2 * kPointerSize));                  // iter
@@ -2110,16 +2117,17 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       // re-boxing.
       __ bind(&l_try);
       __ pop(eax);                                       // result
-      __ PushTryHandler(StackHandler::CATCH, expr->index());
-      const int handler_size = StackHandlerConstants::kSize;
+      EnterTryBlock(expr->index(), &l_catch);
+      const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ push(eax);                                      // result
       __ jmp(&l_suspend);
       __ bind(&l_continuation);
       __ jmp(&l_resume);
       __ bind(&l_suspend);
-      const int generator_object_depth = kPointerSize + handler_size;
+      const int generator_object_depth = kPointerSize + try_block_size;
       __ mov(eax, Operand(esp, generator_object_depth));
       __ push(eax);                                      // g
+      __ push(Immediate(Smi::FromInt(expr->index())));   // handler-index
       DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
       __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
              Immediate(Smi::FromInt(l_continuation.pos())));
@@ -2127,13 +2135,13 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       __ mov(ecx, esi);
       __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
                           kDontSaveFPRegs);
-      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 2);
       __ mov(context_register(),
              Operand(ebp, StandardFrameConstants::kContextOffset));
       __ pop(eax);                                       // result
       EmitReturnSequence();
       __ bind(&l_resume);                                // received in eax
-      __ PopTryHandler();
+      ExitTryBlock(expr->index());
 
       // receiver = iter; f = iter.next; arg = received;
       __ bind(&l_next);
@@ -2479,6 +2487,16 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
       __ push(Operand(esp, 0));  // prototype
     }
     EmitPropertyKey(property, lit->GetIdForProperty(i));
+
+    // The static prototype property is read only. We handle the non computed
+    // property name case in the parser. Since this is the only case where we
+    // need to check for an own read only property we special case this so we do
+    // not need to do this for every property.
+    if (property->is_static() && property->is_computed_name()) {
+      __ CallRuntime(Runtime::kThrowIfStaticPrototype, 1);
+      __ push(eax);
+    }
+
     VisitForStackValue(value);
     EmitSetHomeObjectIfNeeded(value, 2);
 
@@ -2616,25 +2634,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
     __ mov(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(eax);
-      __ push(esi);
-      __ push(Immediate(var->name()));
-      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
-    } else {
-      DCHECK(var->IsStackLocal() || var->IsContextSlot());
-      Label skip;
-      MemOperand location = VarOperand(var, ecx);
-      __ mov(edx, location);
-      __ cmp(edx, isolate()->factory()->the_hole_value());
-      __ j(not_equal, &skip, Label::kNear);
-      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());
@@ -2648,6 +2647,21 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
     __ CallRuntime(Runtime::kThrowReferenceError, 1);
     __ bind(&assign);
     EmitStoreToStackLocalOrContextSlot(var, location);
+
+  } else if (var->mode() == CONST && op != Token::INIT_CONST) {
+    // Assignment to const variable needs a write barrier.
+    DCHECK(!var->IsLookupSlot());
+    DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+    Label const_error;
+    MemOperand location = VarOperand(var, ecx);
+    __ mov(edx, location);
+    __ cmp(edx, isolate()->factory()->the_hole_value());
+    __ j(not_equal, &const_error, Label::kNear);
+    __ push(Immediate(var->name()));
+    __ CallRuntime(Runtime::kThrowReferenceError, 1);
+    __ bind(&const_error);
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
   } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
     if (var->IsLookupSlot()) {
       // Assignment to var.
@@ -2669,8 +2683,33 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
-  } else if (IsSignallingAssignmentToConst(var, op, language_mode())) {
-    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
+  } else if (op == Token::INIT_CONST_LEGACY) {
+    // Const initializers need a write barrier.
+    DCHECK(var->mode() == CONST_LEGACY);
+    DCHECK(!var->IsParameter());  // No const parameters.
+    if (var->IsLookupSlot()) {
+      __ push(eax);
+      __ push(esi);
+      __ push(Immediate(var->name()));
+      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
+    } else {
+      DCHECK(var->IsStackLocal() || var->IsContextSlot());
+      Label skip;
+      MemOperand location = VarOperand(var, ecx);
+      __ mov(edx, location);
+      __ cmp(edx, isolate()->factory()->the_hole_value());
+      __ j(not_equal, &skip, Label::kNear);
+      EmitStoreToStackLocalOrContextSlot(var, location);
+      __ bind(&skip);
+    }
+
+  } else {
+    DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT_CONST_LEGACY);
+    if (is_strict(language_mode())) {
+      __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+    }
+    // Silently ignore store in sloppy mode.
   }
 }
 
@@ -3138,8 +3177,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
 
 
 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
-  if (!ValidateSuperCall(expr)) return;
-
   Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
   GetVar(eax, new_target_var);
   __ push(eax);
@@ -3651,8 +3688,8 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 
   // Check if the constructor in the map is a JS function.
-  __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
-  __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
+  __ GetMapConstructor(eax, eax, ebx);
+  __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
   __ j(not_equal, &non_function_constructor);
 
   // eax now contains the constructor function. Grab the
@@ -3955,7 +3992,7 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
   __ jmp(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&done);
   context()->Plug(result);
@@ -4003,7 +4040,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
   __ jmp(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&done);
   context()->Plug(result);
@@ -4175,7 +4212,7 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
   // Call runtime to perform the lookup.
   __ push(cache);
   __ push(key);
-  __ CallRuntime(Runtime::kGetFromCache, 2);
+  __ CallRuntime(Runtime::kGetFromCacheRT, 2);
 
   __ bind(&done);
   context()->Plug(eax);
@@ -4495,17 +4532,11 @@ void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
 
 
 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()) {
+    Comment cmnt(masm_, "[ CallRuntime");
     // Push the builtins object as receiver.
     __ mov(eax, GlobalObjectOperand());
     __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
@@ -4525,9 +4556,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     __ push(Operand(esp, 0));
     __ mov(Operand(esp, kPointerSize), eax);
 
-    // Code common for calls using the IC.
-    ZoneList<Expression*>* args = expr->arguments();
-    int arg_count = args->length();
+    // Push the arguments ("left-to-right").
     for (int i = 0; i < arg_count; i++) {
       VisitForStackValue(args->at(i));
     }
@@ -4537,21 +4566,33 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
     __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
     __ CallStub(&stub);
+
     // Restore context register.
     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
     context()->DropAndPlug(1, eax);
 
   } else {
-    // Push the arguments ("left-to-right").
-    int arg_count = args->length();
-    for (int i = 0; i < arg_count; i++) {
-      VisitForStackValue(args->at(i));
-    }
-
-    // Call the C runtime function.
-    __ CallRuntime(expr->function(), arg_count);
+    const Runtime::Function* function = expr->function();
+    switch (function->function_id) {
+#define CALL_INTRINSIC_GENERATOR(Name)     \
+  case Runtime::kInline##Name: {           \
+    Comment cmnt(masm_, "[ Inline" #Name); \
+    return Emit##Name(expr);               \
+  }
+      FOR_EACH_FULL_CODE_INTRINSIC(CALL_INTRINSIC_GENERATOR)
+#undef CALL_INTRINSIC_GENERATOR
+      default: {
+        Comment cmnt(masm_, "[ CallRuntime for unhandled intrinsic");
+        // Push the arguments ("left-to-right").
+        for (int i = 0; i < arg_count; i++) {
+          VisitForStackValue(args->at(i));
+        }
 
-    context()->Plug(eax);
+        // Call the C runtime function.
+        __ CallRuntime(expr->function(), arg_count);
+        context()->Plug(eax);
+      }
+    }
   }
 }
 
@@ -5203,17 +5244,6 @@ void FullCodeGenerator::EnterFinallyBlock() {
       ExternalReference::address_of_pending_message_obj(isolate());
   __ mov(edx, Operand::StaticVariable(pending_message_obj));
   __ push(edx);
-
-  ExternalReference has_pending_message =
-      ExternalReference::address_of_has_pending_message(isolate());
-  __ mov(edx, Operand::StaticVariable(has_pending_message));
-  __ SmiTag(edx);
-  __ push(edx);
-
-  ExternalReference pending_message_script =
-      ExternalReference::address_of_pending_message_script(isolate());
-  __ mov(edx, Operand::StaticVariable(pending_message_script));
-  __ push(edx);
 }
 
 
@@ -5221,17 +5251,6 @@ void FullCodeGenerator::ExitFinallyBlock() {
   DCHECK(!result_register().is(edx));
   // Restore pending message from stack.
   __ pop(edx);
-  ExternalReference pending_message_script =
-      ExternalReference::address_of_pending_message_script(isolate());
-  __ mov(Operand::StaticVariable(pending_message_script), edx);
-
-  __ pop(edx);
-  __ SmiUntag(edx);
-  ExternalReference has_pending_message =
-      ExternalReference::address_of_has_pending_message(isolate());
-  __ mov(Operand::StaticVariable(has_pending_message), edx);
-
-  __ pop(edx);
   ExternalReference pending_message_obj =
       ExternalReference::address_of_pending_message_obj(isolate());
   __ mov(Operand::StaticVariable(pending_message_obj), edx);
@@ -5249,33 +5268,6 @@ void FullCodeGenerator::ExitFinallyBlock() {
 
 #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.
-    __ mov(esi, Operand(esp, StackHandlerConstants::kContextOffset));
-    __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
-  }
-  __ PopTryHandler();
-  __ call(finally_entry_);
-
-  *stack_depth = 0;
-  *context_length = 0;
-  return previous_;
-}
-
-#undef __
-
 
 static const byte kJnsInstruction = 0x79;
 static const byte kJnsOffset = 0x11;
index b0e57fc..407b1c7 100644 (file)
@@ -228,6 +228,12 @@ void InternalArrayConstructorDescriptor::Initialize(
 }
 
 
+void CompareDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {esi, edx, eax};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
 void CompareNilDescriptor::Initialize(CallInterfaceDescriptorData* data) {
   Register registers[] = {esi, eax};
   data->Initialize(arraysize(registers), registers, NULL);
index d750cb8..f0cd7b0 100644 (file)
@@ -10,6 +10,7 @@
 #include "src/code-factory.h"
 #include "src/code-stubs.h"
 #include "src/codegen.h"
+#include "src/cpu-profiler.h"
 #include "src/deoptimizer.h"
 #include "src/hydrogen-osr.h"
 #include "src/ia32/lithium-codegen-ia32.h"
@@ -140,7 +141,7 @@ bool LCodeGen::GeneratePrologue() {
     // 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() && is_sloppy(info_->language_mode()) &&
+    if (graph()->this_has_uses() && is_sloppy(info_->language_mode()) &&
         !info_->is_native()) {
       Label ok;
       // +1 for return address.
@@ -376,10 +377,11 @@ void LCodeGen::GenerateBodyInstructionPost(LInstruction* instr) { }
 
 
 bool LCodeGen::GenerateJumpTable() {
+  if (!jump_table_.length()) return !is_aborted();
+
   Label needs_frame;
-  if (jump_table_.length() > 0) {
-    Comment(";;; -------------------- Jump table --------------------");
-  }
+  Comment(";;; -------------------- Jump table --------------------");
+
   for (int i = 0; i < jump_table_.length(); i++) {
     Deoptimizer::JumpTableEntry* table_entry = &jump_table_[i];
     __ bind(&table_entry->label);
@@ -388,34 +390,55 @@ bool LCodeGen::GenerateJumpTable() {
     if (table_entry->needs_frame) {
       DCHECK(!info()->saves_caller_doubles());
       __ push(Immediate(ExternalReference::ForDeoptEntry(entry)));
-      if (needs_frame.is_bound()) {
-        __ jmp(&needs_frame);
-      } else {
-        __ bind(&needs_frame);
-        __ push(MemOperand(ebp, StandardFrameConstants::kContextOffset));
-        // 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());
-        __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
-        // Push a PC inside the function so that the deopt code can find where
-        // the deopt comes from. It doesn't have to be the precise return
-        // address of a "calling" LAZY deopt, it only has to be somewhere
-        // inside the code body.
-        Label push_approx_pc;
-        __ call(&push_approx_pc);
-        __ bind(&push_approx_pc);
-        // Push the continuation which was stashed were the ebp should
-        // be. Replace it with the saved ebp.
-        __ push(MemOperand(esp, 3 * kPointerSize));
-        __ mov(MemOperand(esp, 4 * kPointerSize), ebp);
-        __ lea(ebp, MemOperand(esp, 4 * kPointerSize));
-        __ ret(0);  // Call the continuation without clobbering registers.
-      }
+      __ call(&needs_frame);
     } else {
       if (info()->saves_caller_doubles()) RestoreCallerDoubles();
       __ call(entry, RelocInfo::RUNTIME_ENTRY);
     }
+    info()->LogDeoptCallPosition(masm()->pc_offset(),
+                                 table_entry->deopt_info.inlining_id);
+  }
+  if (needs_frame.is_linked()) {
+    __ bind(&needs_frame);
+    /* stack layout
+       4: entry address
+       3: return address  <-- esp
+       2: garbage
+       1: garbage
+       0: garbage
+    */
+    __ sub(esp, Immediate(kPointerSize));    // Reserve space for stub marker.
+    __ push(MemOperand(esp, kPointerSize));  // Copy return address.
+    __ push(MemOperand(esp, 3 * kPointerSize));  // Copy entry address.
+
+    /* stack layout
+       4: entry address
+       3: return address
+       2: garbage
+       1: return address
+       0: entry address  <-- esp
+    */
+    __ mov(MemOperand(esp, 4 * kPointerSize), ebp);  // Save ebp.
+    // Copy context.
+    __ mov(ebp, MemOperand(ebp, StandardFrameConstants::kContextOffset));
+    __ mov(MemOperand(esp, 3 * kPointerSize), ebp);
+    // Fill ebp with the right stack frame address.
+    __ lea(ebp, MemOperand(esp, 4 * kPointerSize));
+    // 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());
+    __ mov(MemOperand(esp, 2 * kPointerSize),
+           Immediate(Smi::FromInt(StackFrame::STUB)));
+
+    /* stack layout
+       4: old ebp
+       3: context pointer
+       2: stub marker
+       1: return address
+       0: entry address  <-- esp
+    */
+    __ ret(0);  // Call the continuation without clobbering registers.
   }
   return !is_aborted();
 }
@@ -861,12 +884,13 @@ void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
     __ bind(&done);
   }
 
-  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
-                                    instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info = MakeDeoptInfo(instr, deopt_reason);
+
   DCHECK(info()->IsStub() || frame_is_built_);
   if (cc == no_condition && frame_is_built_) {
     DeoptComment(deopt_info);
     __ call(entry, RelocInfo::RUNTIME_ENTRY);
+    info()->LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
   } else {
     Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
                                             !frame_is_built_);
@@ -2580,9 +2604,9 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
 
   // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
   // Check if the constructor in the map is a function.
-  __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
+  __ GetMapConstructor(temp, temp, temp2);
   // Objects with a non-function constructor have class 'Object'.
-  __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
+  __ CmpInstanceType(temp2, JS_FUNCTION_TYPE);
   if (String::Equals(class_name, isolate()->factory()->Object_string())) {
     __ j(not_equal, is_true);
   } else {
@@ -2839,16 +2863,6 @@ void LCodeGen::DoReturn(LReturn* instr) {
 }
 
 
-void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
-  Register result = ToRegister(instr->result());
-  __ mov(result, Operand::ForCell(instr->hydrogen()->cell().handle()));
-  if (instr->hydrogen()->RequiresHoleCheck()) {
-    __ cmp(result, factory()->the_hole_value());
-    DeoptimizeIf(equal, instr, Deoptimizer::kHole);
-  }
-}
-
-
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
@@ -2878,30 +2892,12 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
   }
   ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
-  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode,
+                                                       PREMONOMORPHIC).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
 
-void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
-  Register value = ToRegister(instr->value());
-  Handle<PropertyCell> cell_handle = 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. We deoptimize in that case.
-  if (instr->hydrogen()->RequiresHoleCheck()) {
-    __ cmp(Operand::ForCell(cell_handle), factory()->the_hole_value());
-    DeoptimizeIf(equal, instr, Deoptimizer::kHole);
-  }
-
-  // Store the value.
-  __ mov(Operand::ForCell(cell_handle), value);
-  // Cells are always rescanned, so no write barrier here.
-}
-
-
 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
   Register context = ToRegister(instr->context());
   Register result = ToRegister(instr->result());
@@ -3014,8 +3010,9 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
   if (FLAG_vector_ics) {
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
-  Handle<Code> ic =
-      CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(
+                        isolate(), NOT_CONTEXTUAL,
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3241,7 +3238,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code();
+  Handle<Code> ic =
+      CodeFactory::KeyedLoadICInOptimizedCode(
+          isolate(), instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3693,7 +3692,7 @@ void LCodeGen::DoMathFloor(LMathFloor* instr) {
       DeoptimizeIf(not_zero, instr, Deoptimizer::kMinusZero);
       __ bind(&non_zero);
     }
-    __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
+    __ roundsd(xmm_scratch, input_reg, kRoundDown);
     __ cvttsd2si(output_reg, Operand(xmm_scratch));
     // Overflow is signalled with minint.
     __ cmp(output_reg, 0x1);
@@ -3915,14 +3914,8 @@ void LCodeGen::DoMathLog(LMathLog* instr) {
 void LCodeGen::DoMathClz32(LMathClz32* instr) {
   Register input = ToRegister(instr->value());
   Register result = ToRegister(instr->result());
-  Label not_zero_input;
-  __ bsr(result, input);
 
-  __ j(not_zero, &not_zero_input);
-  __ Move(result, Immediate(63));  // 63^31 == 32
-
-  __ bind(&not_zero_input);
-  __ xor_(result, Immediate(31));  // for x in [0..31], 31^x == 31-x.
+  __ Lzcnt(result, input);
 }
 
 
@@ -4173,7 +4166,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
   __ mov(StoreDescriptor::NameRegister(), instr->name());
-  Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->language_mode());
+  Handle<Code> ic =
+      StoreIC::initialize_stub(isolate(), instr->language_mode(),
+                               instr->hydrogen()->initialization_state());
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -4350,8 +4345,9 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
   DCHECK(ToRegister(instr->key()).is(StoreDescriptor::NameRegister()));
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
-  Handle<Code> ic =
-      CodeFactory::KeyedStoreIC(isolate(), instr->language_mode()).code();
+  Handle<Code> ic = CodeFactory::KeyedStoreICInOptimizedCode(
+                        isolate(), instr->language_mode(),
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
index 1c8d075..0bda914 100644 (file)
@@ -2132,14 +2132,6 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
 }
 
 
-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(), esi);
   LOperand* global_object =
@@ -2155,13 +2147,6 @@ LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
-  LStoreGlobalCell* result =
-      new(zone()) LStoreGlobalCell(UseRegister(instr->value()));
-  return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
-}
-
-
 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
   LOperand* context = UseRegisterAtStart(instr->value());
   LInstruction* result =
index 3f59170..4ea444a 100644 (file)
@@ -103,7 +103,6 @@ class LCodeGen;
   V(LoadContextSlot)                         \
   V(LoadFieldByIndex)                        \
   V(LoadFunctionPrototype)                   \
-  V(LoadGlobalCell)                          \
   V(LoadGlobalGeneric)                       \
   V(LoadKeyed)                               \
   V(LoadKeyedGeneric)                        \
@@ -144,7 +143,6 @@ class LCodeGen;
   V(StoreCodeEntry)                          \
   V(StoreContextSlot)                        \
   V(StoreFrameContext)                       \
-  V(StoreGlobalCell)                         \
   V(StoreKeyed)                              \
   V(StoreKeyedGeneric)                       \
   V(StoreNamedField)                         \
@@ -1718,13 +1716,6 @@ class LLoadKeyedGeneric FINAL : public LTemplateInstruction<1, 3, 1> {
 };
 
 
-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,
@@ -1746,19 +1737,6 @@ class LLoadGlobalGeneric FINAL : public LTemplateInstruction<1, 2, 1> {
 };
 
 
-class LStoreGlobalCell FINAL : public LTemplateInstruction<0, 1, 0> {
- public:
-  explicit LStoreGlobalCell(LOperand* value) {
-    inputs_[0] = value;
-  }
-
-  LOperand* value() { return inputs_[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) {
index 53ffa39..c243ca2 100644 (file)
@@ -14,7 +14,6 @@
 #include "src/debug.h"
 #include "src/isolate-inl.h"
 #include "src/runtime/runtime.h"
-#include "src/serialize.h"
 
 namespace v8 {
 namespace internal {
@@ -1023,44 +1022,21 @@ void MacroAssembler::LeaveApiExitFrame(bool restore_context) {
 }
 
 
-void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
-                                    int handler_index) {
+void MacroAssembler::PushStackHandler() {
   // Adjust this code if not the case.
-  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kSize == 1 * 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);
-
-  // We will build up the handler from the bottom by pushing on the stack.
-  // First push the frame pointer and context.
-  if (kind == StackHandler::JS_ENTRY) {
-    // The frame pointer does not point to a JS frame so we save NULL for
-    // ebp. We expect the code throwing an exception to check ebp before
-    // dereferencing it to restore the context.
-    push(Immediate(0));  // NULL frame pointer.
-    push(Immediate(Smi::FromInt(0)));  // No context.
-  } else {
-    push(ebp);
-    push(esi);
-  }
-  // Push the state and the code object.
-  unsigned state =
-      StackHandler::IndexField::encode(handler_index) |
-      StackHandler::KindField::encode(kind);
-  push(Immediate(state));
-  Push(CodeObject());
 
   // Link the current handler as the next handler.
   ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
   push(Operand::StaticVariable(handler_address));
+
   // Set this new handler as the current one.
   mov(Operand::StaticVariable(handler_address), esp);
 }
 
 
-void MacroAssembler::PopTryHandler() {
+void MacroAssembler::PopStackHandler() {
   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
   ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
   pop(Operand::StaticVariable(handler_address));
@@ -1068,103 +1044,6 @@ void MacroAssembler::PopTryHandler() {
 }
 
 
-void MacroAssembler::JumpToHandlerEntry() {
-  // Compute the handler entry address and jump to it.  The handler table is
-  // a fixed array of (smi-tagged) code offsets.
-  // eax = exception, edi = code object, edx = state.
-  mov(ebx, FieldOperand(edi, Code::kHandlerTableOffset));
-  shr(edx, StackHandler::kKindWidth);
-  mov(edx, FieldOperand(ebx, edx, times_4, FixedArray::kHeaderSize));
-  SmiUntag(edx);
-  lea(edi, FieldOperand(edi, edx, times_1, Code::kHeaderSize));
-  jmp(edi);
-}
-
-
-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);
-
-  // The exception is expected in eax.
-  if (!value.is(eax)) {
-    mov(eax, value);
-  }
-  // Drop the stack pointer to the top of the top handler.
-  ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
-  mov(esp, Operand::StaticVariable(handler_address));
-  // Restore the next handler.
-  pop(Operand::StaticVariable(handler_address));
-
-  // Remove the code object and state, compute the handler address in edi.
-  pop(edi);  // Code object.
-  pop(edx);  // Index and state.
-
-  // Restore the context and frame pointer.
-  pop(esi);  // Context.
-  pop(ebp);  // Frame pointer.
-
-  // If the handler is a JS frame, restore the context to the frame.
-  // (kind == ENTRY) == (ebp == 0) == (esi == 0), so we could test either
-  // ebp or esi.
-  Label skip;
-  test(esi, esi);
-  j(zero, &skip, Label::kNear);
-  mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
-  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);
-  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 eax.
-  if (!value.is(eax)) {
-    mov(eax, value);
-  }
-  // Drop the stack pointer to the top of the top stack handler.
-  ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
-  mov(esp, Operand::StaticVariable(handler_address));
-
-  // Unwind the handlers until the top ENTRY handler is found.
-  Label fetch_next, check_kind;
-  jmp(&check_kind, Label::kNear);
-  bind(&fetch_next);
-  mov(esp, Operand(esp, StackHandlerConstants::kNextOffset));
-
-  bind(&check_kind);
-  STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
-  test(Operand(esp, StackHandlerConstants::kStateOffset),
-       Immediate(StackHandler::KindField::kMask));
-  j(not_zero, &fetch_next);
-
-  // Set the top handler address to next handler past the top ENTRY handler.
-  pop(Operand::StaticVariable(handler_address));
-
-  // Remove the code object and state, compute the handler address in edi.
-  pop(edi);  // Code object.
-  pop(edx);  // Index and state.
-
-  // Clear the context pointer and frame pointer (0 was saved in the handler).
-  pop(esi);
-  pop(ebp);
-
-  JumpToHandlerEntry();
-}
-
-
 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
                                             Register scratch1,
                                             Register scratch2,
@@ -1919,6 +1798,20 @@ void MacroAssembler::NegativeZeroTest(Register result,
 }
 
 
+void MacroAssembler::GetMapConstructor(Register result, Register map,
+                                       Register temp) {
+  Label done, loop;
+  mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
+  bind(&loop);
+  JumpIfSmi(result, &done);
+  CmpObjectType(result, MAP_TYPE, temp);
+  j(not_equal, &done);
+  mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
+  jmp(&loop);
+  bind(&done);
+}
+
+
 void MacroAssembler::TryGetFunctionPrototype(Register function,
                                              Register result,
                                              Register scratch,
@@ -1970,7 +1863,7 @@ void MacroAssembler::TryGetFunctionPrototype(Register function,
     // Non-instance prototype: Fetch prototype from constructor field
     // in initial map.
     bind(&non_instance);
-    mov(result, FieldOperand(result, Map::kConstructorOffset));
+    GetMapConstructor(result, result, scratch);
   }
 
   // All done.
@@ -2524,6 +2417,52 @@ void MacroAssembler::Move(XMMRegister dst, uint64_t src) {
 }
 
 
+void MacroAssembler::Pextrd(Register dst, XMMRegister src, int8_t imm8) {
+  if (imm8 == 0) {
+    movd(dst, src);
+    return;
+  }
+  DCHECK_EQ(1, imm8);
+  if (CpuFeatures::IsSupported(SSE4_1)) {
+    CpuFeatureScope sse_scope(this, SSE4_1);
+    pextrd(dst, src, imm8);
+    return;
+  }
+  pshufd(xmm0, src, 1);
+  movd(dst, xmm0);
+}
+
+
+void MacroAssembler::Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) {
+  DCHECK(imm8 == 0 || imm8 == 1);
+  if (CpuFeatures::IsSupported(SSE4_1)) {
+    CpuFeatureScope sse_scope(this, SSE4_1);
+    pinsrd(dst, src, imm8);
+    return;
+  }
+  movd(xmm0, src);
+  if (imm8 == 1) {
+    punpckldq(dst, xmm0);
+  } else {
+    DCHECK_EQ(0, imm8);
+    psrlq(dst, 32);
+    punpckldq(xmm0, dst);
+    movaps(dst, xmm0);
+  }
+}
+
+
+void MacroAssembler::Lzcnt(Register dst, const Operand& src) {
+  // TODO(intel): Add support for LZCNT (with ABM/BMI1).
+  Label not_zero_src;
+  bsr(dst, src);
+  j(not_zero, &not_zero_src, Label::kNear);
+  Move(dst, Immediate(63));  // 63^31 == 32
+  bind(&not_zero_src);
+  xor_(dst, Immediate(31));  // for x in [0..31], 31^x == 31-x.
+}
+
+
 void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
   if (FLAG_native_code_counters && counter->Enabled()) {
     mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
index e62c7d8..0be4585 100644 (file)
@@ -570,17 +570,11 @@ class MacroAssembler: public Assembler {
   // ---------------------------------------------------------------------------
   // Exception handling
 
-  // Push a new try handler and link it into try handler chain.
-  void PushTryHandler(StackHandler::Kind kind, int handler_index);
+  // Push a new stack handler and link it into stack handler chain.
+  void PushStackHandler();
 
-  // Unlink the stack handler on top of the stack from the try handler chain.
-  void PopTryHandler();
-
-  // Throw to the top handler in the try hander chain.
-  void Throw(Register value);
-
-  // Throw past all JS frames to the top JS entry frame.
-  void ThrowUncatchable(Register value);
+  // Unlink the stack handler on top of the stack from the stack handler chain.
+  void PopStackHandler();
 
   // ---------------------------------------------------------------------------
   // Inline caching support
@@ -718,6 +712,10 @@ class MacroAssembler: public Assembler {
   void NegativeZeroTest(Register result, Register op1, Register op2,
                         Register scratch, Label* then_label);
 
+  // Machine code version of Map::GetConstructor().
+  // |temp| holds |result|'s map when done.
+  void GetMapConstructor(Register result, Register map, Register temp);
+
   // 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
@@ -815,6 +813,16 @@ class MacroAssembler: public Assembler {
   void Push(Register src) { push(src); }
   void Pop(Register dst) { pop(dst); }
 
+  // Non-SSE2 instructions.
+  void Pextrd(Register dst, XMMRegister src, int8_t imm8);
+  void Pinsrd(XMMRegister dst, Register src, int8_t imm8) {
+    Pinsrd(dst, Operand(src), imm8);
+  }
+  void Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8);
+
+  void Lzcnt(Register dst, Register src) { Lzcnt(dst, Operand(src)); }
+  void Lzcnt(Register dst, const Operand& src);
+
   // Emit call to the code we are currently generating.
   void CallSelf() {
     Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
@@ -1005,10 +1013,6 @@ class MacroAssembler: public Assembler {
                           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.
   Operand SafepointRegisterSlot(Register reg);
   static int SafepointRegisterStackIndex(int reg_code);
index bacf44d..7f857ca 100644 (file)
@@ -197,11 +197,11 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
     Register scratch, Label* miss) {
-  Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
+  Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
   DCHECK(cell->value()->IsTheHole());
   Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
   __ LoadWeakValue(scratch, weak_cell, miss);
-  __ ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset));
+  __ ldr(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
   __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
   __ cmp(scratch, ip);
   __ b(ne, miss);
@@ -428,6 +428,17 @@ Register PropertyHandlerCompiler::CheckPrototypes(
   if (receiver_map->IsJSGlobalObjectMap()) {
     current = isolate()->global_object();
   }
+
+  // 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 (receiver_map->IsJSGlobalProxyMap()) {
+    __ CheckAccessGlobalProxy(reg, scratch2, miss);
+  }
+
   Handle<JSObject> prototype = Handle<JSObject>::null();
   Handle<Map> current_map = receiver_map;
   Handle<Map> holder_map(holder()->map());
@@ -462,23 +473,14 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     } else {
       Register map_reg = scratch1;
       __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
-      if (depth != 1 || check == CHECK_ALL_MAPS) {
-        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
-      // 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()) {
+      if (current_map->IsJSGlobalObjectMap()) {
         GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
                                   name, scratch2, miss);
+      } else if (depth != 1 || check == CHECK_ALL_MAPS) {
+        Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+        __ CmpWeakValue(map_reg, cell, scratch2);
+        __ b(ne, miss);
       }
 
       reg = holder_reg;  // From now on the object will be in holder_reg.
@@ -491,6 +493,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     current_map = handle(current->map());
   }
 
+  DCHECK(!current_map->IsJSGlobalProxyMap());
+
   // Log the check depth.
   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
 
@@ -502,13 +506,6 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     __ b(ne, miss);
   }
 
-  // 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;
 }
@@ -731,7 +728,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
   Register result = StoreDescriptor::ValueRegister();
   Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
   __ LoadWeakValue(result, weak_cell, &miss);
-  __ ldr(result, FieldMemOperand(result, Cell::kValueOffset));
+  __ ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset));
 
   // Check for deleted property if property can actually be deleted.
   if (is_configurable) {
index 12a2401..36d88c0 100644 (file)
@@ -109,11 +109,11 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
     Register scratch, Label* miss) {
-  Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
+  Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
   DCHECK(cell->value()->IsTheHole());
   Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
   __ LoadWeakValue(scratch, weak_cell, miss);
-  __ Ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset));
+  __ Ldr(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
   __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss);
 }
 
@@ -345,7 +345,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
   Register result = StoreDescriptor::ValueRegister();
   Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
   __ LoadWeakValue(result, weak_cell, &miss);
-  __ Ldr(result, FieldMemOperand(result, Cell::kValueOffset));
+  __ Ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset));
 
   // Check for deleted property if property can actually be deleted.
   if (is_configurable) {
@@ -477,6 +477,18 @@ Register PropertyHandlerCompiler::CheckPrototypes(
   if (receiver_map->IsJSGlobalObjectMap()) {
     current = isolate()->global_object();
   }
+
+  // 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 (receiver_map->IsJSGlobalProxyMap()) {
+    UseScratchRegisterScope temps(masm());
+    __ CheckAccessGlobalProxy(reg, scratch2, temps.AcquireX(), miss);
+  }
+
   Handle<JSObject> prototype = Handle<JSObject>::null();
   Handle<Map> current_map = receiver_map;
   Handle<Map> holder_map(holder()->map());
@@ -511,26 +523,15 @@ Register PropertyHandlerCompiler::CheckPrototypes(
       Register map_reg = scratch1;
       __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
 
-      if (depth != 1 || check == CHECK_ALL_MAPS) {
+      if (current_map->IsJSGlobalObjectMap()) {
+        GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
+                                  name, scratch2, miss);
+      } else if (depth != 1 || check == CHECK_ALL_MAPS) {
         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
-      // 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()) {
-        UseScratchRegisterScope temps(masm());
-        __ CheckAccessGlobalProxy(reg, scratch2, temps.AcquireX(), 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.
 
       __ Ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
@@ -541,6 +542,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     current_map = handle(current->map());
   }
 
+  DCHECK(!current_map->IsJSGlobalProxyMap());
+
   // Log the check depth.
   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
 
@@ -553,13 +556,6 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     __ B(ne, miss);
   }
 
-  // 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, scratch2, miss);
-  }
-
   // Return the register containing the holder.
   return reg;
 }
index acf380f..f103f8d 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "src/v8.h"
 
+#include "src/cpu-profiler.h"
 #include "src/ic/call-optimization.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
@@ -73,7 +74,7 @@ Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
                                               Handle<Name> name) {
   Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder());
   Handle<Code> code = GetCodeWithFlags(flags, name);
-  PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, *name));
+  PROFILE(isolate(), CodeCreateEvent(Logger::HANDLER_TAG, *code, *name));
 #ifdef DEBUG
   code->VerifyEmbeddedObjects();
 #endif
@@ -279,6 +280,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
     case LookupIterator::INTERCEPTOR:
     case LookupIterator::JSPROXY:
     case LookupIterator::NOT_FOUND:
+    case LookupIterator::INTEGER_INDEXED_EXOTIC:
       break;
     case LookupIterator::DATA:
       inline_followup =
@@ -310,10 +312,36 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
 
   Label miss;
   InterceptorVectorSlotPush(receiver());
+  bool lost_holder_register = false;
+  auto holder_orig = holder();
+  // non masking interceptors must check the entire chain, so temporarily reset
+  // the holder to be that last element for the FrontendHeader call.
+  if (holder()->GetNamedInterceptor()->non_masking()) {
+    DCHECK(!inline_followup);
+    JSObject* last = *holder();
+    PrototypeIterator iter(isolate(), last);
+    while (!iter.IsAtEnd()) {
+      lost_holder_register = true;
+      last = JSObject::cast(iter.GetCurrent());
+      iter.Advance();
+    }
+    auto last_handle = handle(last);
+    set_holder(last_handle);
+  }
   Register reg = FrontendHeader(receiver(), it->name(), &miss);
+  // Reset the holder so further calculations are correct.
+  set_holder(holder_orig);
+  if (lost_holder_register) {
+    if (*it->GetReceiver() == *holder()) {
+      reg = receiver();
+    } else {
+      // Reload lost holder register.
+      auto cell = isolate()->factory()->NewWeakCell(holder());
+      __ LoadWeakValue(reg, cell, &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.
@@ -345,6 +373,7 @@ void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
     case LookupIterator::INTERCEPTOR:
     case LookupIterator::JSPROXY:
     case LookupIterator::NOT_FOUND:
+    case LookupIterator::INTEGER_INDEXED_EXOTIC:
     case LookupIterator::TRANSITION:
       UNREACHABLE();
     case LookupIterator::DATA: {
index 94b48be..c02d83c 100644 (file)
@@ -431,6 +431,17 @@ Register PropertyHandlerCompiler::CheckPrototypes(
   if (receiver_map->IsJSGlobalObjectMap()) {
     current = isolate()->global_object();
   }
+
+  // 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 (receiver_map->IsJSGlobalProxyMap()) {
+    __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
+  }
+
   Handle<JSObject> prototype = Handle<JSObject>::null();
   Handle<Map> current_map = receiver_map;
   Handle<Map> holder_map(holder()->map());
@@ -465,26 +476,15 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     } else {
       Register map_reg = scratch1;
       __ mov(map_reg, FieldOperand(reg, HeapObject::kMapOffset));
-      if (depth != 1 || check == CHECK_ALL_MAPS) {
+      if (current_map->IsJSGlobalObjectMap()) {
+        GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
+                                  name, scratch2, miss);
+      } else if (depth != 1 || check == CHECK_ALL_MAPS) {
         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
-      // 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, 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);
-      }
       reg = holder_reg;  // From now on the object will be in holder_reg.
       __ mov(reg, FieldOperand(map_reg, Map::kPrototypeOffset));
     }
@@ -494,6 +494,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     current_map = handle(current->map());
   }
 
+  DCHECK(!current_map->IsJSGlobalProxyMap());
+
   // Log the check depth.
   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
 
@@ -505,13 +507,6 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     __ j(not_equal, miss);
   }
 
-  // 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, scratch2, miss);
-  }
-
   // Return the register containing the holder.
   return reg;
 }
index 08e0fa6..f597083 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "src/v8.h"
 
+#include "src/cpu-profiler.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic-inl.h"
 #include "src/ic/ic-compiler.h"
@@ -196,6 +197,8 @@ Handle<Code> PropertyICCompiler::ComputeLoad(Isolate* isolate,
     code = compiler.CompileLoadInitialize(flags);
   } else if (ic_state == PREMONOMORPHIC) {
     code = compiler.CompileLoadPreMonomorphic(flags);
+  } else if (ic_state == MEGAMORPHIC) {
+    code = compiler.CompileLoadMegamorphic(flags);
   } else {
     UNREACHABLE();
   }
@@ -333,6 +336,14 @@ Handle<Code> PropertyICCompiler::CompileLoadPreMonomorphic(Code::Flags flags) {
 }
 
 
+Handle<Code> PropertyICCompiler::CompileLoadMegamorphic(Code::Flags flags) {
+  MegamorphicLoadStub stub(isolate(), LoadICState(extra_ic_state_));
+  auto code = stub.GetCode();
+  PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_MEGAMORPHIC_TAG, *code, 0));
+  return code;
+}
+
+
 Handle<Code> PropertyICCompiler::CompileStoreInitialize(Code::Flags flags) {
   StoreIC::GenerateInitialize(masm());
   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
index d1bd7a1..a6c4e81 100644 (file)
@@ -70,6 +70,7 @@ class PropertyICCompiler : public PropertyAccessCompiler {
 
   Handle<Code> CompileLoadInitialize(Code::Flags flags);
   Handle<Code> CompileLoadPreMonomorphic(Code::Flags flags);
+  Handle<Code> CompileLoadMegamorphic(Code::Flags flags);
   Handle<Code> CompileStoreInitialize(Code::Flags flags);
   Handle<Code> CompileStorePreMonomorphic(Code::Flags flags);
   Handle<Code> CompileStoreGeneric(Code::Flags flags);
index a38a27a..13c8e64 100644 (file)
@@ -45,18 +45,17 @@ STATIC_CONST_MEMBER_DEFINITION const int BinaryOpICState::LAST_TOKEN;
 
 
 BinaryOpICState::BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state)
-    : isolate_(isolate) {
+    : fixed_right_arg_(
+          HasFixedRightArgField::decode(extra_ic_state)
+              ? Just(1 << FixedRightArgValueField::decode(extra_ic_state))
+              : Nothing<int>()),
+      isolate_(isolate) {
   op_ =
       static_cast<Token::Value>(FIRST_TOKEN + OpField::decode(extra_ic_state));
-  fixed_right_arg_ =
-      Maybe<int>(HasFixedRightArgField::decode(extra_ic_state),
-                 1 << FixedRightArgValueField::decode(extra_ic_state));
   left_kind_ = LeftKindField::decode(extra_ic_state);
-  if (fixed_right_arg_.has_value) {
-    right_kind_ = Smi::IsValid(fixed_right_arg_.value) ? SMI : INT32;
-  } else {
-    right_kind_ = RightKindField::decode(extra_ic_state);
-  }
+  right_kind_ = fixed_right_arg_.IsJust()
+                    ? (Smi::IsValid(fixed_right_arg_.FromJust()) ? SMI : INT32)
+                    : RightKindField::decode(extra_ic_state);
   result_kind_ = ResultKindField::decode(extra_ic_state);
   DCHECK_LE(FIRST_TOKEN, op_);
   DCHECK_LE(op_, LAST_TOKEN);
@@ -67,10 +66,10 @@ ExtraICState BinaryOpICState::GetExtraICState() const {
   ExtraICState extra_ic_state =
       OpField::encode(op_ - FIRST_TOKEN) | LeftKindField::encode(left_kind_) |
       ResultKindField::encode(result_kind_) |
-      HasFixedRightArgField::encode(fixed_right_arg_.has_value);
-  if (fixed_right_arg_.has_value) {
+      HasFixedRightArgField::encode(fixed_right_arg_.IsJust());
+  if (fixed_right_arg_.IsJust()) {
     extra_ic_state = FixedRightArgValueField::update(
-        extra_ic_state, WhichPowerOf2(fixed_right_arg_.value));
+        extra_ic_state, WhichPowerOf2(fixed_right_arg_.FromJust()));
   } else {
     extra_ic_state = RightKindField::update(extra_ic_state, right_kind_);
   }
@@ -89,7 +88,7 @@ void BinaryOpICState::GenerateAheadOfTime(
   do {                                                   \
     BinaryOpICState state(isolate, op);                  \
     state.left_kind_ = left_kind;                        \
-    state.fixed_right_arg_.has_value = false;            \
+    state.fixed_right_arg_ = Nothing<int>();             \
     state.right_kind_ = right_kind;                      \
     state.result_kind_ = result_kind;                    \
     Generate(isolate, state);                            \
@@ -191,8 +190,7 @@ void BinaryOpICState::GenerateAheadOfTime(
   do {                                                              \
     BinaryOpICState state(isolate, op);                             \
     state.left_kind_ = left_kind;                                   \
-    state.fixed_right_arg_.has_value = true;                        \
-    state.fixed_right_arg_.value = fixed_right_arg_value;           \
+    state.fixed_right_arg_ = Just(fixed_right_arg_value);           \
     state.right_kind_ = SMI;                                        \
     state.result_kind_ = result_kind;                               \
     Generate(isolate, state);                                       \
@@ -225,8 +223,8 @@ std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s) {
   os << "(" << Token::Name(s.op_);
   if (s.CouldCreateAllocationMementos()) os << "_CreateAllocationMementos";
   os << ":" << BinaryOpICState::KindToString(s.left_kind_) << "*";
-  if (s.fixed_right_arg_.has_value) {
-    os << s.fixed_right_arg_.value;
+  if (s.fixed_right_arg_.IsJust()) {
+    os << s.fixed_right_arg_.FromJust();
   } else {
     os << BinaryOpICState::KindToString(s.right_kind_);
   }
@@ -248,9 +246,9 @@ void BinaryOpICState::Update(Handle<Object> left, Handle<Object> right,
       base::bits::IsPowerOfTwo32(fixed_right_arg_value) &&
       FixedRightArgValueField::is_valid(WhichPowerOf2(fixed_right_arg_value)) &&
       (left_kind_ == SMI || left_kind_ == INT32) &&
-      (result_kind_ == NONE || !fixed_right_arg_.has_value);
-  fixed_right_arg_ = Maybe<int32_t>(has_fixed_right_arg, fixed_right_arg_value);
-
+      (result_kind_ == NONE || !fixed_right_arg_.IsJust());
+  fixed_right_arg_ =
+      has_fixed_right_arg ? Just(fixed_right_arg_value) : Nothing<int32_t>();
   result_kind_ = UpdateKind(result, result_kind_);
 
   if (!Token::IsTruncatingBinaryOp(op_)) {
index b5f58ed..f35bac3 100644 (file)
@@ -63,6 +63,7 @@ class BinaryOpICState FINAL BASE_EMBEDDED {
         left_kind_(NONE),
         right_kind_(NONE),
         result_kind_(NONE),
+        fixed_right_arg_(Nothing<int>()),
         isolate_(isolate) {
     DCHECK_LE(FIRST_TOKEN, op);
     DCHECK_LE(op, LAST_TOKEN);
index 93f33cf..0ba80d3 100644 (file)
@@ -230,6 +230,14 @@ bool IC::AddressIsOptimizedCode() const {
 }
 
 
+bool IC::AddressIsDeoptimizedCode() const {
+  Code* host =
+      isolate()->inner_pointer_to_code_cache()->GetCacheEntry(address())->code;
+  return host->kind() == Code::OPTIMIZED_FUNCTION &&
+         host->marked_for_deoptimization();
+}
+
+
 static void LookupForRead(LookupIterator* it) {
   for (; it->IsFound(); it->Next()) {
     switch (it->state()) {
@@ -249,12 +257,12 @@ static void LookupForRead(LookupIterator* it) {
       case LookupIterator::ACCESS_CHECK:
         // PropertyHandlerCompiler::CheckPrototypes() knows how to emit
         // access checks for global proxies.
-        if (it->GetHolder<JSObject>()->IsJSGlobalProxy() &&
-            it->HasAccess(v8::ACCESS_GET)) {
+        if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
           break;
         }
         return;
       case LookupIterator::ACCESSOR:
+      case LookupIterator::INTEGER_INDEXED_EXOTIC:
       case LookupIterator::DATA:
         return;
     }
@@ -308,8 +316,7 @@ bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
     LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
     if (it.state() == LookupIterator::ACCESS_CHECK) return false;
     if (!it.IsFound()) return false;
-    Handle<PropertyCell> cell = it.GetPropertyCell();
-    return cell->type()->IsConstant();
+    return it.property_details().cell_type() == PropertyCellType::kConstant;
   }
 
   return true;
@@ -714,7 +721,7 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
 
   bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
 
-  if (FLAG_harmony_scoping && object->IsGlobalObject() && name->IsString()) {
+  if (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);
@@ -942,12 +949,48 @@ Handle<Code> LoadIC::initialize_stub(Isolate* isolate,
 }
 
 
+Handle<Code> LoadIC::load_global(Isolate* isolate, Handle<GlobalObject> global,
+                                 Handle<String> name) {
+  // This special IC doesn't work with vector ics.
+  DCHECK(!FLAG_vector_ics);
+
+  Handle<ScriptContextTable> script_contexts(
+      global->native_context()->script_context_table());
+
+  ScriptContextTable::LookupResult lookup_result;
+  if (ScriptContextTable::Lookup(script_contexts, name, &lookup_result)) {
+    return initialize_stub(isolate, LoadICState(CONTEXTUAL).GetExtraICState());
+  }
+
+  Handle<Map> global_map(global->map());
+  Handle<Code> handler = PropertyHandlerCompiler::Find(
+      name, global_map, Code::LOAD_IC, kCacheOnReceiver, Code::NORMAL);
+  if (handler.is_null()) {
+    LookupIterator it(global, name);
+    if (!it.IsFound() || !it.GetHolder<JSObject>().is_identical_to(global) ||
+        it.state() != LookupIterator::DATA) {
+      return initialize_stub(isolate,
+                             LoadICState(CONTEXTUAL).GetExtraICState());
+    }
+    NamedLoadHandlerCompiler compiler(isolate, global_map, global,
+                                      kCacheOnReceiver);
+    Handle<PropertyCell> cell = it.GetPropertyCell();
+    handler = compiler.CompileLoadGlobal(cell, name, it.IsConfigurable());
+    Map::UpdateCodeCache(global_map, name, handler);
+  }
+  return PropertyICCompiler::ComputeMonomorphic(
+      Code::LOAD_IC, name, handle(global->map()), handler,
+      LoadICState(CONTEXTUAL).GetExtraICState());
+}
+
+
 Handle<Code> LoadIC::initialize_stub_in_optimized_code(
-    Isolate* isolate, ExtraICState extra_state) {
+    Isolate* isolate, ExtraICState extra_state, State initialization_state) {
   if (FLAG_vector_ics) {
-    return VectorLoadStub(isolate, LoadICState(extra_state)).GetCode();
+    return VectorRawLoadStub(isolate, LoadICState(extra_state)).GetCode();
   }
-  return initialize_stub(isolate, extra_state);
+  return PropertyICCompiler::ComputeLoad(isolate, initialization_state,
+                                         extra_state);
 }
 
 
@@ -960,11 +1003,45 @@ Handle<Code> KeyedLoadIC::initialize_stub(Isolate* isolate) {
 }
 
 
-Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(Isolate* isolate) {
+Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(
+    Isolate* isolate, State initialization_state) {
   if (FLAG_vector_ics) {
-    return VectorKeyedLoadStub(isolate).GetCode();
+    return VectorRawKeyedLoadStub(isolate).GetCode();
+  }
+  switch (initialization_state) {
+    case UNINITIALIZED:
+      return isolate->builtins()->KeyedLoadIC_Initialize();
+    case PREMONOMORPHIC:
+      return isolate->builtins()->KeyedLoadIC_PreMonomorphic();
+    case MEGAMORPHIC:
+      return isolate->builtins()->KeyedLoadIC_Megamorphic();
+    default:
+      UNREACHABLE();
+  }
+  return Handle<Code>();
+}
+
+
+Handle<Code> KeyedStoreIC::initialize_stub(Isolate* isolate,
+                                           LanguageMode language_mode,
+                                           State initialization_state) {
+  switch (initialization_state) {
+    case UNINITIALIZED:
+      return is_strict(language_mode)
+                 ? isolate->builtins()->KeyedStoreIC_Initialize_Strict()
+                 : isolate->builtins()->KeyedStoreIC_Initialize();
+    case PREMONOMORPHIC:
+      return is_strict(language_mode)
+                 ? isolate->builtins()->KeyedStoreIC_PreMonomorphic_Strict()
+                 : isolate->builtins()->KeyedStoreIC_PreMonomorphic();
+    case MEGAMORPHIC:
+      return is_strict(language_mode)
+                 ? isolate->builtins()->KeyedStoreIC_Megamorphic_Strict()
+                 : isolate->builtins()->KeyedStoreIC_Megamorphic();
+    default:
+      UNREACHABLE();
   }
-  return initialize_stub(isolate);
+  return Handle<Code>();
 }
 
 
@@ -1239,6 +1316,8 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
                                           lookup->GetConstantIndex());
     }
 
+    case LookupIterator::INTEGER_INDEXED_EXOTIC:
+      return slow_stub();
     case LookupIterator::ACCESS_CHECK:
     case LookupIterator::JSPROXY:
     case LookupIterator::NOT_FOUND:
@@ -1429,6 +1508,8 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
         break;
       case LookupIterator::ACCESSOR:
         return !it->IsReadOnly();
+      case LookupIterator::INTEGER_INDEXED_EXOTIC:
+        return false;
       case LookupIterator::DATA: {
         if (it->IsReadOnly()) return false;
         Handle<JSObject> holder = it->GetHolder<JSObject>();
@@ -1453,7 +1534,6 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
     }
   }
 
-  if (it->IsSpecialNumericIndex()) return false;
   it->PrepareTransitionToDataProperty(value, NONE, store_mode);
   return it->IsCacheableTransition();
 }
@@ -1462,7 +1542,7 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
 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()) {
+  if (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);
@@ -1474,7 +1554,16 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
       Handle<Context> script_context = ScriptContextTable::GetContext(
           script_contexts, lookup_result.context_index);
       if (lookup_result.mode == CONST) {
-        return TypeError("harmony_const_assign", object, name);
+        return TypeError("const_assign", object, name);
+      }
+
+      Handle<Object> previous_value =
+          FixedArray::get(script_context, lookup_result.slot_index);
+
+      if (*previous_value == *isolate()->factory()->the_hole_value()) {
+        // Do not install stubs and stay pre-monomorphic for
+        // uninitialized accesses.
+        return ReferenceError("not_defined", name);
       }
 
       if (FLAG_use_ic &&
@@ -1560,10 +1649,14 @@ Handle<Code> CallIC::initialize_stub_in_optimized_code(
 
 
 Handle<Code> StoreIC::initialize_stub(Isolate* isolate,
-                                      LanguageMode language_mode) {
+                                      LanguageMode language_mode,
+                                      State initialization_state) {
+  DCHECK(initialization_state == UNINITIALIZED ||
+         initialization_state == PREMONOMORPHIC ||
+         initialization_state == MEGAMORPHIC);
   ExtraICState extra_state = ComputeExtraICState(language_mode);
-  Handle<Code> ic =
-      PropertyICCompiler::ComputeStore(isolate, UNINITIALIZED, extra_state);
+  Handle<Code> ic = PropertyICCompiler::ComputeStore(
+      isolate, initialization_state, extra_state);
   return ic;
 }
 
@@ -1623,9 +1716,8 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
 
 static Handle<Code> PropertyCellStoreHandler(
     Isolate* isolate, Handle<JSObject> receiver, Handle<GlobalObject> holder,
-    Handle<Name> name, Handle<PropertyCell> cell, Handle<Object> value) {
-  auto union_type = PropertyCell::UpdatedType(cell, value);
-  StoreGlobalStub stub(isolate, union_type->IsConstant(),
+    Handle<Name> name, Handle<PropertyCell> cell, PropertyCellType type) {
+  StoreGlobalStub stub(isolate, type == PropertyCellType::kConstant,
                        receiver->IsJSGlobalProxy());
   auto code = stub.GetCodeCopyFromTemplate(holder, cell);
   // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
@@ -1648,10 +1740,14 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
     case LookupIterator::TRANSITION: {
       auto store_target = lookup->GetStoreTarget();
       if (store_target->IsGlobalObject()) {
-        auto cell = lookup->GetTransitionPropertyCell();
-        return PropertyCellStoreHandler(
+        // TODO(dcarney): this currently just deopts. Use the transition cell.
+        auto cell = isolate()->factory()->NewPropertyCell();
+        cell->set_value(*value);
+        auto code = PropertyCellStoreHandler(
             isolate(), store_target, Handle<GlobalObject>::cast(store_target),
-            lookup->name(), cell, value);
+            lookup->name(), cell, PropertyCellType::kConstant);
+        cell->set_value(isolate()->heap()->the_hole_value());
+        return code;
       }
       Handle<Map> transition = lookup->transition_map();
       // Currently not handled by CompileStoreTransition.
@@ -1722,9 +1818,11 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
           DCHECK(holder.is_identical_to(receiver) ||
                  receiver->map()->prototype() == *holder);
           auto cell = lookup->GetPropertyCell();
+          auto union_type = PropertyCell::UpdatedType(
+              cell, value, lookup->property_details());
           return PropertyCellStoreHandler(isolate(), receiver,
                                           Handle<GlobalObject>::cast(holder),
-                                          lookup->name(), cell, value);
+                                          lookup->name(), cell, union_type);
         }
         DCHECK(holder.is_identical_to(receiver));
         return isolate()->builtins()->StoreIC_Normal();
@@ -1754,6 +1852,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
       break;
     }
 
+    case LookupIterator::INTEGER_INDEXED_EXOTIC:
     case LookupIterator::ACCESS_CHECK:
     case LookupIterator::JSPROXY:
     case LookupIterator::NOT_FOUND:
@@ -2100,7 +2199,9 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
     TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "slow stub");
   }
   DCHECK(!stub.is_null());
-  set_target(*stub);
+  if (!AddressIsDeoptimizedCode()) {
+    set_target(*stub);
+  }
   TRACE_IC("StoreIC", key);
 
   return store_handle;
@@ -2477,9 +2578,17 @@ MaybeHandle<Object> BinaryOpIC::Transition(
       isolate(), result, Execution::Call(isolate(), function, left, 1, &right),
       Object);
 
+  // Do not try to update the target if the code was marked for lazy
+  // deoptimization. (Since we do not relocate addresses in these
+  // code objects, an attempt to access the target could fail.)
+  if (AddressIsDeoptimizedCode()) {
+    return result;
+  }
+
   // Execution::Call can execute arbitrary JavaScript, hence potentially
   // update the state of this very IC, so we must update the stored state.
   UpdateTarget();
+
   // Compute the new state.
   BinaryOpICState old_state(isolate(), target()->extra_ic_state());
   state.Update(left, right, result);
@@ -2805,30 +2914,10 @@ RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly) {
   Handle<JSObject> holder =
       args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
   HandleScope scope(isolate);
-  Handle<InterceptorInfo> interceptor_info(holder->GetNamedInterceptor());
-
-  if (name->IsSymbol() && !interceptor_info->can_intercept_symbols())
-    return isolate->heap()->no_interceptor_result_sentinel();
-
-  Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
-  v8::GenericNamedPropertyGetterCallback getter =
-      FUNCTION_CAST<v8::GenericNamedPropertyGetterCallback>(getter_address);
-  DCHECK(getter != NULL);
-
-  PropertyCallbackArguments callback_args(isolate, interceptor_info->data(),
-                                          *receiver, *holder);
-  {
-    // Use the interceptor getter.
-    v8::Handle<v8::Value> r =
-        callback_args.Call(getter, v8::Utils::ToLocal(name));
-    RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
-    if (!r.IsEmpty()) {
-      Handle<Object> result = v8::Utils::OpenHandle(*r);
-      result->VerifyApiCallResultType();
-      return *v8::Utils::OpenHandle(*r);
-    }
-  }
-
+  auto res = JSObject::GetPropertyWithInterceptor(holder, receiver, name);
+  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
+  Handle<Object> result;
+  if (res.ToHandle(&result)) return *result;
   return isolate->heap()->no_interceptor_result_sentinel();
 }
 
index 8c1c82e..4da6e7c 100644 (file)
@@ -104,12 +104,12 @@ class IC {
 
   static bool IsCleared(Code* code) {
     InlineCacheState state = code->ic_state();
-    return state == UNINITIALIZED || state == PREMONOMORPHIC;
+    return !FLAG_use_ic || state == UNINITIALIZED || state == PREMONOMORPHIC;
   }
 
   static bool IsCleared(FeedbackNexus* nexus) {
     InlineCacheState state = nexus->StateFromFeedback();
-    return state == UNINITIALIZED || state == PREMONOMORPHIC;
+    return !FLAG_use_ic || state == UNINITIALIZED || state == PREMONOMORPHIC;
   }
 
   static bool ICUseVector(Code::Kind kind) {
@@ -134,6 +134,7 @@ class IC {
   Code* GetOriginalCode() const;
 
   bool AddressIsOptimizedCode() const;
+  bool AddressIsDeoptimizedCode() const;
 
   // Set the call-site target.
   inline void set_target(Code* code);
@@ -396,7 +397,9 @@ class LoadIC : public IC {
   static Handle<Code> initialize_stub(Isolate* isolate,
                                       ExtraICState extra_state);
   static Handle<Code> initialize_stub_in_optimized_code(
-      Isolate* isolate, ExtraICState extra_state);
+      Isolate* isolate, ExtraICState extra_state, State initialization_state);
+  static Handle<Code> load_global(Isolate* isolate, Handle<GlobalObject> global,
+                                  Handle<String> name);
 
   MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
                                            Handle<Name> name);
@@ -481,7 +484,8 @@ class KeyedLoadIC : public LoadIC {
       (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> initialize_stub_in_optimized_code(
+      Isolate* isolate, State initialization_state);
   static Handle<Code> ChooseMegamorphicStub(Isolate* isolate);
   static Handle<Code> pre_monomorphic_stub(Isolate* isolate);
 
@@ -539,7 +543,8 @@ class StoreIC : public IC {
                                          LanguageMode language_mode);
 
   static Handle<Code> initialize_stub(Isolate* isolate,
-                                      LanguageMode language_mode);
+                                      LanguageMode language_mode,
+                                      State initialization_state);
 
   MUST_USE_RESULT MaybeHandle<Object> Store(
       Handle<Object> object, Handle<Name> name, Handle<Object> value,
@@ -631,6 +636,10 @@ class KeyedStoreIC : public StoreIC {
                                   LanguageMode language_mode);
   static void GenerateSloppyArguments(MacroAssembler* masm);
 
+  static Handle<Code> initialize_stub(Isolate* isolate,
+                                      LanguageMode language_mode,
+                                      State initialization_state);
+
  protected:
   virtual Handle<Code> pre_monomorphic_stub() const {
     return pre_monomorphic_stub(isolate(), language_mode());
index 93106ea..83f57bc 100644 (file)
@@ -193,11 +193,11 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
     Register scratch, Label* miss) {
-  Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
+  Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
   DCHECK(cell->value()->IsTheHole());
   Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
   __ LoadWeakValue(scratch, weak_cell, miss);
-  __ lw(scratch, FieldMemOperand(scratch, Cell::kValueOffset));
+  __ lw(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
   __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
   __ Branch(miss, ne, scratch, Operand(at));
 }
@@ -418,6 +418,17 @@ Register PropertyHandlerCompiler::CheckPrototypes(
   if (receiver_map->IsJSGlobalObjectMap()) {
     current = isolate()->global_object();
   }
+
+  // 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 (receiver_map->IsJSGlobalProxyMap()) {
+    __ CheckAccessGlobalProxy(reg, scratch2, miss);
+  }
+
   Handle<JSObject> prototype = Handle<JSObject>::null();
   Handle<Map> current_map = receiver_map;
   Handle<Map> holder_map(holder()->map());
@@ -452,23 +463,14 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     } else {
       Register map_reg = scratch1;
       __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
-      if (depth != 1 || check == CHECK_ALL_MAPS) {
-        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
-      // 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()) {
+      if (current_map->IsJSGlobalObjectMap()) {
         GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
                                   name, scratch2, miss);
+      } else if (depth != 1 || check == CHECK_ALL_MAPS) {
+        Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+        __ GetWeakValue(scratch2, cell);
+        __ Branch(miss, ne, scratch2, Operand(map_reg));
       }
 
       reg = holder_reg;  // From now on the object will be in holder_reg.
@@ -481,6 +483,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     current_map = handle(current->map());
   }
 
+  DCHECK(!current_map->IsJSGlobalProxyMap());
+
   // Log the check depth.
   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
 
@@ -492,13 +496,6 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     __ Branch(miss, ne, scratch2, Operand(scratch1));
   }
 
-  // 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;
 }
@@ -721,7 +718,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
   Register result = StoreDescriptor::ValueRegister();
   Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
   __ LoadWeakValue(result, weak_cell, &miss);
-  __ lw(result, FieldMemOperand(result, Cell::kValueOffset));
+  __ lw(result, FieldMemOperand(result, PropertyCell::kValueOffset));
 
   // Check for deleted property if property can actually be deleted.
   if (is_configurable) {
index a68a418..90eecaa 100644 (file)
@@ -194,11 +194,11 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
     Register scratch, Label* miss) {
-  Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
+  Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
   DCHECK(cell->value()->IsTheHole());
   Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
   __ LoadWeakValue(scratch, weak_cell, miss);
-  __ ld(scratch, FieldMemOperand(scratch, Cell::kValueOffset));
+  __ ld(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
   __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
   __ Branch(miss, ne, scratch, Operand(at));
 }
@@ -419,6 +419,17 @@ Register PropertyHandlerCompiler::CheckPrototypes(
   if (receiver_map->IsJSGlobalObjectMap()) {
     current = isolate()->global_object();
   }
+
+  // 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 (receiver_map->IsJSGlobalProxyMap()) {
+    __ CheckAccessGlobalProxy(reg, scratch2, miss);
+  }
+
   Handle<JSObject> prototype = Handle<JSObject>::null();
   Handle<Map> current_map = receiver_map;
   Handle<Map> holder_map(holder()->map());
@@ -453,23 +464,14 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     } else {
       Register map_reg = scratch1;
       __ ld(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
-      if (depth != 1 || check == CHECK_ALL_MAPS) {
-        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
-      // 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()) {
+      if (current_map->IsJSGlobalObjectMap()) {
         GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
                                   name, scratch2, miss);
+      } else if (depth != 1 || check == CHECK_ALL_MAPS) {
+        Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+        __ GetWeakValue(scratch2, cell);
+        __ Branch(miss, ne, scratch2, Operand(map_reg));
       }
 
       reg = holder_reg;  // From now on the object will be in holder_reg.
@@ -482,6 +484,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     current_map = handle(current->map());
   }
 
+  DCHECK(!current_map->IsJSGlobalProxyMap());
+
   // Log the check depth.
   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
 
@@ -493,13 +497,6 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     __ Branch(miss, ne, scratch2, Operand(scratch1));
   }
 
-  // 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;
 }
@@ -722,7 +719,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
   Register result = StoreDescriptor::ValueRegister();
   Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
   __ LoadWeakValue(result, weak_cell, &miss);
-  __ ld(result, FieldMemOperand(result, Cell::kValueOffset));
+  __ ld(result, FieldMemOperand(result, PropertyCell::kValueOffset));
 
   // Check for deleted property if property can actually be deleted.
   if (is_configurable) {
index 7b22b8c..1ec49c4 100644 (file)
@@ -668,7 +668,7 @@ static void KeyedStoreGenerateMegamorphicHelper(
   __ daddu(address, address, at);
   __ lw(scratch_value, MemOperand(address));
   __ Branch(&fast_double_without_map_check, ne, scratch_value,
-            Operand(kHoleNanUpper32));
+            Operand(static_cast<int32_t>(kHoleNanUpper32)));
   __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
                                       slow);
 
@@ -676,7 +676,7 @@ static void KeyedStoreGenerateMegamorphicHelper(
   __ StoreNumberToDoubleElements(value, key,
                                  elements,  // Overwritten.
                                  a3,        // Scratch regs...
-                                 a4, a5, &transition_double_elements);
+                                 a4, &transition_double_elements);
   if (increment_length == kIncrementLength) {
     // Add 1 to receiver->length.
     __ Daddu(scratch_value, key, Operand(Smi::FromInt(1)));
diff --git a/deps/v8/src/ic/ppc/OWNERS b/deps/v8/src/ic/ppc/OWNERS
new file mode 100644 (file)
index 0000000..beecb3d
--- /dev/null
@@ -0,0 +1,3 @@
+joransiu@ca.ibm.com
+mbrandy@us.ibm.com
+michael_dawson@ca.ibm.com
index 4283d39..d7a70d7 100644 (file)
@@ -17,22 +17,21 @@ namespace internal {
 
 
 void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
-    MacroAssembler* masm, Handle<HeapType> type, Register receiver,
-    Register holder, int accessor_index, int expected_arguments,
-    Register scratch) {
+    MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
+    int accessor_index, int expected_arguments, Register scratch) {
   // ----------- S t a t e -------------
   //  -- r3    : receiver
   //  -- r5    : name
   //  -- lr    : return address
   // -----------------------------------
   {
-    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    FrameScope scope(masm, StackFrame::INTERNAL);
 
     if (accessor_index >= 0) {
       DCHECK(!holder.is(scratch));
       DCHECK(!receiver.is(scratch));
       // Call the JavaScript getter with the receiver on the stack.
-      if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
+      if (map->IsJSGlobalObjectMap()) {
         // Swap in the global receiver.
         __ LoadP(scratch,
                  FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
@@ -57,14 +56,13 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
 
 
 void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
-    MacroAssembler* masm, Handle<HeapType> type, Register receiver,
-    Register holder, int accessor_index, int expected_arguments,
-    Register scratch) {
+    MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
+    int accessor_index, int expected_arguments, Register scratch) {
   // ----------- S t a t e -------------
   //  -- lr    : return address
   // -----------------------------------
   {
-    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    FrameScope scope(masm, StackFrame::INTERNAL);
 
     // Save value register, so we can restore it later.
     __ push(value());
@@ -74,7 +72,7 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
       DCHECK(!receiver.is(scratch));
       DCHECK(!value().is(scratch));
       // Call the JavaScript setter with receiver and value on the stack.
-      if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
+      if (map->IsJSGlobalObjectMap()) {
         // Swap in the global receiver.
         __ LoadP(scratch,
                  FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
@@ -197,11 +195,11 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
     Register scratch, Label* miss) {
-  Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
+  Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
   DCHECK(cell->value()->IsTheHole());
   Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
   __ LoadWeakValue(scratch, weak_cell, miss);
-  __ LoadP(scratch, FieldMemOperand(scratch, Cell::kValueOffset));
+  __ LoadP(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
   __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
   __ cmp(scratch, ip);
   __ bne(miss);
@@ -414,7 +412,7 @@ 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()));
+  Handle<Map> receiver_map = map();
 
   // Make sure there's no overlap between holder and object registers.
   DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
@@ -426,9 +424,19 @@ Register PropertyHandlerCompiler::CheckPrototypes(
   int depth = 0;
 
   Handle<JSObject> current = Handle<JSObject>::null();
-  if (type()->IsConstant()) {
-    current = Handle<JSObject>::cast(type()->AsConstant()->Value());
+  if (receiver_map->IsJSGlobalObjectMap()) {
+    current = isolate()->global_object();
   }
+  // 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 (receiver_map->IsJSGlobalProxyMap()) {
+    __ CheckAccessGlobalProxy(reg, scratch2, miss);
+  }
+
   Handle<JSObject> prototype = Handle<JSObject>::null();
   Handle<Map> current_map = receiver_map;
   Handle<Map> holder_map(holder()->map());
@@ -463,23 +471,14 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     } else {
       Register map_reg = scratch1;
       __ LoadP(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
-      if (depth != 1 || check == CHECK_ALL_MAPS) {
-        Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
-        __ CmpWeakValue(map_reg, cell, scratch2);
-        __ bne(miss);
-      }
 
-      // 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()) {
+      if (current_map->IsJSGlobalObjectMap()) {
         GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
                                   name, scratch2, miss);
+      } else if (depth != 1 || check == CHECK_ALL_MAPS) {
+        Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+        __ CmpWeakValue(map_reg, cell, scratch2);
+        __ bne(miss);
       }
 
       reg = holder_reg;  // From now on the object will be in holder_reg.
@@ -503,13 +502,6 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     __ bne(miss);
   }
 
-  // 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;
 }
@@ -619,7 +611,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
   // Save necessary data before invoking an interceptor.
   // Requires a frame to make GC aware of pushed pointers.
   {
-    FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
+    FrameScope frame_scope(masm(), StackFrame::INTERNAL);
     if (must_preserve_receiver_reg) {
       __ Push(receiver(), holder_reg, this->name());
     } else {
@@ -671,11 +663,20 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
 
 
 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
-    Handle<JSObject> object, Handle<Name> name, int accessor_index) {
+    Handle<JSObject> object, Handle<Name> name,
+    Handle<ExecutableAccessorInfo> callback) {
   Register holder_reg = Frontend(name);
 
   __ Push(receiver(), holder_reg);  // receiver
-  __ LoadSmiLiteral(ip, Smi::FromInt(accessor_index));
+
+  // If the callback cannot leak, then push the callback directly,
+  // otherwise wrap it in a weak cell.
+  if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
+    __ mov(ip, Operand(callback));
+  } else {
+    Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
+    __ mov(ip, Operand(cell));
+  }
   __ push(ip);
   __ mov(ip, Operand(name));
   __ Push(ip, value());
@@ -721,7 +722,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
   Register result = StoreDescriptor::ValueRegister();
   Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
   __ LoadWeakValue(result, weak_cell, &miss);
-  __ LoadP(result, FieldMemOperand(result, Cell::kValueOffset));
+  __ LoadP(result, FieldMemOperand(result, PropertyCell::kValueOffset));
 
   // Check for deleted property if property can actually be deleted.
   if (is_configurable) {
index 820ab92..9f33a59 100644 (file)
@@ -30,7 +30,7 @@ void PropertyICCompiler::GenerateRuntimeSetProperty(
 #define __ ACCESS_MASM(masm())
 
 
-Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
+Handle<Code> PropertyICCompiler::CompilePolymorphic(MapHandleList* maps,
                                                     CodeHandleList* handlers,
                                                     Handle<Name> name,
                                                     Code::StubType type,
@@ -57,7 +57,7 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
   }
 
   Label number_case;
-  Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
+  Label* smi_target = IncludesNumberMap(maps) ? &number_case : &miss;
   __ JumpIfSmi(receiver(), smi_target);
 
   // Polymorphic keyed stores may use the map register
@@ -65,21 +65,23 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
   DCHECK(kind() != Code::KEYED_STORE_IC ||
          map_reg.is(ElementTransitionAndStoreDescriptor::MapRegister()));
 
-  int receiver_count = types->length();
+  int receiver_count = maps->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());
+    Handle<Map> map = maps->at(current);
     if (!map->is_deprecated()) {
       number_of_handled_maps++;
       Handle<WeakCell> cell = Map::WeakCellForMap(map);
       __ CmpWeakValue(map_reg, cell, scratch2());
-      if (type->Is(HeapType::Number())) {
+      Label next;
+      __ bne(&next);
+      if (map->instance_type() == HEAP_NUMBER_TYPE) {
         DCHECK(!number_case.is_unused());
         __ bind(&number_case);
       }
-      __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq);
+      __ Jump(handlers->at(current), RelocInfo::CODE_TARGET);
+      __ bind(&next);
     }
   }
   DCHECK(number_of_handled_maps != 0);
index 35a4acf..e3a4938 100644 (file)
@@ -118,7 +118,7 @@ void StubCache::CollectMatchingMaps(SmallMapList* types, Handle<Name> name,
 
       int offset = PrimaryOffset(*name, flags, map);
       if (entry(primary_, offset) == &primary_[i] &&
-          !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
+          TypeFeedbackOracle::IsRelevantFeedback(map, *native_context)) {
         types->AddMapIfMissing(Handle<Map>(map), zone);
       }
     }
@@ -137,7 +137,7 @@ void StubCache::CollectMatchingMaps(SmallMapList* types, Handle<Name> name,
       // Lookup in secondary table and add matches.
       int offset = SecondaryOffset(*name, flags, primary_offset);
       if (entry(secondary_, offset) == &secondary_[i] &&
-          !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
+          TypeFeedbackOracle::IsRelevantFeedback(map, *native_context)) {
         types->AddMapIfMissing(Handle<Map>(map), zone);
       }
     }
index 485d87d..b6add9d 100644 (file)
@@ -209,7 +209,8 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
   Factory* factory = masm->isolate()->factory();
   Handle<WeakCell> weak_cell = factory->NewWeakCell(cell);
   __ LoadWeakValue(scratch, weak_cell, miss);
-  __ Cmp(FieldOperand(scratch, Cell::kValueOffset), factory->the_hole_value());
+  __ Cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
+         factory->the_hole_value());
   __ j(not_equal, miss);
 }
 
@@ -431,6 +432,17 @@ Register PropertyHandlerCompiler::CheckPrototypes(
   if (receiver_map->IsJSGlobalObjectMap()) {
     current = isolate()->global_object();
   }
+
+  // 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 (receiver_map->IsJSGlobalProxyMap()) {
+    __ CheckAccessGlobalProxy(reg, scratch2, miss);
+  }
+
   Handle<JSObject> prototype = Handle<JSObject>::null();
   Handle<Map> current_map = receiver_map;
   Handle<Map> holder_map(holder()->map());
@@ -466,24 +478,15 @@ Register PropertyHandlerCompiler::CheckPrototypes(
       Register map_reg = scratch1;
       __ movp(map_reg, FieldOperand(reg, HeapObject::kMapOffset));
 
-      if (depth != 1 || check == CHECK_ALL_MAPS) {
+      if (current_map->IsJSGlobalObjectMap()) {
+        GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
+                                  name, scratch2, miss);
+      } else if (depth != 1 || check == CHECK_ALL_MAPS) {
         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
-      // 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.
 
       __ movp(reg, FieldOperand(map_reg, Map::kPrototypeOffset));
@@ -494,6 +497,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     current_map = handle(current->map());
   }
 
+  DCHECK(!current_map->IsJSGlobalProxyMap());
+
   // Log the check depth.
   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
 
@@ -504,13 +509,6 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     __ j(not_equal, miss);
   }
 
-  // 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;
 }
index 2eb10c3..ce90275 100644 (file)
@@ -431,6 +431,17 @@ Register PropertyHandlerCompiler::CheckPrototypes(
   if (receiver_map->IsJSGlobalObjectMap()) {
     current = isolate()->global_object();
   }
+
+  // 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 (receiver_map->IsJSGlobalProxyMap()) {
+    __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
+  }
+
   Handle<JSObject> prototype = Handle<JSObject>::null();
   Handle<Map> current_map = receiver_map;
   Handle<Map> holder_map(holder()->map());
@@ -465,26 +476,15 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     } else {
       Register map_reg = scratch1;
       __ mov(map_reg, FieldOperand(reg, HeapObject::kMapOffset));
-      if (depth != 1 || check == CHECK_ALL_MAPS) {
+      if (current_map->IsJSGlobalObjectMap()) {
+        GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
+                                  name, scratch2, miss);
+      } else if (depth != 1 || check == CHECK_ALL_MAPS) {
         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
-      // 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, 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);
-      }
       reg = holder_reg;  // From now on the object will be in holder_reg.
       __ mov(reg, FieldOperand(map_reg, Map::kPrototypeOffset));
     }
@@ -494,6 +494,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     current_map = handle(current->map());
   }
 
+  DCHECK(!current_map->IsJSGlobalProxyMap());
+
   // Log the check depth.
   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
 
@@ -505,13 +507,6 @@ Register PropertyHandlerCompiler::CheckPrototypes(
     __ j(not_equal, miss);
   }
 
-  // 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, scratch2, miss);
-  }
-
   // Return the register containing the holder.
   return reg;
 }
index 51fb920..a100123 100644 (file)
@@ -40,6 +40,7 @@ class PlatformInterfaceDescriptor;
   V(ArrayConstructor)                         \
   V(InternalArrayConstructorConstantArgCount) \
   V(InternalArrayConstructor)                 \
+  V(Compare)                                  \
   V(CompareNil)                               \
   V(ToBoolean)                                \
   V(BinaryOp)                                 \
@@ -406,6 +407,12 @@ class InternalArrayConstructorDescriptor : public CallInterfaceDescriptor {
 };
 
 
+class CompareDescriptor : public CallInterfaceDescriptor {
+ public:
+  DECLARE_DESCRIPTOR(CompareDescriptor, CallInterfaceDescriptor)
+};
+
+
 class CompareNilDescriptor : public CallInterfaceDescriptor {
  public:
   DECLARE_DESCRIPTOR(CompareNilDescriptor, CallInterfaceDescriptor)
index 2c8367d..e9713db 100644 (file)
@@ -34,8 +34,8 @@
 #include "src/runtime-profiler.h"
 #include "src/sampler.h"
 #include "src/scopeinfo.h"
-#include "src/serialize.h"
 #include "src/simulator.h"
+#include "src/snapshot/serialize.h"
 #include "src/version.h"
 #include "src/vm-state-inl.h"
 
@@ -82,16 +82,13 @@ void ThreadLocalTop::InitializeInternal() {
   external_caught_exception_ = false;
   failed_access_check_callback_ = NULL;
   save_context_ = NULL;
-  catcher_ = NULL;
   promise_on_stack_ = NULL;
 
   // These members are re-initialized later after deserialization
   // is complete.
   pending_exception_ = NULL;
-  has_pending_message_ = false;
   rethrowing_message_ = false;
   pending_message_obj_ = NULL;
-  pending_message_script_ = NULL;
   scheduled_exception_ = NULL;
 }
 
@@ -190,7 +187,6 @@ void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
   // Visit the roots from the top for a given thread.
   v->VisitPointer(&thread->pending_exception_);
   v->VisitPointer(&(thread->pending_message_obj_));
-  v->VisitPointer(bit_cast<Object**>(&(thread->pending_message_script_)));
   v->VisitPointer(bit_cast<Object**>(&(thread->context_)));
   v->VisitPointer(&thread->scheduled_exception_);
 
@@ -199,7 +195,6 @@ void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
        block = block->next_) {
     v->VisitPointer(bit_cast<Object**>(&(block->exception_)));
     v->VisitPointer(bit_cast<Object**>(&(block->message_obj_)));
-    v->VisitPointer(bit_cast<Object**>(&(block->message_script_)));
   }
 
   // Iterate over pointers on native execution stack.
@@ -255,7 +250,6 @@ void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) {
 void Isolate::UnregisterTryCatchHandler(v8::TryCatch* that) {
   DCHECK(thread_local_top()->try_catch_handler() == that);
   thread_local_top()->set_try_catch_handler(that->next_);
-  thread_local_top()->catcher_ = NULL;
 }
 
 
@@ -550,7 +544,7 @@ class CaptureStackTraceHelper {
     }
 
     if (!function_key_.is_null()) {
-      Handle<Object> fun_name(fun->shared()->DebugName(), isolate_);
+      Handle<Object> fun_name = JSFunction::GetDebugName(fun);
       JSObject::AddProperty(stack_frame, function_key_, fun_name, NONE);
     }
 
@@ -611,7 +605,7 @@ Handle<JSArray> Isolate::GetDetailedFromSimpleStackTrace(
     Address pc = code->address() + offset->value();
     bool is_constructor =
         recv->IsJSObject() &&
-        Handle<JSObject>::cast(recv)->map()->constructor() == *fun;
+        Handle<JSObject>::cast(recv)->map()->GetConstructor() == *fun;
 
     Handle<JSObject> stack_frame =
         helper.NewStackFrameObject(fun, code, pc, is_constructor);
@@ -724,7 +718,9 @@ void Isolate::SetFailedAccessCheckCallback(
 
 static inline AccessCheckInfo* GetAccessCheckInfo(Isolate* isolate,
                                                   Handle<JSObject> receiver) {
-  JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
+  Object* maybe_constructor = receiver->map()->GetConstructor();
+  if (!maybe_constructor->IsJSFunction()) return NULL;
+  JSFunction* constructor = JSFunction::cast(maybe_constructor);
   if (!constructor->shared()->IsApiFunction()) return NULL;
 
   Object* data_obj =
@@ -735,15 +731,16 @@ static inline AccessCheckInfo* GetAccessCheckInfo(Isolate* isolate,
 }
 
 
-void Isolate::ReportFailedAccessCheck(Handle<JSObject> receiver,
-                                      v8::AccessType type) {
+static void ThrowAccessCheckError(Isolate* isolate) {
+  Handle<String> message =
+      isolate->factory()->InternalizeUtf8String("no access");
+  isolate->ScheduleThrow(*isolate->factory()->NewTypeError(message));
+}
+
+
+void Isolate::ReportFailedAccessCheck(Handle<JSObject> receiver) {
   if (!thread_local_top()->failed_access_check_callback_) {
-    Handle<String> message = factory()->InternalizeUtf8String("no access");
-    Handle<Object> error;
-    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-        this, error, factory()->NewTypeError(message), /* void */);
-    ScheduleThrow(*error);
-    return;
+    return ThrowAccessCheckError(this);
   }
 
   DCHECK(receiver->IsAccessCheckNeeded());
@@ -754,47 +751,17 @@ void Isolate::ReportFailedAccessCheck(Handle<JSObject> receiver,
   Handle<Object> data;
   { DisallowHeapAllocation no_gc;
     AccessCheckInfo* access_check_info = GetAccessCheckInfo(this, receiver);
-    if (!access_check_info) return;
+    if (!access_check_info) {
+      AllowHeapAllocation doesnt_matter_anymore;
+      return ThrowAccessCheckError(this);
+    }
     data = handle(access_check_info->data(), this);
   }
 
   // Leaving JavaScript.
   VMState<EXTERNAL> state(this);
   thread_local_top()->failed_access_check_callback_(
-      v8::Utils::ToLocal(receiver),
-      type,
-      v8::Utils::ToLocal(data));
-}
-
-
-enum MayAccessDecision {
-  YES, NO, UNKNOWN
-};
-
-
-static MayAccessDecision MayAccessPreCheck(Isolate* isolate,
-                                           Handle<JSObject> receiver,
-                                           v8::AccessType type) {
-  DisallowHeapAllocation no_gc;
-  // During bootstrapping, callback functions are not enabled yet.
-  if (isolate->bootstrapper()->IsActive()) return YES;
-
-  if (receiver->IsJSGlobalProxy()) {
-    Object* receiver_context = JSGlobalProxy::cast(*receiver)->native_context();
-    if (!receiver_context->IsContext()) return NO;
-
-    // Get the native context of current top context.
-    // avoid using Isolate::native_context() because it uses Handle.
-    Context* native_context =
-        isolate->context()->global_object()->native_context();
-    if (receiver_context == native_context) return YES;
-
-    if (Context::cast(receiver_context)->security_token() ==
-        native_context->security_token())
-      return YES;
-  }
-
-  return UNKNOWN;
+      v8::Utils::ToLocal(receiver), v8::ACCESS_HAS, v8::Utils::ToLocal(data));
 }
 
 
@@ -810,21 +777,33 @@ bool Isolate::IsInternallyUsedPropertyName(Object* name) {
 }
 
 
-bool Isolate::MayNamedAccess(Handle<JSObject> receiver,
-                             Handle<Object> key,
-                             v8::AccessType type) {
+bool Isolate::MayAccess(Handle<JSObject> receiver) {
   DCHECK(receiver->IsJSGlobalProxy() || receiver->IsAccessCheckNeeded());
 
-  // Skip checks for internally used properties. Note, we do not
-  // require existence of a context in this case.
-  if (IsInternallyUsedPropertyName(key)) return true;
-
   // Check for compatibility between the security tokens in the
   // current lexical context and the accessed object.
   DCHECK(context());
 
-  MayAccessDecision decision = MayAccessPreCheck(this, receiver, type);
-  if (decision != UNKNOWN) return decision == YES;
+  {
+    DisallowHeapAllocation no_gc;
+    // During bootstrapping, callback functions are not enabled yet.
+    if (bootstrapper()->IsActive()) return true;
+
+    if (receiver->IsJSGlobalProxy()) {
+      Object* receiver_context =
+          JSGlobalProxy::cast(*receiver)->native_context();
+      if (!receiver_context->IsContext()) return false;
+
+      // Get the native context of current top context.
+      // avoid using Isolate::native_context() because it uses Handle.
+      Context* native_context = context()->global_object()->native_context();
+      if (receiver_context == native_context) return true;
+
+      if (Context::cast(receiver_context)->security_token() ==
+          native_context->security_token())
+        return true;
+    }
+  }
 
   HandleScope scope(this);
   Handle<Object> data;
@@ -838,47 +817,13 @@ bool Isolate::MayNamedAccess(Handle<JSObject> receiver,
     data = handle(access_check_info->data(), this);
   }
 
-  LOG(this, ApiNamedSecurityCheck(*key));
+  LOG(this, ApiSecurityCheck());
 
   // Leaving JavaScript.
   VMState<EXTERNAL> state(this);
-  return callback(v8::Utils::ToLocal(receiver),
-                  v8::Utils::ToLocal(key),
-                  type,
-                  v8::Utils::ToLocal(data));
-}
-
-
-bool Isolate::MayIndexedAccess(Handle<JSObject> receiver,
-                               uint32_t index,
-                               v8::AccessType type) {
-  DCHECK(receiver->IsJSGlobalProxy() || receiver->IsAccessCheckNeeded());
-  // Check for compatibility between the security tokens in the
-  // current lexical context and the accessed object.
-  DCHECK(context());
-
-  MayAccessDecision decision = MayAccessPreCheck(this, receiver, type);
-  if (decision != UNKNOWN) return decision == YES;
-
-  HandleScope scope(this);
-  Handle<Object> data;
-  v8::IndexedSecurityCallback callback;
-  { DisallowHeapAllocation no_gc;
-    // Get named access check callback
-    AccessCheckInfo* access_check_info = GetAccessCheckInfo(this, receiver);
-    if (!access_check_info) return false;
-    Object* fun_obj = access_check_info->indexed_callback();
-    callback = v8::ToCData<v8::IndexedSecurityCallback>(fun_obj);
-    if (!callback) return false;
-    data = handle(access_check_info->data(), this);
-  }
-
-  LOG(this, ApiIndexedSecurityCheck(index));
-
-  // Leaving JavaScript.
-  VMState<EXTERNAL> state(this);
-  return callback(
-      v8::Utils::ToLocal(receiver), index, type, v8::Utils::ToLocal(data));
+  Handle<Object> key = factory()->undefined_value();
+  return callback(v8::Utils::ToLocal(receiver), v8::Utils::ToLocal(key),
+                  v8::ACCESS_HAS, v8::Utils::ToLocal(data));
 }
 
 
@@ -895,7 +840,7 @@ Object* Isolate::StackOverflow() {
   Handle<JSObject> boilerplate = Handle<JSObject>::cast(
       Object::GetProperty(js_builtins_object(), key).ToHandleChecked());
   Handle<JSObject> exception = factory()->CopyJSObject(boilerplate);
-  DoThrow(*exception, NULL);
+  Throw(*exception, nullptr);
 
   CaptureAndSetSimpleStackTrace(exception, factory()->undefined_value());
   return heap()->exception();
@@ -903,8 +848,7 @@ Object* Isolate::StackOverflow() {
 
 
 Object* Isolate::TerminateExecution() {
-  DoThrow(heap_.termination_exception(), NULL);
-  return heap()->exception();
+  return Throw(heap_.termination_exception(), nullptr);
 }
 
 
@@ -949,19 +893,119 @@ void Isolate::InvokeApiInterruptCallbacks() {
 }
 
 
+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
+}
+
+
 Object* Isolate::Throw(Object* exception, MessageLocation* location) {
-  DoThrow(exception, location);
+  DCHECK(!has_pending_exception());
+
+  HandleScope scope(this);
+  Handle<Object> exception_handle(exception, this);
+
+  // Determine whether a message needs to be created for the given exception
+  // depending on the following criteria:
+  // 1) External v8::TryCatch missing: Always create a message because any
+  //    JavaScript handler for a finally-block might re-throw to top-level.
+  // 2) External v8::TryCatch exists: Only create a message if the handler
+  //    captures messages or is verbose (which reports despite the catch).
+  // 3) ReThrow from v8::TryCatch: The message from a previous throw still
+  //    exists and we preserve it instead of creating a new message.
+  bool requires_message = try_catch_handler() == nullptr ||
+                          try_catch_handler()->is_verbose_ ||
+                          try_catch_handler()->capture_message_;
+  bool rethrowing_message = thread_local_top()->rethrowing_message_;
+
+  thread_local_top()->rethrowing_message_ = false;
+
+  // Notify debugger of exception.
+  if (is_catchable_by_javascript(exception)) {
+    debug()->OnThrow(exception_handle);
+  }
+
+  // Generate the message if required.
+  if (requires_message && !rethrowing_message) {
+    MessageLocation potential_computed_location;
+    if (location == NULL) {
+      // If no location was specified we use a computed one instead.
+      ComputeLocation(&potential_computed_location);
+      location = &potential_computed_location;
+    }
+
+    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 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 (FLAG_abort_on_uncaught_exception &&
+          PredictExceptionCatcher() != CAUGHT_BY_JAVASCRIPT) {
+        FLAG_abort_on_uncaught_exception = false;  // Prevent endless recursion.
+        PrintF(stderr, "%s\n\nFROM\n",
+               MessageHandler::GetLocalizedMessage(this, message_obj).get());
+        PrintCurrentStackTrace(stderr);
+        base::OS::Abort();
+      }
+    }
+  }
+
+  // Set the exception being thrown.
+  set_pending_exception(*exception_handle);
   return heap()->exception();
 }
 
 
 Object* Isolate::ReThrow(Object* exception) {
-  bool can_be_caught_externally = false;
-  bool catchable_by_javascript = is_catchable_by_javascript(exception);
-  ShouldReportException(&can_be_caught_externally, catchable_by_javascript);
-
-  thread_local_top()->catcher_ = can_be_caught_externally ?
-      try_catch_handler() : NULL;
+  DCHECK(!has_pending_exception());
 
   // Set the exception being re-thrown.
   set_pending_exception(exception);
@@ -969,9 +1013,138 @@ Object* Isolate::ReThrow(Object* exception) {
 }
 
 
+Object* Isolate::FindHandler() {
+  Object* exception = pending_exception();
+
+  Code* code = nullptr;
+  Context* context = nullptr;
+  intptr_t offset = 0;
+  Address handler_sp = nullptr;
+  Address handler_fp = nullptr;
+
+  // Special handling of termination exceptions, uncatchable by JavaScript code,
+  // we unwind the handlers until the top ENTRY handler is found.
+  bool catchable_by_js = is_catchable_by_javascript(exception);
+
+  // Compute handler and stack unwinding information by performing a full walk
+  // over the stack and dispatching according to the frame type.
+  for (StackFrameIterator iter(this); !iter.done(); iter.Advance()) {
+    StackFrame* frame = iter.frame();
+
+    // For JSEntryStub frames we always have a handler.
+    if (frame->is_entry() || frame->is_entry_construct()) {
+      StackHandler* handler = frame->top_handler();
+
+      // Restore the next handler.
+      thread_local_top()->handler_ = handler->next()->address();
+
+      // Gather information from the handler.
+      code = frame->LookupCode();
+      handler_sp = handler->address() + StackHandlerConstants::kSize;
+      offset = Smi::cast(code->handler_table()->get(0))->value();
+      break;
+    }
+
+    // For optimized frames we perform a lookup in the handler table.
+    if (frame->is_optimized() && catchable_by_js) {
+      OptimizedFrame* js_frame = static_cast<OptimizedFrame*>(frame);
+      int stack_slots = 0;  // Will contain stack slot count of frame.
+      offset = js_frame->LookupExceptionHandlerInTable(&stack_slots);
+      if (offset < 0) continue;
+
+      // Compute the stack pointer from the frame pointer. This ensures that
+      // argument slots on the stack are dropped as returning would.
+      Address return_sp = frame->fp() -
+                          StandardFrameConstants::kFixedFrameSizeFromFp -
+                          stack_slots * kPointerSize;
+
+      // Gather information from the frame.
+      code = frame->LookupCode();
+      handler_sp = return_sp;
+      handler_fp = frame->fp();
+      break;
+    }
+
+    // For JavaScript frames we perform a range lookup in the handler table.
+    if (frame->is_java_script() && catchable_by_js) {
+      JavaScriptFrame* js_frame = static_cast<JavaScriptFrame*>(frame);
+      int stack_slots = 0;  // Will contain operand stack depth of handler.
+      offset = js_frame->LookupExceptionHandlerInTable(&stack_slots);
+      if (offset < 0) continue;
+
+      // Compute the stack pointer from the frame pointer. This ensures that
+      // operand stack slots are dropped for nested statements. Also restore
+      // correct context for the handler which is pushed within the try-block.
+      Address return_sp = frame->fp() -
+                          StandardFrameConstants::kFixedFrameSizeFromFp -
+                          stack_slots * kPointerSize;
+      STATIC_ASSERT(TryBlockConstant::kElementCount == 1);
+      context = Context::cast(Memory::Object_at(return_sp - kPointerSize));
+
+      // Gather information from the frame.
+      code = frame->LookupCode();
+      handler_sp = return_sp;
+      handler_fp = frame->fp();
+      break;
+    }
+  }
+
+  // Handler must exist.
+  CHECK(code != nullptr);
+
+  // Store information to be consumed by the CEntryStub.
+  thread_local_top()->pending_handler_context_ = context;
+  thread_local_top()->pending_handler_code_ = code;
+  thread_local_top()->pending_handler_offset_ = offset;
+  thread_local_top()->pending_handler_fp_ = handler_fp;
+  thread_local_top()->pending_handler_sp_ = handler_sp;
+
+  // Return and clear pending exception.
+  clear_pending_exception();
+  return exception;
+}
+
+
+Isolate::CatchType Isolate::PredictExceptionCatcher() {
+  Address external_handler = thread_local_top()->try_catch_handler_address();
+  Address entry_handler = Isolate::handler(thread_local_top());
+  if (IsExternalHandlerOnTop(nullptr)) return CAUGHT_BY_EXTERNAL;
+
+  // Search for an exception handler by performing a full walk over the stack.
+  for (StackFrameIterator iter(this); !iter.done(); iter.Advance()) {
+    StackFrame* frame = iter.frame();
+
+    // For JSEntryStub frames we update the JS_ENTRY handler.
+    if (frame->is_entry() || frame->is_entry_construct()) {
+      entry_handler = frame->top_handler()->next()->address();
+    }
+
+    // For JavaScript frames we perform a lookup in the handler table.
+    if (frame->is_java_script()) {
+      JavaScriptFrame* js_frame = static_cast<JavaScriptFrame*>(frame);
+      int stack_slots = 0;  // The computed stack slot count is not used.
+      if (js_frame->LookupExceptionHandlerInTable(&stack_slots) > 0) {
+        return CAUGHT_BY_JAVASCRIPT;
+      }
+    }
+
+    // The exception has been externally caught if and only if there is an
+    // external handler which is on top of the top-most JS_ENTRY handler.
+    if (external_handler != nullptr && !try_catch_handler()->is_verbose_) {
+      if (entry_handler == nullptr || entry_handler > external_handler) {
+        return CAUGHT_BY_EXTERNAL;
+      }
+    }
+  }
+
+  // Handler not found.
+  return NOT_CAUGHT;
+}
+
+
 Object* Isolate::ThrowIllegalOperation() {
   if (FLAG_stack_trace_on_illegal) PrintStack(stdout);
-  return Throw(heap_.illegal_access_string());
+  return Throw(heap()->illegal_access_string());
 }
 
 
@@ -994,13 +1167,8 @@ void Isolate::RestorePendingMessageFromTryCatch(v8::TryCatch* handler) {
   DCHECK(handler->rethrow_);
   DCHECK(handler->capture_message_);
   Object* message = reinterpret_cast<Object*>(handler->message_obj_);
-  Object* script = reinterpret_cast<Object*>(handler->message_script_);
   DCHECK(message->IsJSMessageObject() || message->IsTheHole());
-  DCHECK(script->IsScript() || script->IsTheHole());
   thread_local_top()->pending_message_obj_ = message;
-  thread_local_top()->pending_message_script_ = script;
-  thread_local_top()->pending_message_start_pos_ = handler->message_start_pos_;
-  thread_local_top()->pending_message_end_pos_ = handler->message_end_pos_;
 }
 
 
@@ -1127,37 +1295,6 @@ bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target,
 }
 
 
-bool Isolate::ShouldReportException(bool* can_be_caught_externally,
-                                    bool catchable_by_javascript) {
-  // Find the top-most try-catch handler.
-  StackHandler* handler =
-      StackHandler::FromAddress(Isolate::handler(thread_local_top()));
-  while (handler != NULL && !handler->is_catch()) {
-    handler = handler->next();
-  }
-
-  // Get the address of the external handler so we can compare the address to
-  // determine which one is closer to the top of the stack.
-  Address external_handler_address =
-      thread_local_top()->try_catch_handler_address();
-
-  // The exception has been externally caught if and only if there is
-  // an external handler which is on top of the top-most try-catch
-  // handler.
-  *can_be_caught_externally = external_handler_address != NULL &&
-      (handler == NULL || handler->address() > external_handler_address ||
-       !catchable_by_javascript);
-
-  if (*can_be_caught_externally) {
-    // Only report the exception if the external handler is verbose.
-    return try_catch_handler()->is_verbose_;
-  } else {
-    // Report the exception if it isn't caught by JavaScript code.
-    return handler == NULL;
-  }
-}
-
-
 // Traverse prototype chain to find out whether the object is derived from
 // the Error object.
 bool Isolate::IsErrorObject(Handle<Object> obj) {
@@ -1172,7 +1309,7 @@ bool Isolate::IsErrorObject(Handle<Object> obj) {
   for (PrototypeIterator iter(this, *obj, PrototypeIterator::START_AT_RECEIVER);
        !iter.IsAtEnd(); iter.Advance()) {
     if (iter.GetCurrent()->IsJSProxy()) return false;
-    if (JSObject::cast(iter.GetCurrent())->map()->constructor() ==
+    if (JSObject::cast(iter.GetCurrent())->map()->GetConstructor() ==
         *error_constructor) {
       return true;
     }
@@ -1180,8 +1317,6 @@ bool Isolate::IsErrorObject(Handle<Object> obj) {
   return false;
 }
 
-static int fatal_exception_depth = 0;
-
 
 Handle<JSMessageObject> Isolate::CreateMessage(Handle<Object> exception,
                                                MessageLocation* location) {
@@ -1231,190 +1366,96 @@ Handle<JSMessageObject> Isolate::CreateMessage(Handle<Object> exception,
 }
 
 
-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
-}
+bool Isolate::IsJavaScriptHandlerOnTop(Object* exception) {
+  DCHECK_NE(heap()->the_hole_value(), exception);
 
+  // For uncatchable exceptions, the JavaScript handler cannot be on top.
+  if (!is_catchable_by_javascript(exception)) return false;
 
-void Isolate::DoThrow(Object* exception, MessageLocation* location) {
-  DCHECK(!has_pending_exception());
+  // Get the top-most JS_ENTRY handler, cannot be on top if it doesn't exist.
+  Address entry_handler = Isolate::handler(thread_local_top());
+  if (entry_handler == nullptr) return false;
 
-  HandleScope scope(this);
-  Handle<Object> exception_handle(exception, this);
-
-  // Determine reporting and whether the exception is caught externally.
-  bool catchable_by_javascript = is_catchable_by_javascript(exception);
-  bool can_be_caught_externally = false;
-  bool should_report_exception =
-      ShouldReportException(&can_be_caught_externally, catchable_by_javascript);
-  bool report_exception = catchable_by_javascript && should_report_exception;
-  bool try_catch_needs_message =
-      can_be_caught_externally && try_catch_handler()->capture_message_;
-  bool rethrowing_message = thread_local_top()->rethrowing_message_;
-
-  thread_local_top()->rethrowing_message_ = false;
-
-  // Notify debugger of exception.
-  if (catchable_by_javascript) {
-    debug()->OnThrow(exception_handle, report_exception);
-  }
+  // Get the address of the external handler so we can compare the address to
+  // determine which one is closer to the top of the stack.
+  Address external_handler = thread_local_top()->try_catch_handler_address();
+  if (external_handler == nullptr) return true;
 
-  // Generate the message if required.
-  if (!rethrowing_message && (report_exception || try_catch_needs_message)) {
-    MessageLocation potential_computed_location;
-    if (location == NULL) {
-      // If no location was specified we use a computed one instead.
-      ComputeLocation(&potential_computed_location);
-      location = &potential_computed_location;
-    }
+  // The exception has been externally caught if and only if there is an
+  // external handler which is on top of the top-most JS_ENTRY handler.
+  //
+  // Note, that finally clauses would re-throw an exception unless it's aborted
+  // by jumps in control flow (like return, break, etc.) and we'll have another
+  // chance to set proper v8::TryCatch later.
+  return (entry_handler < external_handler);
+}
 
-    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;
-      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();
+bool Isolate::IsExternalHandlerOnTop(Object* exception) {
+  DCHECK_NE(heap()->the_hole_value(), exception);
 
-      // 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 &&
-          (report_exception || can_be_caught_externally)) {
-        fatal_exception_depth++;
-        PrintF(stderr, "%s\n\nFROM\n",
-               MessageHandler::GetLocalizedMessage(this, message_obj).get());
-        PrintCurrentStackTrace(stderr);
-        base::OS::Abort();
-      }
-    }
-  }
+  // Get the address of the external handler so we can compare the address to
+  // determine which one is closer to the top of the stack.
+  Address external_handler = thread_local_top()->try_catch_handler_address();
+  if (external_handler == nullptr) return false;
 
-  // Save the message for reporting if the the exception remains uncaught.
-  thread_local_top()->has_pending_message_ = report_exception;
+  // For uncatchable exceptions, the external handler is always on top.
+  if (!is_catchable_by_javascript(exception)) return true;
 
-  // Do not forget to clean catcher_ if currently thrown exception cannot
-  // be caught.  If necessary, ReThrow will update the catcher.
-  thread_local_top()->catcher_ = can_be_caught_externally ?
-      try_catch_handler() : NULL;
+  // Get the top-most JS_ENTRY handler, cannot be on top if it doesn't exist.
+  Address entry_handler = Isolate::handler(thread_local_top());
+  if (entry_handler == nullptr) return true;
 
-  set_pending_exception(*exception_handle);
+  // The exception has been externally caught if and only if there is an
+  // external handler which is on top of the top-most JS_ENTRY handler.
+  //
+  // Note, that finally clauses would re-throw an exception unless it's aborted
+  // by jumps in control flow (like return, break, etc.) and we'll have another
+  // chance to set proper v8::TryCatch later.
+  return (entry_handler > external_handler);
 }
 
 
-bool Isolate::HasExternalTryCatch() {
-  DCHECK(has_pending_exception());
+void Isolate::ReportPendingMessages() {
+  Object* exception = pending_exception();
 
-  return (thread_local_top()->catcher_ != NULL) &&
-      (try_catch_handler() == thread_local_top()->catcher_);
-}
+  // Try to propagate the exception to an external v8::TryCatch handler. If
+  // propagation was unsuccessful, then we will get another chance at reporting
+  // the pending message if the exception is re-thrown.
+  bool has_been_propagated = PropagatePendingExceptionToExternalTryCatch();
+  if (!has_been_propagated) return;
 
+  // Clear the pending message object early to avoid endless recursion.
+  Object* message_obj = thread_local_top_.pending_message_obj_;
+  clear_pending_message();
 
-bool Isolate::IsFinallyOnTop() {
-  // Get the address of the external handler so we can compare the address to
-  // determine which one is closer to the top of the stack.
-  Address external_handler_address =
-      thread_local_top()->try_catch_handler_address();
-  DCHECK(external_handler_address != NULL);
-
-  // The exception has been externally caught if and only if there is
-  // an external handler which is on top of the top-most try-finally
-  // handler.
-  // There should be no try-catch blocks as they would prohibit us from
-  // finding external catcher in the first place (see catcher_ check above).
-  //
-  // Note, that finally clause would rethrow an exception unless it's
-  // aborted by jumps in control flow like return, break, etc. and we'll
-  // have another chances to set proper v8::TryCatch.
-  StackHandler* handler =
-      StackHandler::FromAddress(Isolate::handler(thread_local_top()));
-  while (handler != NULL && handler->address() < external_handler_address) {
-    DCHECK(!handler->is_catch());
-    if (handler->is_finally()) return true;
+  // For uncatchable exceptions we do nothing. If needed, the exception and the
+  // message have already been propagated to v8::TryCatch.
+  if (!is_catchable_by_javascript(exception)) return;
 
-    handler = handler->next();
+  // Determine whether the message needs to be reported to all message handlers
+  // depending on whether and external v8::TryCatch or an internal JavaScript
+  // handler is on top.
+  bool should_report_exception;
+  if (IsExternalHandlerOnTop(exception)) {
+    // Only report the exception if the external handler is verbose.
+    should_report_exception = try_catch_handler()->is_verbose_;
+  } else {
+    // Report the exception if it isn't caught by JavaScript code.
+    should_report_exception = !IsJavaScriptHandlerOnTop(exception);
   }
 
-  return false;
-}
-
-
-void Isolate::ReportPendingMessages() {
-  DCHECK(has_pending_exception());
-  bool can_clear_message = PropagatePendingExceptionToExternalTryCatch();
-
-  HandleScope scope(this);
-  if (thread_local_top_.pending_exception_ == heap()->termination_exception()) {
-    // Do nothing: if needed, the exception has been already propagated to
-    // v8::TryCatch.
-  } else {
-    if (thread_local_top_.has_pending_message_) {
-      thread_local_top_.has_pending_message_ = false;
-      if (!thread_local_top_.pending_message_obj_->IsTheHole()) {
-        HandleScope scope(this);
-        Handle<Object> message_obj(thread_local_top_.pending_message_obj_,
-                                   this);
-        if (!thread_local_top_.pending_message_script_->IsTheHole()) {
-          Handle<Script> script(
-              Script::cast(thread_local_top_.pending_message_script_));
-          int start_pos = thread_local_top_.pending_message_start_pos_;
-          int end_pos = thread_local_top_.pending_message_end_pos_;
-          MessageLocation location(script, start_pos, end_pos);
-          MessageHandler::ReportMessage(this, &location, message_obj);
-        } else {
-          MessageHandler::ReportMessage(this, NULL, message_obj);
-        }
-      }
-    }
+  // Actually report the pending message to all message handlers.
+  if (!message_obj->IsTheHole() && should_report_exception) {
+    HandleScope scope(this);
+    Handle<JSMessageObject> message(JSMessageObject::cast(message_obj));
+    Handle<JSValue> script_wrapper(JSValue::cast(message->script()));
+    Handle<Script> script(Script::cast(script_wrapper->value()));
+    int start_pos = message->start_position();
+    int end_pos = message->end_position();
+    MessageLocation location(script, start_pos, end_pos);
+    MessageHandler::ReportMessage(this, &location, message);
   }
-  if (can_clear_message) clear_pending_message();
 }
 
 
@@ -1422,12 +1463,13 @@ MessageLocation Isolate::GetMessageLocation() {
   DCHECK(has_pending_exception());
 
   if (thread_local_top_.pending_exception_ != heap()->termination_exception() &&
-      thread_local_top_.has_pending_message_ &&
       !thread_local_top_.pending_message_obj_->IsTheHole()) {
-    Handle<Script> script(
-        Script::cast(thread_local_top_.pending_message_script_));
-    int start_pos = thread_local_top_.pending_message_start_pos_;
-    int end_pos = thread_local_top_.pending_message_end_pos_;
+    Handle<JSMessageObject> message_obj(
+        JSMessageObject::cast(thread_local_top_.pending_message_obj_));
+    Handle<JSValue> script_wrapper(JSValue::cast(message_obj->script()));
+    Handle<Script> script(Script::cast(script_wrapper->value()));
+    int start_pos = message_obj->start_position();
+    int end_pos = message_obj->end_position();
     return MessageLocation(script, start_pos, end_pos);
   }
 
@@ -1478,13 +1520,16 @@ bool Isolate::OptionalRescheduleException(bool is_bottom_call) {
 }
 
 
-void Isolate::PushPromise(Handle<JSObject> promise) {
+void Isolate::PushPromise(Handle<JSObject> promise,
+                          Handle<JSFunction> function) {
   ThreadLocalTop* tltop = thread_local_top();
   PromiseOnStack* prev = tltop->promise_on_stack_;
-  StackHandler* handler = StackHandler::FromAddress(Isolate::handler(tltop));
-  Handle<JSObject> global_handle =
+  Handle<JSObject> global_promise =
       Handle<JSObject>::cast(global_handles()->Create(*promise));
-  tltop->promise_on_stack_ = new PromiseOnStack(handler, global_handle, prev);
+  Handle<JSFunction> global_function =
+      Handle<JSFunction>::cast(global_handles()->Create(*function));
+  tltop->promise_on_stack_ =
+      new PromiseOnStack(global_function, global_promise, prev);
 }
 
 
@@ -1492,10 +1537,12 @@ void Isolate::PopPromise() {
   ThreadLocalTop* tltop = thread_local_top();
   if (tltop->promise_on_stack_ == NULL) return;
   PromiseOnStack* prev = tltop->promise_on_stack_->prev();
-  Handle<Object> global_handle = tltop->promise_on_stack_->promise();
+  Handle<Object> global_function = tltop->promise_on_stack_->function();
+  Handle<Object> global_promise = tltop->promise_on_stack_->promise();
   delete tltop->promise_on_stack_;
   tltop->promise_on_stack_ = prev;
-  global_handles()->Destroy(global_handle.location());
+  global_handles()->Destroy(global_function.location());
+  global_handles()->Destroy(global_promise.location());
 }
 
 
@@ -1503,17 +1550,21 @@ Handle<Object> Isolate::GetPromiseOnStackOnThrow() {
   Handle<Object> undefined = factory()->undefined_value();
   ThreadLocalTop* tltop = thread_local_top();
   if (tltop->promise_on_stack_ == NULL) return undefined;
-  StackHandler* promise_try = tltop->promise_on_stack_->handler();
-  // Find the top-most try-catch handler.
-  StackHandler* handler = StackHandler::FromAddress(Isolate::handler(tltop));
-  do {
-    if (handler == promise_try) {
-      return tltop->promise_on_stack_->promise();
+  Handle<JSFunction> promise_function = tltop->promise_on_stack_->function();
+  // Find the top-most try-catch or try-finally handler.
+  if (PredictExceptionCatcher() != CAUGHT_BY_JAVASCRIPT) return undefined;
+  for (JavaScriptFrameIterator it(this); !it.done(); it.Advance()) {
+    JavaScriptFrame* frame = it.frame();
+    int stack_slots = 0;  // The computed stack slot count is not used.
+    if (frame->LookupExceptionHandlerInTable(&stack_slots) > 0) {
+      // Throwing inside a Promise only leads to a reject if not caught by an
+      // inner try-catch or try-finally.
+      if (frame->function() == *promise_function) {
+        return tltop->promise_on_stack_->promise();
+      }
+      return undefined;
     }
-    handler = handler->next();
-    // Throwing inside a Promise can be intercepted by an inner try-catch, so
-    // we stop at the first try-catch handler.
-  } while (handler != NULL && !handler->is_catch());
+  }
   return undefined;
 }
 
@@ -1757,11 +1808,6 @@ void Isolate::TearDown() {
     thread_data_table_->RemoveAllThreads(this);
   }
 
-  if (serialize_partial_snapshot_cache_ != NULL) {
-    delete[] serialize_partial_snapshot_cache_;
-    serialize_partial_snapshot_cache_ = NULL;
-  }
-
   delete this;
 
   // Restore the previous current isolate.
@@ -1775,6 +1821,16 @@ void Isolate::GlobalTearDown() {
 }
 
 
+void Isolate::ClearSerializerData() {
+  delete external_reference_table_;
+  external_reference_table_ = NULL;
+  delete external_reference_map_;
+  external_reference_map_ = NULL;
+  delete root_index_map_;
+  root_index_map_ = NULL;
+}
+
+
 void Isolate::Deinit() {
   TRACE_ISOLATE(deinit);
 
@@ -1822,26 +1878,8 @@ void Isolate::Deinit() {
   heap_profiler_ = NULL;
   delete cpu_profiler_;
   cpu_profiler_ = NULL;
-}
-
-
-void Isolate::PushToPartialSnapshotCache(Object* obj) {
-  int length = serialize_partial_snapshot_cache_length();
-  int capacity = serialize_partial_snapshot_cache_capacity();
 
-  if (length >= capacity) {
-    int new_capacity = static_cast<int>((capacity + 10) * 1.2);
-    Object** new_array = new Object*[new_capacity];
-    for (int i = 0; i < length; i++) {
-      new_array[i] = serialize_partial_snapshot_cache()[i];
-    }
-    if (capacity != 0) delete[] serialize_partial_snapshot_cache();
-    set_serialize_partial_snapshot_cache(new_array);
-    set_serialize_partial_snapshot_cache_capacity(new_capacity);
-  }
-
-  serialize_partial_snapshot_cache()[length] = obj;
-  set_serialize_partial_snapshot_cache_length(length + 1);
+  ClearSerializerData();
 }
 
 
@@ -1930,9 +1968,6 @@ Isolate::~Isolate() {
   delete string_stream_debug_object_cache_;
   string_stream_debug_object_cache_ = NULL;
 
-  delete external_reference_table_;
-  external_reference_table_ = NULL;
-
   delete random_number_generator_;
   random_number_generator_ = NULL;
 
@@ -1948,22 +1983,20 @@ void Isolate::InitializeThreadLocal() {
 
 
 bool Isolate::PropagatePendingExceptionToExternalTryCatch() {
-  DCHECK(has_pending_exception());
+  Object* exception = pending_exception();
 
-  bool has_external_try_catch = HasExternalTryCatch();
-  if (!has_external_try_catch) {
+  if (IsJavaScriptHandlerOnTop(exception)) {
     thread_local_top_.external_caught_exception_ = false;
-    return true;
+    return false;
   }
 
-  bool catchable_by_js = is_catchable_by_javascript(pending_exception());
-  if (catchable_by_js && IsFinallyOnTop()) {
+  if (!IsExternalHandlerOnTop(exception)) {
     thread_local_top_.external_caught_exception_ = false;
-    return false;
+    return true;
   }
 
   thread_local_top_.external_caught_exception_ = true;
-  if (thread_local_top_.pending_exception_ == heap()->termination_exception()) {
+  if (!is_catchable_by_javascript(exception)) {
     try_catch_handler()->can_continue_ = false;
     try_catch_handler()->has_terminated_ = true;
     try_catch_handler()->exception_ = heap()->null_value();
@@ -1971,8 +2004,6 @@ bool Isolate::PropagatePendingExceptionToExternalTryCatch() {
     v8::TryCatch* handler = try_catch_handler();
     DCHECK(thread_local_top_.pending_message_obj_->IsJSMessageObject() ||
            thread_local_top_.pending_message_obj_->IsTheHole());
-    DCHECK(thread_local_top_.pending_message_script_->IsScript() ||
-           thread_local_top_.pending_message_script_->IsTheHole());
     handler->can_continue_ = true;
     handler->has_terminated_ = false;
     handler->exception_ = pending_exception();
@@ -1980,9 +2011,6 @@ bool Isolate::PropagatePendingExceptionToExternalTryCatch() {
     if (thread_local_top_.pending_message_obj_->IsTheHole()) return true;
 
     handler->message_obj_ = thread_local_top_.pending_message_obj_;
-    handler->message_script_ = thread_local_top_.pending_message_script_;
-    handler->message_start_pos_ = thread_local_top_.pending_message_start_pos_;
-    handler->message_end_pos_ = thread_local_top_.pending_message_end_pos_;
   }
   return true;
 }
@@ -2088,7 +2116,7 @@ bool Isolate::Init(Deserializer* des) {
 
   if (create_heap_objects) {
     // Terminate the cache array with the sentinel so we can iterate.
-    PushToPartialSnapshotCache(heap_.undefined_value());
+    partial_snapshot_cache_.Add(heap_.undefined_value());
   }
 
   InitializeThreadLocal();
@@ -2589,6 +2617,7 @@ void Isolate::CheckDetachedContextsAfterGC() {
   int new_length = 0;
   for (int i = 0; i < length; i += 2) {
     int mark_sweeps = Smi::cast(detached_contexts->get(i))->value();
+    DCHECK(detached_contexts->get(i + 1)->IsWeakCell());
     WeakCell* cell = WeakCell::cast(detached_contexts->get(i + 1));
     if (!cell->cleared()) {
       detached_contexts->set(new_length, Smi::FromInt(mark_sweeps + 1));
@@ -2602,6 +2631,7 @@ void Isolate::CheckDetachedContextsAfterGC() {
            length - new_length, length);
     for (int i = 0; i < new_length; i += 2) {
       int mark_sweeps = Smi::cast(detached_contexts->get(i))->value();
+      DCHECK(detached_contexts->get(i + 1)->IsWeakCell());
       WeakCell* cell = WeakCell::cast(detached_contexts->get(i + 1));
       if (mark_sweeps > 3) {
         PrintF("detached context 0x%p\n survived %d GCs (leak?)\n",
@@ -2612,8 +2642,8 @@ void Isolate::CheckDetachedContextsAfterGC() {
   if (new_length == 0) {
     heap()->set_detached_contexts(heap()->empty_fixed_array());
   } else if (new_length < length) {
-    heap()->RightTrimFixedArray<Heap::FROM_GC>(*detached_contexts,
-                                               length - new_length);
+    heap()->RightTrimFixedArray<Heap::FROM_MUTATOR>(*detached_contexts,
+                                                    length - new_length);
   }
 }
 
index fdd1832..80c3dae 100644 (file)
@@ -137,20 +137,14 @@ typedef ZoneList<Handle<Object> > ZoneObjectList;
 #define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call, T)  \
   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, MaybeHandle<T>())
 
-#define THROW_NEW_ERROR(isolate, call, T)                                    \
-  do {                                                                       \
-    Handle<Object> __error__;                                                \
-    ASSIGN_RETURN_ON_EXCEPTION(isolate, __error__, isolate->factory()->call, \
-                               T);                                           \
-    return isolate->Throw<T>(__error__);                                     \
+#define THROW_NEW_ERROR(isolate, call, T)               \
+  do {                                                  \
+    return isolate->Throw<T>(isolate->factory()->call); \
   } while (false)
 
-#define THROW_NEW_ERROR_RETURN_FAILURE(isolate, call)             \
-  do {                                                            \
-    Handle<Object> __error__;                                     \
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, __error__,        \
-                                       isolate->factory()->call); \
-    return isolate->Throw(*__error__);                            \
+#define THROW_NEW_ERROR_RETURN_FAILURE(isolate, call) \
+  do {                                                \
+    return isolate->Throw(*isolate->factory()->call); \
   } while (false)
 
 #define RETURN_ON_EXCEPTION_VALUE(isolate, call, value)            \
@@ -174,6 +168,11 @@ typedef ZoneList<Handle<Object> > ZoneObjectList;
   C(CFunction, c_function)                              \
   C(Context, context)                                   \
   C(PendingException, pending_exception)                \
+  C(PendingHandlerContext, pending_handler_context)     \
+  C(PendingHandlerCode, pending_handler_code)           \
+  C(PendingHandlerOffset, pending_handler_offset)       \
+  C(PendingHandlerFP, pending_handler_fp)               \
+  C(PendingHandlerSP, pending_handler_sp)               \
   C(ExternalCaughtException, external_caught_exception) \
   C(JSEntrySP, js_entry_sp)
 
@@ -274,23 +273,28 @@ class ThreadLocalTop BASE_EMBEDDED {
   Context* context_;
   ThreadId thread_id_;
   Object* pending_exception_;
-  bool has_pending_message_;
+
+  // Communication channel between Isolate::FindHandler and the CEntryStub.
+  Context* pending_handler_context_;
+  Code* pending_handler_code_;
+  intptr_t pending_handler_offset_;
+  Address pending_handler_fp_;
+  Address pending_handler_sp_;
+
+  // Communication channel between Isolate::Throw and message consumers.
   bool rethrowing_message_;
   Object* pending_message_obj_;
-  Object* pending_message_script_;
-  int pending_message_start_pos_;
-  int pending_message_end_pos_;
+
   // Use a separate value for scheduled exceptions to preserve the
   // invariants that hold about pending_exception.  We may want to
   // unify them later.
   Object* scheduled_exception_;
   bool external_caught_exception_;
   SaveContext* save_context_;
-  v8::TryCatch* catcher_;
 
   // Stack.
   Address c_entry_fp_;  // the frame pointer of the top c entry frame
-  Address handler_;   // try-blocks are chained through the stack
+  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
@@ -307,9 +311,6 @@ class ThreadLocalTop BASE_EMBEDDED {
   ExternalCallbackScope* external_callback_scope_;
   StateTag current_vm_state_;
 
-  // Generated code scratch locations.
-  int32_t formal_count_;
-
   // Call back function to report unsafe JS accesses.
   v8::FailedAccessCheckCallback failed_access_check_callback_;
 
@@ -361,10 +362,6 @@ class ThreadLocalTop BASE_EMBEDDED {
 typedef List<HeapObject*> DebugObjectCache;
 
 #define ISOLATE_INIT_LIST(V)                                                   \
-  /* SerializerDeserializer state. */                                          \
-  V(int, serialize_partial_snapshot_cache_length, 0)                           \
-  V(int, serialize_partial_snapshot_cache_capacity, 0)                         \
-  V(Object**, serialize_partial_snapshot_cache, NULL)                          \
   /* Assembler state. */                                                       \
   V(FatalErrorCallback, exception_behavior, NULL)                              \
   V(LogEventCallback, event_logger, NULL)                                      \
@@ -379,8 +376,9 @@ typedef List<HeapObject*> DebugObjectCache;
   V(Relocatable*, relocatable_top, NULL)                                       \
   V(DebugObjectCache*, string_stream_debug_object_cache, NULL)                 \
   V(Object*, string_stream_current_security_token, NULL)                       \
-  /* Serializer state. */                                                      \
   V(ExternalReferenceTable*, external_reference_table, NULL)                   \
+  V(HashMap*, external_reference_map, NULL)                                    \
+  V(HashMap*, root_index_map, NULL)                                            \
   V(int, pending_microtask_count, 0)                                           \
   V(bool, autorun_microtasks, true)                                            \
   V(HStatistics*, hstatistics, NULL)                                           \
@@ -391,12 +389,16 @@ typedef List<HeapObject*> DebugObjectCache;
   V(int, max_available_threads, 0)                                             \
   V(uint32_t, per_isolate_assert_data, 0xFFFFFFFFu)                            \
   V(PromiseRejectCallback, promise_reject_callback, NULL)                      \
+  V(const v8::StartupData*, snapshot_blob, NULL)                               \
   ISOLATE_INIT_SIMULATOR_LIST(V)
 
 #define THREAD_LOCAL_TOP_ACCESSOR(type, name)                        \
   inline void set_##name(type v) { thread_local_top_.name##_ = v; }  \
   inline type name() const { return thread_local_top_.name##_; }
 
+#define THREAD_LOCAL_TOP_ADDRESS(type, name) \
+  type* name##_address() { return &thread_local_top_.name##_; }
+
 
 class Isolate {
   // These forward declarations are required to make the friend declarations in
@@ -526,6 +528,8 @@ class Isolate {
 
   static void GlobalTearDown();
 
+  void ClearSerializerData();
+
   // Find the PerThread for this particular (isolate, thread) combination
   // If one does not yet exist, return null.
   PerIsolateThreadData* FindPerThreadDataForThisThread();
@@ -583,51 +587,37 @@ class Isolate {
     thread_local_top_.pending_exception_ = heap_.the_hole_value();
   }
 
-  Object** pending_exception_address() {
-    return &thread_local_top_.pending_exception_;
-  }
+  THREAD_LOCAL_TOP_ADDRESS(Object*, pending_exception)
 
   bool has_pending_exception() {
     DCHECK(!thread_local_top_.pending_exception_->IsException());
     return !thread_local_top_.pending_exception_->IsTheHole();
   }
 
+  THREAD_LOCAL_TOP_ADDRESS(Context*, pending_handler_context)
+  THREAD_LOCAL_TOP_ADDRESS(Code*, pending_handler_code)
+  THREAD_LOCAL_TOP_ADDRESS(intptr_t, pending_handler_offset)
+  THREAD_LOCAL_TOP_ADDRESS(Address, pending_handler_fp)
+  THREAD_LOCAL_TOP_ADDRESS(Address, pending_handler_sp)
+
   THREAD_LOCAL_TOP_ACCESSOR(bool, external_caught_exception)
 
   void clear_pending_message() {
-    thread_local_top_.has_pending_message_ = false;
     thread_local_top_.pending_message_obj_ = heap_.the_hole_value();
-    thread_local_top_.pending_message_script_ = heap_.the_hole_value();
   }
   v8::TryCatch* try_catch_handler() {
     return thread_local_top_.try_catch_handler();
   }
-  Address try_catch_handler_address() {
-    return thread_local_top_.try_catch_handler_address();
-  }
   bool* external_caught_exception_address() {
     return &thread_local_top_.external_caught_exception_;
   }
 
-  THREAD_LOCAL_TOP_ACCESSOR(v8::TryCatch*, catcher)
-
-  Object** scheduled_exception_address() {
-    return &thread_local_top_.scheduled_exception_;
-  }
+  THREAD_LOCAL_TOP_ADDRESS(Object*, scheduled_exception)
 
   Address pending_message_obj_address() {
     return reinterpret_cast<Address>(&thread_local_top_.pending_message_obj_);
   }
 
-  Address has_pending_message_address() {
-    return reinterpret_cast<Address>(&thread_local_top_.has_pending_message_);
-  }
-
-  Address pending_message_script_address() {
-    return reinterpret_cast<Address>(
-        &thread_local_top_.pending_message_script_);
-  }
-
   Object* scheduled_exception() {
     DCHECK(has_scheduled_exception());
     DCHECK(!thread_local_top_.scheduled_exception_->IsException());
@@ -642,16 +632,13 @@ class Isolate {
     thread_local_top_.scheduled_exception_ = heap_.the_hole_value();
   }
 
-  bool HasExternalTryCatch();
-  bool IsFinallyOnTop();
+  bool IsJavaScriptHandlerOnTop(Object* exception);
+  bool IsExternalHandlerOnTop(Object* exception);
 
   bool is_catchable_by_javascript(Object* exception) {
     return exception != heap()->termination_exception();
   }
 
-  // Serializer.
-  void PushToPartialSnapshotCache(Object* obj);
-
   // JS execution stack (see frames.h).
   static Address c_entry_fp(ThreadLocalTop* thread) {
     return thread->c_entry_fp_;
@@ -675,9 +662,6 @@ class Isolate {
     return &thread_local_top_.js_entry_sp_;
   }
 
-  // Generated code scratch locations.
-  void* formal_count_address() { return &thread_local_top_.formal_count_; }
-
   // Returns the global object of the current context. It could be
   // a builtin object, or a JS global object.
   Handle<GlobalObject> global_object() {
@@ -703,29 +687,25 @@ class Isolate {
   bool OptionalRescheduleException(bool is_bottom_call);
 
   // Push and pop a promise and the current try-catch handler.
-  void PushPromise(Handle<JSObject> promise);
+  void PushPromise(Handle<JSObject> promise, Handle<JSFunction> function);
   void PopPromise();
   Handle<Object> GetPromiseOnStackOnThrow();
 
   class ExceptionScope {
    public:
-    explicit ExceptionScope(Isolate* isolate) :
-      // Scope currently can only be used for regular exceptions,
-      // not termination exception.
-      isolate_(isolate),
-      pending_exception_(isolate_->pending_exception(), isolate_),
-      catcher_(isolate_->catcher())
-    { }
+    // Scope currently can only be used for regular exceptions,
+    // not termination exception.
+    explicit ExceptionScope(Isolate* isolate)
+        : isolate_(isolate),
+          pending_exception_(isolate_->pending_exception(), isolate_) {}
 
     ~ExceptionScope() {
-      isolate_->set_catcher(catcher_);
       isolate_->set_pending_exception(*pending_exception_);
     }
 
    private:
     Isolate* isolate_;
     Handle<Object> pending_exception_;
-    v8::TryCatch* catcher_;
   };
 
   void SetCaptureStackTraceForUncaughtExceptions(
@@ -757,21 +737,17 @@ class Isolate {
   // the result is false, the pending exception is guaranteed to be
   // set.
 
-  bool MayNamedAccess(Handle<JSObject> receiver,
-                      Handle<Object> key,
-                      v8::AccessType type);
-  bool MayIndexedAccess(Handle<JSObject> receiver,
-                        uint32_t index,
-                        v8::AccessType type);
+  bool MayAccess(Handle<JSObject> receiver);
   bool IsInternallyUsedPropertyName(Handle<Object> name);
   bool IsInternallyUsedPropertyName(Object* name);
 
   void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback);
-  void ReportFailedAccessCheck(Handle<JSObject> receiver, v8::AccessType type);
+  void ReportFailedAccessCheck(Handle<JSObject> receiver);
 
   // Exception throwing support. The caller should use the result
   // of Throw() as its return value.
   Object* Throw(Object* exception, MessageLocation* location = NULL);
+  Object* ThrowIllegalOperation();
 
   template <typename T>
   MUST_USE_RESULT MaybeHandle<T> Throw(Handle<Object> exception,
@@ -780,10 +756,21 @@ class Isolate {
     return MaybeHandle<T>();
   }
 
-  // Re-throw an exception.  This involves no error reporting since
-  // error reporting was handled when the exception was thrown
-  // originally.
+  // Re-throw an exception.  This involves no error reporting since error
+  // reporting was handled when the exception was thrown originally.
   Object* ReThrow(Object* exception);
+
+  // Find the correct handler for the current pending exception. This also
+  // clears and returns the current pending exception.
+  Object* FindHandler();
+
+  // Tries to predict whether an exception will be caught. Note that this can
+  // only produce an estimate, because it is undecidable whether a finally
+  // clause will consume or re-throw an exception. We conservatively assume any
+  // finally clause will behave as if the exception were consumed.
+  enum CatchType { NOT_CAUGHT, CAUGHT_BY_JAVASCRIPT, CAUGHT_BY_EXTERNAL };
+  CatchType PredictExceptionCatcher();
+
   void ScheduleThrow(Object* exception);
   // Re-set pending message, script and positions reported to the TryCatch
   // back to the TLS for re-use when rethrowing.
@@ -793,15 +780,9 @@ class Isolate {
   void ReportPendingMessages();
   // Return pending location if any or unfilled structure.
   MessageLocation GetMessageLocation();
-  Object* ThrowIllegalOperation();
 
   // Promote a scheduled exception to pending. Asserts has_scheduled_exception.
   Object* PromoteScheduledException();
-  void DoThrow(Object* exception, MessageLocation* location);
-  // Checks if exception should be reported and finds out if it's
-  // caught externally.
-  bool ShouldReportException(bool* can_be_caught_externally,
-                             bool catchable_by_javascript);
 
   // Attempts to compute the current source location, storing the
   // result in the target out parameter.
@@ -828,7 +809,6 @@ class Isolate {
   char* Iterate(ObjectVisitor* v, char* t);
   void IterateThread(ThreadVisitor* v, char* t);
 
-
   // Returns the current native context.
   Handle<Context> native_context();
 
@@ -1006,6 +986,7 @@ class Isolate {
   }
 
   bool serializer_enabled() const { return serializer_enabled_; }
+  bool snapshot_available() const { return snapshot_blob_ != NULL; }
 
   bool IsDead() { return has_fatal_error_; }
   void SignalFatalError() { has_fatal_error_ = true; }
@@ -1139,9 +1120,12 @@ class Isolate {
   void AddDetachedContext(Handle<Context> context);
   void CheckDetachedContextsAfterGC();
 
- private:
+  List<Object*>* partial_snapshot_cache() { return &partial_snapshot_cache_; }
+
+ protected:
   explicit Isolate(bool enable_serializer);
 
+ private:
   friend struct GlobalState;
   friend struct InitializeGlobalState;
 
@@ -1360,6 +1344,7 @@ class Isolate {
   v8::Isolate::UseCounterCallback use_counter_callback_;
   BasicBlockProfiler* basic_block_profiler_;
 
+  List<Object*> partial_snapshot_cache_;
 
   friend class ExecutionAccess;
   friend class HandleScopeImplementer;
@@ -1374,6 +1359,7 @@ class Isolate {
   friend class v8::Isolate;
   friend class v8::Locker;
   friend class v8::Unlocker;
+  friend v8::StartupData v8::V8::CreateSnapshotDataBlob(const char*);
 
   DISALLOW_COPY_AND_ASSIGN(Isolate);
 };
@@ -1385,15 +1371,15 @@ class Isolate {
 
 class PromiseOnStack {
  public:
-  PromiseOnStack(StackHandler* handler, Handle<JSObject> promise,
+  PromiseOnStack(Handle<JSFunction> function, Handle<JSObject> promise,
                  PromiseOnStack* prev)
-      : handler_(handler), promise_(promise), prev_(prev) {}
-  StackHandler* handler() { return handler_; }
+      : function_(function), promise_(promise), prev_(prev) {}
+  Handle<JSFunction> function() { return function_; }
   Handle<JSObject> promise() { return promise_; }
   PromiseOnStack* prev() { return prev_; }
 
  private:
-  StackHandler* handler_;
+  Handle<JSFunction> function_;
   Handle<JSObject> promise_;
   PromiseOnStack* prev_;
 };
index 9a22738..12eea78 100644 (file)
@@ -108,8 +108,9 @@ class JsonParser BASE_EMBEDDED {
         const uint8_t* expected_chars = content.ToOneByteVector().start();
         for (int i = 0; i < length; i++) {
           uint8_t c0 = input_chars[i];
-          // The expected string has to be free of \, " and characters < 0x20.
-          if (c0 != expected_chars[i]) return false;
+          if (c0 != expected_chars[i] || c0 == '"' || c0 < 0x20 || c0 == '\\') {
+            return false;
+          }
         }
         if (input_chars[length] == '"') {
           position_ = position_ + length + 1;
@@ -172,7 +173,7 @@ class JsonParser BASE_EMBEDDED {
   inline Factory* factory() { return factory_; }
   inline Handle<JSFunction> object_constructor() { return object_constructor_; }
 
-  static const int kInitialSpecialStringLength = 1024;
+  static const int kInitialSpecialStringLength = 32;
   static const int kPretenureTreshold = 100 * 1024;
 
 
@@ -244,9 +245,7 @@ MaybeHandle<Object> JsonParser<seq_one_byte>::ParseJson() {
     MessageLocation location(factory->NewScript(source_),
                              position_,
                              position_ + 1);
-    Handle<Object> error;
-    ASSIGN_RETURN_ON_EXCEPTION(isolate(), error,
-                               factory->NewSyntaxError(message, array), Object);
+    Handle<Object> error = factory->NewSyntaxError(message, array);
     return isolate()->template Throw<Object>(error, &location);
   }
   return result;
@@ -262,6 +261,12 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonValue() {
     return Handle<Object>::null();
   }
 
+  if (isolate_->stack_guard()->InterruptRequested()) {
+    ExecutionAccess access(isolate_);
+    // Avoid blocking GC in long running parser (v8:3974).
+    isolate_->stack_guard()->CheckAndHandleGCInterrupt();
+  }
+
   if (c0_ == '"') return ParseJsonString();
   if ((c0_ >= '0' && c0_ <= '9') || c0_ == '-') return ParseJsonNumber();
   if (c0_ == '{') return ParseJsonObject();
@@ -301,6 +306,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
   Handle<JSObject> json_object =
       factory()->NewJSObject(object_constructor(), pretenure_);
   Handle<Map> map(json_object->map());
+  int descriptor = 0;
   ZoneList<Handle<Object> > properties(8, zone());
   DCHECK_EQ(c0_, '{');
 
@@ -315,7 +321,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
       Advance();
 
       uint32_t index = 0;
-      if (c0_ >= '0' && c0_ <= '9') {
+      if (IsDecimalDigit(c0_)) {
         // Maybe an array index, try to parse it.
         if (c0_ == '0') {
           // With a leading zero, the string has to be "0" only to be an index.
@@ -326,7 +332,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
             if (index > 429496729U - ((d > 5) ? 1 : 0)) break;
             index = (index * 10) + d;
             Advance();
-          } while (c0_ >= '0' && c0_ <= '9');
+          } while (IsDecimalDigit(c0_));
         }
 
         if (c0_ == '"') {
@@ -360,19 +366,19 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
         bool follow_expected = false;
         Handle<Map> target;
         if (seq_one_byte) {
-          key = Map::ExpectedTransitionKey(map);
+          key = TransitionArray::ExpectedTransitionKey(map);
           follow_expected = !key.is_null() && ParseJsonString(key);
         }
         // If the expected transition hits, follow it.
         if (follow_expected) {
-          target = Map::ExpectedTransitionTarget(map);
+          target = TransitionArray::ExpectedTransitionTarget(map);
         } else {
           // If the expected transition failed, parse an internalized string and
           // try to find a matching transition.
           key = ParseJsonInternalizedString();
           if (key.is_null()) return ReportUnexpectedCharacter();
 
-          target = Map::FindTransitionToField(map, key);
+          target = TransitionArray::FindTransitionToField(map, key);
           // If a transition was found, follow it and continue.
           transitioning = !target.is_null();
         }
@@ -383,18 +389,15 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
         if (value.is_null()) return ReportUnexpectedCharacter();
 
         if (transitioning) {
-          int descriptor = map->NumberOfOwnDescriptors();
           PropertyDetails details =
               target->instance_descriptors()->GetDetails(descriptor);
           Representation expected_representation = details.representation();
 
           if (value->FitsRepresentation(expected_representation)) {
-            if (expected_representation.IsDouble()) {
-              value = Object::NewStorageFor(isolate(), value,
-                                            expected_representation);
-            } else if (expected_representation.IsHeapObject() &&
-                       !target->instance_descriptors()->GetFieldType(
-                           descriptor)->NowContains(value)) {
+            if (expected_representation.IsHeapObject() &&
+                !target->instance_descriptors()
+                     ->GetFieldType(descriptor)
+                     ->NowContains(value)) {
               Handle<HeapType> value_type(value->OptimalType(
                       isolate(), expected_representation));
               Map::GeneralizeFieldType(target, descriptor,
@@ -404,6 +407,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
                     descriptor)->NowContains(value));
             properties.Add(value, zone());
             map = target;
+            descriptor++;
             continue;
           } else {
             transitioning = false;
@@ -445,30 +449,11 @@ void JsonParser<seq_one_byte>::CommitStateToJsonObject(
   DCHECK(!json_object->map()->is_dictionary_map());
 
   DisallowHeapAllocation no_gc;
-  Factory* factory = isolate()->factory();
-  // If the |json_object|'s map is exactly the same as |map| then the
-  // |properties| values correspond to the |map| and nothing more has to be
-  // done. But if the |json_object|'s map is different then we have to
-  // iterate descriptors to ensure that properties still correspond to the
-  // map.
-  bool slow_case = json_object->map() != *map;
-  DescriptorArray* descriptors = NULL;
 
   int length = properties->length();
-  if (slow_case) {
-    descriptors = json_object->map()->instance_descriptors();
-    DCHECK(json_object->map()->NumberOfOwnDescriptors() == length);
-  }
   for (int i = 0; i < length; i++) {
     Handle<Object> value = (*properties)[i];
-    if (slow_case && value->IsMutableHeapNumber() &&
-        !descriptors->GetDetails(i).representation().IsDouble()) {
-      // Turn mutable heap numbers into immutable if the field representation
-      // is not double.
-      HeapNumber::cast(*value)->set_map(*factory->heap_number_map());
-    }
-    FieldIndex index = FieldIndex::ForPropertyIndex(*map, i);
-    json_object->FastPropertyAtPut(index, *value);
+    json_object->WriteToField(i, *value);
   }
 }
 
@@ -516,7 +501,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonNumber() {
     Advance();
     // Prefix zero is only allowed if it's the only digit before
     // a decimal point or exponent.
-    if ('0' <= c0_ && c0_ <= '9') return ReportUnexpectedCharacter();
+    if (IsDecimalDigit(c0_)) return ReportUnexpectedCharacter();
   } else {
     int i = 0;
     int digits = 0;
@@ -525,7 +510,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonNumber() {
       i = i * 10 + c0_ - '0';
       digits++;
       Advance();
-    } while (c0_ >= '0' && c0_ <= '9');
+    } while (IsDecimalDigit(c0_));
     if (c0_ != '.' && c0_ != 'e' && c0_ != 'E' && digits < 10) {
       SkipWhitespace();
       return Handle<Smi>(Smi::FromInt((negative ? -i : i)), isolate());
@@ -533,18 +518,18 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonNumber() {
   }
   if (c0_ == '.') {
     Advance();
-    if (c0_ < '0' || c0_ > '9') return ReportUnexpectedCharacter();
+    if (!IsDecimalDigit(c0_)) return ReportUnexpectedCharacter();
     do {
       Advance();
-    } while (c0_ >= '0' && c0_ <= '9');
+    } while (IsDecimalDigit(c0_));
   }
   if (AsciiAlphaToLower(c0_) == 'e') {
     Advance();
     if (c0_ == '-' || c0_ == '+') Advance();
-    if (c0_ < '0' || c0_ > '9') return ReportUnexpectedCharacter();
+    if (!IsDecimalDigit(c0_)) return ReportUnexpectedCharacter();
     do {
       Advance();
-    } while (c0_ >= '0' && c0_ <= '9');
+    } while (IsDecimalDigit(c0_));
   }
   int length = position_ - beg_pos;
   double number;
index d7caefc..fabc8f3 100644 (file)
@@ -272,10 +272,9 @@ BasicJsonStringifier::Result BasicJsonStringifier::StackPush(
     for (int i = 0; i < length; i++) {
       if (elements->get(i) == *object) {
         AllowHeapAllocation allow_to_return_error;
-        Handle<Object> error;
-        MaybeHandle<Object> maybe_error = factory()->NewTypeError(
+        Handle<Object> error = factory()->NewTypeError(
             "circular_structure", HandleVector<Object>(NULL, 0));
-        if (maybe_error.ToHandle(&error)) isolate_->Throw(*error);
+        isolate_->Throw(*error);
         return EXCEPTION;
       }
     }
index e2b7dc8..90ffa25 100644 (file)
@@ -178,7 +178,7 @@ function JSONStringify(value, replacer, space) {
   }
   var gap;
   if (IS_NUMBER(space)) {
-    space = MathMax(0, MathMin(ToInteger(space), 10));
+    space = $max(0, $min(ToInteger(space), 10));
     gap = %_SubString("          ", 0, space);
   } else if (IS_STRING(space)) {
     if (space.length > 10) {
index bb7ad60..03398cf 100644 (file)
@@ -360,10 +360,8 @@ static void CreateRegExpErrorObjectAndThrow(Handle<JSRegExp> re,
   elements->set(0, re->Pattern());
   elements->set(1, *error_message);
   Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
-  Handle<Object> error;
-  MaybeHandle<Object> maybe_error =
-      factory->NewSyntaxError("malformed_regexp", array);
-  if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
+  Handle<Object> error = factory->NewSyntaxError("malformed_regexp", array);
+  isolate->Throw(*error);
 }
 
 
index ceee09a..ba76704 100644 (file)
@@ -20,18 +20,7 @@ Handle<LayoutDescriptor> LayoutDescriptor::New(Isolate* isolate, int length) {
     // 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;
-  }
+  length = GetSlowModeBackingStoreLength(length);
   return Handle<LayoutDescriptor>::cast(
       isolate->factory()->NewFixedTypedArray(length, kExternalUint32Array));
 }
@@ -154,6 +143,77 @@ LayoutDescriptor* LayoutDescriptor::cast_gc_safe(Object* object) {
 }
 
 
+int LayoutDescriptor::GetSlowModeBackingStoreLength(int length) {
+  length = (length + kNumberOfBits - 1) / kNumberOfBits;
+  DCHECK_LT(0, length);
+
+  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 length;
+}
+
+
+int LayoutDescriptor::CalculateCapacity(Map* map, DescriptorArray* descriptors,
+                                        int num_descriptors) {
+  int inobject_properties = map->inobject_properties();
+  if (inobject_properties == 0) return 0;
+
+  DCHECK_LE(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);
+    }
+  }
+  layout_descriptor_length = Min(layout_descriptor_length, inobject_properties);
+  return layout_descriptor_length;
+}
+
+
+LayoutDescriptor* LayoutDescriptor::Initialize(
+    LayoutDescriptor* layout_descriptor, Map* map, DescriptorArray* descriptors,
+    int num_descriptors) {
+  DisallowHeapAllocation no_allocation;
+  int inobject_properties = map->inobject_properties();
+
+  for (int i = 0; i < num_descriptors; i++) {
+    PropertyDetails details = descriptors->GetDetails(i);
+    if (!InobjectUnboxedField(inobject_properties, details)) {
+      DCHECK(details.location() != kField ||
+             layout_descriptor->IsTagged(details.field_index()));
+      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 layout_descriptor;
+}
+
+
 // InobjectPropertiesHelper is a helper class for querying whether inobject
 // property at offset is Double or not.
 LayoutDescriptorHelper::LayoutDescriptorHelper(Map* map)
index 121836c..4bb48c0 100644 (file)
@@ -19,55 +19,22 @@ Handle<LayoutDescriptor> LayoutDescriptor::New(
   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);
+  int layout_descriptor_length =
+      CalculateCapacity(*map, *descriptors, num_descriptors);
 
-  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);
-    }
+  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);
-    }
-  }
+  LayoutDescriptor* layout_descriptor = Initialize(
+      *layout_descriptor_handle, *map, *descriptors, num_descriptors);
+
   return handle(layout_descriptor, isolate);
 }
 
@@ -258,13 +225,44 @@ bool LayoutDescriptorHelper::IsTagged(
 }
 
 
-bool LayoutDescriptor::IsConsistentWithMap(Map* map) {
+LayoutDescriptor* LayoutDescriptor::Trim(Heap* heap, Map* map,
+                                         DescriptorArray* descriptors,
+                                         int num_descriptors) {
+  DisallowHeapAllocation no_allocation;
+  // Fast mode descriptors are never shared and therefore always fully
+  // correspond to their map.
+  if (!IsSlowLayout()) return this;
+
+  int layout_descriptor_length =
+      CalculateCapacity(map, descriptors, num_descriptors);
+  // It must not become fast-mode descriptor here, because otherwise it has to
+  // be fast pointer layout descriptor already but it's is slow mode now.
+  DCHECK_LT(kSmiValueSize, layout_descriptor_length);
+
+  // Trim, clean and reinitialize this slow-mode layout descriptor.
+  int array_length = GetSlowModeBackingStoreLength(layout_descriptor_length);
+  int current_length = length();
+  if (current_length != array_length) {
+    DCHECK_LT(array_length, current_length);
+    int delta = current_length - array_length;
+    heap->RightTrimFixedArray<Heap::FROM_GC>(this, delta);
+  }
+  memset(DataPtr(), 0, DataSize());
+  LayoutDescriptor* layout_descriptor =
+      Initialize(this, map, descriptors, num_descriptors);
+  DCHECK_EQ(this, layout_descriptor);
+  return layout_descriptor;
+}
+
+
+bool LayoutDescriptor::IsConsistentWithMap(Map* map, bool check_tail) {
   if (FLAG_unbox_double_fields) {
     DescriptorArray* descriptors = map->instance_descriptors();
     int nof_descriptors = map->NumberOfOwnDescriptors();
+    int last_field_index = 0;
     for (int i = 0; i < nof_descriptors; i++) {
       PropertyDetails details = descriptors->GetDetails(i);
-      if (details.type() != DATA) continue;
+      if (details.location() != kField) continue;
       FieldIndex field_index = FieldIndex::ForDescriptor(map, i);
       bool tagged_expected =
           !field_index.is_inobject() || !details.representation().IsDouble();
@@ -273,6 +271,15 @@ bool LayoutDescriptor::IsConsistentWithMap(Map* map) {
         DCHECK_EQ(tagged_expected, tagged_actual);
         if (tagged_actual != tagged_expected) return false;
       }
+      last_field_index =
+          Max(last_field_index,
+              details.field_index() + details.field_width_in_words());
+    }
+    if (check_tail) {
+      int n = capacity();
+      for (int i = last_field_index; i < n; i++) {
+        DCHECK(IsTagged(i));
+      }
     }
   }
   return true;
index 8f2942c..0a14f53 100644 (file)
@@ -70,7 +70,14 @@ class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> {
   V8_INLINE static LayoutDescriptor* FastPointerLayout();
 
   // Check that this layout descriptor corresponds to given map.
-  bool IsConsistentWithMap(Map* map);
+  bool IsConsistentWithMap(Map* map, bool check_tail = false);
+
+  // Trims this layout descriptor to given number of descriptors. This happens
+  // only when corresponding descriptors array is trimmed.
+  // The layout descriptor could be trimmed if it was slow or it could
+  // become fast.
+  LayoutDescriptor* Trim(Heap* heap, Map* map, DescriptorArray* descriptors,
+                         int num_descriptors);
 
 #ifdef OBJECT_PRINT
   // For our gdb macros, we should perhaps change these in the future.
@@ -94,6 +101,21 @@ class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> {
   V8_INLINE static bool InobjectUnboxedField(int inobject_properties,
                                              PropertyDetails details);
 
+  // Calculates minimal layout descriptor capacity required for given
+  // |map|, |descriptors| and |num_descriptors|.
+  V8_INLINE static int CalculateCapacity(Map* map, DescriptorArray* descriptors,
+                                         int num_descriptors);
+
+  // Calculates the length of the slow-mode backing store array by given layout
+  // descriptor length.
+  V8_INLINE static int GetSlowModeBackingStoreLength(int length);
+
+  // Fills in clean |layout_descriptor| according to given |map|, |descriptors|
+  // and |num_descriptors|.
+  V8_INLINE static LayoutDescriptor* Initialize(
+      LayoutDescriptor* layout_descriptor, Map* map,
+      DescriptorArray* descriptors, int num_descriptors);
+
   static Handle<LayoutDescriptor> EnsureCapacity(
       Isolate* isolate, Handle<LayoutDescriptor> layout_descriptor,
       int new_capacity);
index 242db22..89df2ce 100644 (file)
@@ -153,7 +153,7 @@ void LCodeGenBase::Comment(const char* format, ...) {
 
 
 void LCodeGenBase::DeoptComment(const Deoptimizer::DeoptInfo& deopt_info) {
-  masm()->RecordDeoptReason(deopt_info.deopt_reason, deopt_info.raw_position);
+  masm()->RecordDeoptReason(deopt_info.deopt_reason, deopt_info.position);
 }
 
 
@@ -189,4 +189,13 @@ void LCodeGenBase::AddStabilityDependency(Handle<Map> map) {
   chunk_->AddStabilityDependency(map);
 }
 
+
+Deoptimizer::DeoptInfo LCodeGenBase::MakeDeoptInfo(
+    LInstruction* instr, Deoptimizer::DeoptReason deopt_reason) {
+  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position(),
+                                    instr->Mnemonic(), deopt_reason);
+  HEnterInlined* enter_inlined = instr->environment()->entry();
+  deopt_info.inlining_id = enter_inlined ? enter_inlined->inlining_id() : 0;
+  return deopt_info;
+}
 } }  // namespace v8::internal
index 17bf78c..80afbaf 100644 (file)
@@ -36,6 +36,8 @@ class LCodeGenBase BASE_EMBEDDED {
 
   void FPRINTF_CHECKING Comment(const char* format, ...);
   void DeoptComment(const Deoptimizer::DeoptInfo& deopt_info);
+  static Deoptimizer::DeoptInfo MakeDeoptInfo(
+      LInstruction* instr, Deoptimizer::DeoptReason deopt_reason);
 
   bool GenerateBody();
   virtual void GenerateBodyInstructionPre(LInstruction* instr) {}
index c15e9db..a2563d8 100644 (file)
@@ -7,7 +7,6 @@
 #include "src/v8.h"
 
 #include "src/scopes.h"
-#include "src/serialize.h"
 
 #if V8_TARGET_ARCH_IA32
 #include "src/ia32/lithium-ia32.h"  // NOLINT
@@ -448,6 +447,10 @@ void LChunk::RegisterWeakObjectsInOptimizedCode(Handle<Code> code) const {
     }
   }
   for (int i = 0; i < maps.length(); i++) {
+    if (maps.at(i)->dependent_code()->number_of_entries(
+            DependentCode::kWeakCodeGroup) == 0) {
+      isolate()->heap()->AddRetainedMap(maps.at(i));
+    }
     Map::AddDependentCode(maps.at(i), DependentCode::kWeakCodeGroup, code);
   }
   for (int i = 0; i < objects.length(); i++) {
index e880cab..c03d8d3 100644 (file)
@@ -995,9 +995,6 @@ class LiteralFixer {
                             Handle<SharedFunctionInfo> shared_info,
                             Isolate* isolate) {
     int new_literal_count = compile_info_wrapper->GetLiteralCount();
-    if (new_literal_count > 0) {
-      new_literal_count += JSFunction::kLiteralsPrefixSize;
-    }
     int old_literal_count = shared_info->num_literals();
 
     if (old_literal_count == new_literal_count) {
@@ -1013,21 +1010,8 @@ class LiteralFixer {
           CollectJSFunctions(shared_info, isolate);
       for (int i = 0; i < function_instances->length(); i++) {
         Handle<JSFunction> fun(JSFunction::cast(function_instances->get(i)));
-        Handle<FixedArray> old_literals(fun->literals());
         Handle<FixedArray> new_literals =
             isolate->factory()->NewFixedArray(new_literal_count);
-        if (new_literal_count > 0) {
-          Handle<Context> native_context;
-          if (old_literals->length() >
-              JSFunction::kLiteralNativeContextIndex) {
-            native_context = Handle<Context>(
-                JSFunction::NativeContextFromLiterals(fun->literals()));
-          } else {
-            native_context = Handle<Context>(fun->context()->native_context());
-          }
-          new_literals->set(JSFunction::kLiteralNativeContextIndex,
-              *native_context);
-        }
         fun->set_literals(*new_literals);
       }
 
@@ -1075,7 +1059,7 @@ class LiteralFixer {
     void visit(JSFunction* fun) {
       FixedArray* literals = fun->literals();
       int len = literals->length();
-      for (int j = JSFunction::kLiteralsPrefixSize; j < len; j++) {
+      for (int j = 0; j < len; j++) {
         literals->set_undefined(j);
       }
     }
index 9f2eed1..1ae7b27 100644 (file)
@@ -21,7 +21,6 @@
 #include "src/macro-assembler.h"
 #include "src/perf-jit.h"
 #include "src/runtime-profiler.h"
-#include "src/serialize.h"
 #include "src/string-stream.h"
 #include "src/vm-state-inl.h"
 
@@ -876,27 +875,9 @@ void Logger::ApiEvent(const char* format, ...) {
 }
 
 
-void Logger::ApiNamedSecurityCheck(Object* key) {
+void Logger::ApiSecurityCheck() {
   if (!log_->IsEnabled() || !FLAG_log_api) return;
-  if (key->IsString()) {
-    SmartArrayPointer<char> str =
-        String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
-    ApiEvent("api,check-security,\"%s\"", str.get());
-  } else if (key->IsSymbol()) {
-    Symbol* symbol = Symbol::cast(key);
-    if (symbol->name()->IsUndefined()) {
-      ApiEvent("api,check-security,symbol(hash %x)", Symbol::cast(key)->Hash());
-    } else {
-      SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
-          DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
-      ApiEvent("api,check-security,symbol(\"%s\" hash %x)", str.get(),
-               Symbol::cast(key)->Hash());
-    }
-  } else if (key->IsUndefined()) {
-    ApiEvent("api,check-security,undefined");
-  } else {
-    ApiEvent("api,check-security,['no-name']");
-  }
+  ApiEvent("api,check-security");
 }
 
 
@@ -911,9 +892,8 @@ void Logger::SharedLibraryEvent(const std::string& library_path,
 }
 
 
-void Logger::CodeDeoptEvent(Code* code, int bailout_id, Address from,
-                            int fp_to_sp_delta) {
-  PROFILER_LOG(CodeDeoptEvent(code, bailout_id, from, fp_to_sp_delta));
+void Logger::CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) {
+  PROFILER_LOG(CodeDeoptEvent(code, pc, fp_to_sp_delta));
   if (!log_->IsEnabled() || !FLAG_log_internal_timer_events) return;
   Log::MessageBuilder msg(log_);
   int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
@@ -1029,12 +1009,6 @@ void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
 }
 
 
-void Logger::ApiIndexedSecurityCheck(uint32_t index) {
-  if (!log_->IsEnabled() || !FLAG_log_api) return;
-  ApiEvent("api,check-security,%u", index);
-}
-
-
 void Logger::ApiNamedPropertyAccess(const char* tag,
                                     JSObject* holder,
                                     Object* name) {
@@ -1412,8 +1386,6 @@ void Logger::SnapshotPositionEvent(Address addr, int pos) {
 
 
 void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
-  PROFILER_LOG(SharedFunctionInfoMoveEvent(from, to));
-
   if (!is_logging_code_events()) return;
   MoveEventInternal(SHARED_FUNC_MOVE_EVENT, from, to);
 }
@@ -1793,8 +1765,16 @@ static void AddIsolateIdIfNeeded(std::ostream& os,  // NOLINT
 
 static void PrepareLogFileName(std::ostream& os,  // NOLINT
                                Isolate* isolate, const char* file_name) {
-  AddIsolateIdIfNeeded(os, isolate);
+  int dir_separator_count = 0;
   for (const char* p = file_name; *p; p++) {
+    if (base::OS::isDirectorySeparator(*p)) dir_separator_count++;
+  }
+
+  for (const char* p = file_name; *p; p++) {
+    if (dir_separator_count == 0) {
+      AddIsolateIdIfNeeded(os, isolate);
+      dir_separator_count--;
+    }
     if (*p == '%') {
       p++;
       switch (*p) {
@@ -1820,6 +1800,7 @@ static void PrepareLogFileName(std::ostream& os,  // NOLINT
           break;
       }
     } else {
+      if (base::OS::isDirectorySeparator(*p)) dir_separator_count--;
       os << *p;
     }
   }
index bb7ff32..c0559e7 100644 (file)
@@ -210,8 +210,7 @@ class Logger {
 
 
   // ==== Events logged by --log-api. ====
-  void ApiNamedSecurityCheck(Object* key);
-  void ApiIndexedSecurityCheck(uint32_t index);
+  void ApiSecurityCheck();
   void ApiNamedPropertyAccess(const char* tag, JSObject* holder, Object* name);
   void ApiIndexedPropertyAccess(const char* tag,
                                 JSObject* holder,
@@ -292,8 +291,7 @@ class Logger {
                           uintptr_t start,
                           uintptr_t end);
 
-  void CodeDeoptEvent(Code* code, int bailout_id, Address from,
-                      int fp_to_sp_delta);
+  void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta);
   void CurrentTimeEvent();
 
   void TimerEvent(StartEnd se, const char* name);
index ffc02e7..a801e34 100644 (file)
@@ -31,17 +31,28 @@ JSReceiver* LookupIterator::NextHolder(Map* map) {
 }
 
 
-LookupIterator::State LookupIterator::LookupInHolder(Map* map,
-                                                     JSReceiver* holder) {
+LookupIterator::State LookupIterator::LookupInHolder(Map* const map,
+                                                     JSReceiver* const holder) {
   STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
   DisallowHeapAllocation no_gc;
+  if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
+    return LookupNonMaskingInterceptorInHolder(map, holder);
+  }
   switch (state_) {
     case NOT_FOUND:
       if (map->IsJSProxyMap()) return JSPROXY;
-      if (map->is_access_check_needed()) return ACCESS_CHECK;
+      if (map->is_access_check_needed() &&
+          !isolate_->IsInternallyUsedPropertyName(name_)) {
+        return ACCESS_CHECK;
+      }
     // Fall through.
     case ACCESS_CHECK:
-      if (check_interceptor() && map->has_named_interceptor()) {
+      if (exotic_index_state_ != ExoticIndexState::kNoIndex &&
+          IsIntegerIndexedExotic(holder)) {
+        return INTEGER_INDEXED_EXOTIC;
+      }
+      if (check_interceptor() && map->has_named_interceptor() &&
+          !SkipInterceptor(JSObject::cast(holder))) {
         return INTERCEPTOR;
       }
     // Fall through.
@@ -50,12 +61,12 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* map,
         NameDictionary* dict = JSObject::cast(holder)->property_dictionary();
         number_ = dict->FindEntry(name_);
         if (number_ == NameDictionary::kNotFound) return NOT_FOUND;
-        property_details_ = dict->DetailsAt(number_);
         if (holder->IsGlobalObject()) {
-          if (property_details_.IsDeleted()) return NOT_FOUND;
+          DCHECK(dict->ValueAt(number_)->IsPropertyCell());
           PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_));
           if (cell->value()->IsTheHole()) return NOT_FOUND;
         }
+        property_details_ = dict->DetailsAt(number_);
       } else {
         DescriptorArray* descriptors = map->instance_descriptors();
         number_ = descriptors->SearchWithCache(*name_, map);
@@ -72,6 +83,7 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* map,
     case ACCESSOR:
     case DATA:
       return NOT_FOUND;
+    case INTEGER_INDEXED_EXOTIC:
     case JSPROXY:
     case TRANSITION:
       UNREACHABLE();
@@ -79,6 +91,23 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* map,
   UNREACHABLE();
   return state_;
 }
+
+
+LookupIterator::State LookupIterator::LookupNonMaskingInterceptorInHolder(
+    Map* const map, JSReceiver* const holder) {
+  switch (state_) {
+    case NOT_FOUND:
+      if (check_interceptor() && map->has_named_interceptor() &&
+          !SkipInterceptor(JSObject::cast(holder))) {
+        return INTERCEPTOR;
+      }
+    // Fall through.
+    default:
+      return NOT_FOUND;
+  }
+  UNREACHABLE();
+  return state_;
+}
 }
 }  // namespace v8::internal
 
index 672c026..5a6c5da 100644 (file)
@@ -29,7 +29,13 @@ void LookupIterator::Next() {
   // Continue lookup if lookup on current holder failed.
   do {
     JSReceiver* maybe_holder = NextHolder(map);
-    if (maybe_holder == NULL) break;
+    if (maybe_holder == nullptr) {
+      if (interceptor_state_ == InterceptorState::kSkipNonMasking) {
+        RestartLookupForNonMaskingInterceptors();
+        return;
+      }
+      break;
+    }
     holder = maybe_holder;
     map = holder->map();
     state_ = LookupInHolder(map, holder);
@@ -42,11 +48,25 @@ void LookupIterator::Next() {
 }
 
 
-Handle<JSReceiver> LookupIterator::GetRoot() const {
-  if (receiver_->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver_);
-  Handle<Object> root =
-      handle(receiver_->GetRootMap(isolate_)->prototype(), isolate_);
-  CHECK(!root->IsNull());
+void LookupIterator::RestartLookupForNonMaskingInterceptors() {
+  interceptor_state_ = InterceptorState::kProcessNonMasking;
+  state_ = NOT_FOUND;
+  property_details_ = PropertyDetails::Empty();
+  number_ = DescriptorArray::kNotFound;
+  holder_ = initial_holder_;
+  holder_map_ = handle(holder_->map(), isolate_);
+  Next();
+}
+
+
+Handle<JSReceiver> LookupIterator::GetRoot(Handle<Object> receiver,
+                                           Isolate* isolate) {
+  if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver);
+  auto root = handle(receiver->GetRootMap(isolate)->prototype(), isolate);
+  if (root->IsNull()) {
+    unsigned int magic = 0xbbbbbbbb;
+    isolate->PushStackTraceAndDie(magic, *receiver, NULL, magic);
+  }
   return Handle<JSReceiver>::cast(root);
 }
 
@@ -72,14 +92,15 @@ bool LookupIterator::IsBootstrapping() const {
 }
 
 
-bool LookupIterator::HasAccess(v8::AccessType access_type) const {
+bool LookupIterator::HasAccess() const {
   DCHECK_EQ(ACCESS_CHECK, state_);
-  return isolate_->MayNamedAccess(GetHolder<JSObject>(), name_, access_type);
+  return isolate_->MayAccess(GetHolder<JSObject>());
 }
 
 
 void LookupIterator::ReloadPropertyInformation() {
   state_ = BEFORE_PROPERTY;
+  interceptor_state_ = InterceptorState::kUninitialized;
   state_ = LookupInHolder(*holder_map_, *holder_);
   DCHECK(IsFound() || holder_map_->is_dictionary_map());
 }
@@ -102,7 +123,8 @@ void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
   DCHECK(HolderIsReceiverOrHiddenPrototype());
   Handle<JSObject> holder = GetHolder<JSObject>();
   if (holder_map_->is_dictionary_map()) {
-    PropertyDetails details(attributes, v8::internal::DATA, 0);
+    PropertyDetails details(attributes, v8::internal::DATA, 0,
+                            PropertyCellType::kMutable);
     JSObject::SetNormalizedProperty(holder, name(), value, details);
   } else {
     holder_map_ = Map::ReconfigureExistingProperty(
@@ -120,9 +142,9 @@ void LookupIterator::PrepareTransitionToDataProperty(
     Handle<Object> value, PropertyAttributes attributes,
     Object::StoreFromKeyed store_mode) {
   if (state_ == TRANSITION) return;
-  DCHECK(state_ != LookupIterator::ACCESSOR);
+  DCHECK_NE(LookupIterator::ACCESSOR, state_);
+  DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, state_);
   DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype());
-  DCHECK(!IsSpecialNumericIndex());
   // Can only be called when the receiver is a JSObject. JSProxy has to be
   // handled via a trap. Adding properties to primitive values is not
   // observable.
@@ -182,14 +204,10 @@ void LookupIterator::TransitionToAccessorProperty(
 
   if (!holder_map_->is_dictionary_map()) return;
 
-  // We have to deoptimize since accesses to data properties may have been
-  // inlined without a corresponding map-check.
-  if (holder_map_->IsGlobalObjectMap()) {
-    Deoptimizer::DeoptimizeGlobalObject(*receiver);
-  }
 
   // Install the accessor into the dictionary-mode object.
-  PropertyDetails details(attributes, ACCESSOR_CONSTANT, 0);
+  PropertyDetails details(attributes, ACCESSOR_CONSTANT, 0,
+                          PropertyCellType::kMutable);
   Handle<AccessorPair> pair;
   if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) {
     pair = Handle<AccessorPair>::cast(GetAccessors());
@@ -241,6 +259,7 @@ Handle<Object> LookupIterator::FetchValue() const {
   if (holder_map_->is_dictionary_map()) {
     result = holder->property_dictionary()->ValueAt(number_);
     if (holder_map_->IsGlobalObjectMap()) {
+      DCHECK(result->IsPropertyCell());
       result = PropertyCell::cast(result)->value();
     }
   } else if (property_details_.type() == v8::internal::DATA) {
@@ -295,7 +314,8 @@ Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
   Handle<JSObject> holder = GetHolder<JSObject>();
   Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
   Object* value = global->property_dictionary()->ValueAt(dictionary_entry());
-  return Handle<PropertyCell>(PropertyCell::cast(value));
+  DCHECK(value->IsPropertyCell());
+  return handle(PropertyCell::cast(value));
 }
 
 
@@ -316,11 +336,11 @@ Handle<Object> LookupIterator::WriteDataValue(Handle<Object> value) {
   DCHECK_EQ(DATA, state_);
   Handle<JSObject> holder = GetHolder<JSObject>();
   if (holder_map_->is_dictionary_map()) {
-    NameDictionary* property_dictionary = holder->property_dictionary();
+    Handle<NameDictionary> property_dictionary =
+        handle(holder->property_dictionary());
     if (holder->IsGlobalObject()) {
-      Handle<PropertyCell> cell(
-          PropertyCell::cast(property_dictionary->ValueAt(dictionary_entry())));
-      value = PropertyCell::SetValueInferType(cell, value);
+      value = PropertyCell::UpdateCell(property_dictionary, dictionary_entry(),
+                                       value, property_details_);
     } else {
       property_dictionary->ValueAtPut(dictionary_entry(), *value);
     }
@@ -333,25 +353,23 @@ Handle<Object> LookupIterator::WriteDataValue(Handle<Object> value) {
 }
 
 
-bool LookupIterator::IsSpecialNumericIndex() const {
-  if (GetStoreTarget()->IsJSTypedArray() && name()->IsString()) {
+bool LookupIterator::IsIntegerIndexedExotic(JSReceiver* holder) {
+  DCHECK(exotic_index_state_ != ExoticIndexState::kNoIndex);
+  // Currently typed arrays are the only such objects.
+  if (!holder->IsJSTypedArray()) return false;
+  if (exotic_index_state_ == ExoticIndexState::kIndex) return true;
+  DCHECK(exotic_index_state_ == ExoticIndexState::kUninitialized);
+  bool result = false;
+  // Compute and cache result.
+  if (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;
-      }
+    if (name_string->length() != 0) {
+      result = IsNonArrayIndexInteger(*name_string);
     }
   }
-  return false;
+  exotic_index_state_ =
+      result ? ExoticIndexState::kIndex : ExoticIndexState::kNoIndex;
+  return result;
 }
 
 
@@ -359,4 +377,22 @@ void LookupIterator::InternalizeName() {
   if (name_->IsUniqueName()) return;
   name_ = factory()->InternalizeString(Handle<String>::cast(name_));
 }
+
+
+bool LookupIterator::SkipInterceptor(JSObject* holder) {
+  auto info = holder->GetNamedInterceptor();
+  // TODO(dcarney): check for symbol/can_intercept_symbols here as well.
+  if (info->non_masking()) {
+    switch (interceptor_state_) {
+      case InterceptorState::kUninitialized:
+        interceptor_state_ = InterceptorState::kSkipNonMasking;
+      // Fall through.
+      case InterceptorState::kSkipNonMasking:
+        return true;
+      case InterceptorState::kProcessNonMasking:
+        return false;
+    }
+  }
+  return interceptor_state_ == InterceptorState::kProcessNonMasking;
+}
 } }  // namespace v8::internal
index 5a5466e..f658b13 100644 (file)
@@ -31,6 +31,7 @@ class LookupIterator FINAL BASE_EMBEDDED {
 
   enum State {
     ACCESS_CHECK,
+    INTEGER_INDEXED_EXOTIC,
     INTERCEPTOR,
     JSPROXY,
     NOT_FOUND,
@@ -46,13 +47,16 @@ class LookupIterator FINAL BASE_EMBEDDED {
                  Configuration configuration = PROTOTYPE_CHAIN)
       : configuration_(ComputeConfiguration(configuration, name)),
         state_(NOT_FOUND),
-        property_details_(NONE, v8::internal::DATA, 0),
+        exotic_index_state_(ExoticIndexState::kUninitialized),
+        interceptor_state_(InterceptorState::kUninitialized),
+        property_details_(PropertyDetails::Empty()),
         isolate_(name->GetIsolate()),
         name_(name),
         receiver_(receiver),
+        holder_(GetRoot(receiver_, isolate_)),
+        holder_map_(holder_->map(), isolate_),
+        initial_holder_(holder_),
         number_(DescriptorArray::kNotFound) {
-    holder_ = GetRoot();
-    holder_map_ = handle(holder_->map(), isolate_);
     Next();
   }
 
@@ -61,12 +65,15 @@ class LookupIterator FINAL BASE_EMBEDDED {
                  Configuration configuration = PROTOTYPE_CHAIN)
       : configuration_(ComputeConfiguration(configuration, name)),
         state_(NOT_FOUND),
-        property_details_(NONE, v8::internal::DATA, 0),
+        exotic_index_state_(ExoticIndexState::kUninitialized),
+        interceptor_state_(InterceptorState::kUninitialized),
+        property_details_(PropertyDetails::Empty()),
         isolate_(name->GetIsolate()),
         name_(name),
-        holder_map_(holder->map(), isolate_),
         receiver_(receiver),
         holder_(holder),
+        holder_map_(holder_->map(), isolate_),
+        initial_holder_(holder_),
         number_(DescriptorArray::kNotFound) {
     Next();
   }
@@ -95,11 +102,11 @@ class LookupIterator FINAL BASE_EMBEDDED {
     DCHECK(IsFound());
     return Handle<T>::cast(holder_);
   }
-  Handle<JSReceiver> GetRoot() const;
+  static Handle<JSReceiver> GetRoot(Handle<Object> receiver, Isolate* isolate);
   bool HolderIsReceiverOrHiddenPrototype() const;
 
   /* ACCESS_CHECK */
-  bool HasAccess(v8::AccessType access_type) const;
+  bool HasAccess() const;
 
   /* PROPERTY */
   void PrepareForDataProperty(Handle<Object> value);
@@ -131,29 +138,29 @@ class LookupIterator FINAL BASE_EMBEDDED {
   int GetAccessorIndex() const;
   int GetConstantIndex() const;
   Handle<PropertyCell> GetPropertyCell() const;
-  Handle<PropertyCell> GetTransitionPropertyCell() const {
-    DCHECK_EQ(TRANSITION, state_);
-    return Handle<PropertyCell>::cast(transition_);
-  }
   Handle<Object> GetAccessors() const;
   Handle<Object> GetDataValue() const;
   // 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();
 
  private:
+  enum class InterceptorState {
+    kUninitialized,
+    kSkipNonMasking,
+    kProcessNonMasking
+  };
+
   Handle<Map> GetReceiverMap() const;
 
   MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map);
   inline State LookupInHolder(Map* map, JSReceiver* holder);
+  void RestartLookupForNonMaskingInterceptors();
+  State LookupNonMaskingInterceptorInHolder(Map* map, JSReceiver* holder);
   Handle<Object> FetchValue() const;
   void ReloadPropertyInformation();
+  bool SkipInterceptor(JSObject* holder);
 
   bool IsBootstrapping() const;
 
@@ -185,19 +192,24 @@ class LookupIterator FINAL BASE_EMBEDDED {
     }
   }
 
+  enum class ExoticIndexState { kUninitialized, kNoIndex, kIndex };
+  bool IsIntegerIndexedExotic(JSReceiver* holder);
+
   // If configuration_ becomes mutable, update
   // HolderIsReceiverOrHiddenPrototype.
-  Configuration configuration_;
+  const Configuration configuration_;
   State state_;
   bool has_property_;
+  ExoticIndexState exotic_index_state_;
+  InterceptorState interceptor_state_;
   PropertyDetails property_details_;
-  Isolate* isolate_;
+  Isolate* const isolate_;
   Handle<Name> name_;
-  Handle<Map> holder_map_;
   Handle<Object> transition_;
-  Handle<Object> receiver_;
+  const Handle<Object> receiver_;
   Handle<JSReceiver> holder_;
-
+  Handle<Map> holder_map_;
+  const Handle<JSReceiver> initial_holder_;
   int number_;
 };
 
index 93a5563..324702b 100644 (file)
@@ -69,6 +69,11 @@ const kMaxYear  = 1000000;
 const kMinMonth = -10000000;
 const kMaxMonth = 10000000;
 
+# Safe maximum number of arguments to push to stack, when multiplied by
+# pointer size. Used by Function.prototype.apply(), Reflect.apply() and
+# Reflect.construct().
+const kSafeArgumentsLength = 0x800000;
+
 # Strict mode flags for passing to %SetProperty
 const kSloppyMode = 0;
 const kStrictMode = 1;
@@ -111,7 +116,6 @@ macro IS_GENERATOR(arg)         = (%_ClassOf(arg) === 'Generator');
 macro IS_SET_ITERATOR(arg)      = (%_ClassOf(arg) === 'Set Iterator');
 macro IS_MAP_ITERATOR(arg)      = (%_ClassOf(arg) === 'Map Iterator');
 macro IS_UNDETECTABLE(arg)      = (%_IsUndetectableObject(arg));
-macro FLOOR(arg)                = $floor(arg);
 
 # Macro for ECMAScript 5 queries of the type:
 # "Type(O) is object."
index cc478d3..b802de0 100644 (file)
@@ -2,58 +2,59 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-"use strict";
+var rngstate;  // Initialized to a Uint32Array during genesis.
 
-// This file relies on the fact that the following declarations have been made
-// in runtime.js:
-// var $Object = global.Object;
+var $abs;
+var $exp;
+var $floor;
+var $max;
+var $min;
 
-// Keep reference to original values of some global properties.  This
-// has the added benefit that the code in this file is isolated from
-// changes to these properties.
-var $floor = MathFloor;
-var $abs = MathAbs;
+(function() {
 
-// Instance class name can only be set on functions. That is the only
-// purpose for MathConstructor.
-function MathConstructor() {}
-var $Math = new MathConstructor();
+"use strict";
 
-// -------------------------------------------------------------------
+%CheckIsBootstrapping();
+
+var GlobalObject = global.Object;
+var GlobalArray = global.Array;
+
+//-------------------------------------------------------------------
 
 // ECMA 262 - 15.8.2.1
 function MathAbs(x) {
-  if (%_IsSmi(x)) return x >= 0 ? x : -x;
-  x = TO_NUMBER_INLINE(x);
-  if (x === 0) return 0;  // To handle -0.
-  return x > 0 ? x : -x;
+  x = +x;
+  if (x > 0) return x;
+  return 0 - x;
 }
 
 // ECMA 262 - 15.8.2.2
 function MathAcosJS(x) {
-  return %MathAcos(TO_NUMBER_INLINE(x));
+  return %_MathAcos(+x);
 }
 
 // ECMA 262 - 15.8.2.3
 function MathAsinJS(x) {
-  return %MathAsin(TO_NUMBER_INLINE(x));
+  return %_MathAsin(+x);
 }
 
 // ECMA 262 - 15.8.2.4
 function MathAtanJS(x) {
-  return %MathAtan(TO_NUMBER_INLINE(x));
+  return %_MathAtan(+x);
 }
 
 // ECMA 262 - 15.8.2.5
 // The naming of y and x matches the spec, as does the order in which
 // ToNumber (valueOf) is called.
 function MathAtan2JS(y, x) {
-  return %MathAtan2(TO_NUMBER_INLINE(y), TO_NUMBER_INLINE(x));
+  y = +y;
+  x = +x;
+  return %_MathAtan2(y, x);
 }
 
 // ECMA 262 - 15.8.2.6
 function MathCeil(x) {
-  return -MathFloor(-x);
+  return -%_MathFloor(-x);
 }
 
 // ECMA 262 - 15.8.2.8
@@ -62,19 +63,8 @@ function MathExp(x) {
 }
 
 // ECMA 262 - 15.8.2.9
-function MathFloor(x) {
-  x = TO_NUMBER_INLINE(x);
-  // It's more common to call this with a positive number that's out
-  // of range than negative numbers; check the upper bound first.
-  if (x < 0x80000000 && x > 0) {
-    // Numbers in the range [0, 2^31) can be floored by converting
-    // them to an unsigned 32-bit value using the shift operator.
-    // We avoid doing so for -0, because the result of Math.floor(-0)
-    // has to be -0, which wouldn't be the case with the shift.
-    return TO_UINT32(x);
-  } else {
-    return %MathFloorRT(x);
-  }
+function MathFloorJS(x) {
+  return %_MathFloor(+x);
 }
 
 // ECMA 262 - 15.8.2.10
@@ -137,12 +127,11 @@ function MathMin(arg1, arg2) {  // length == 2
 }
 
 // ECMA 262 - 15.8.2.13
-function MathPow(x, y) {
+function MathPowJS(x, y) {
   return %_MathPow(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y));
 }
 
 // ECMA 262 - 15.8.2.14
-var rngstate;  // Initialized to a Uint32Array during genesis.
 function MathRandom() {
   var r0 = (MathImul(18030, rngstate[0] & 0xFFFF) + (rngstate[0] >>> 16)) | 0;
   rngstate[0] = r0;
@@ -159,8 +148,8 @@ function MathRound(x) {
 }
 
 // ECMA 262 - 15.8.2.17
-function MathSqrt(x) {
-  return %_MathSqrtRT(TO_NUMBER_INLINE(x));
+function MathSqrtJS(x) {
+  return %_MathSqrt(+x);
 }
 
 // Non-standard extension.
@@ -170,7 +159,7 @@ function MathImul(x, y) {
 
 // ES6 draft 09-27-13, section 20.2.2.28.
 function MathSign(x) {
-  x = TO_NUMBER_INLINE(x);
+  x = +x;
   if (x > 0) return 1;
   if (x < 0) return -1;
   // -0, 0 or NaN.
@@ -179,9 +168,9 @@ function MathSign(x) {
 
 // ES6 draft 09-27-13, section 20.2.2.34.
 function MathTrunc(x) {
-  x = TO_NUMBER_INLINE(x);
-  if (x > 0) return MathFloor(x);
-  if (x < 0) return MathCeil(x);
+  x = +x;
+  if (x > 0) return %_MathFloor(x);
+  if (x < 0) return -%_MathFloor(-x);
   // -0, 0 or NaN.
   return x;
 }
@@ -203,9 +192,9 @@ function MathAsinh(x) {
   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
   // Idempotent for NaN, +/-0 and +/-Infinity.
   if (x === 0 || !NUMBER_IS_FINITE(x)) return x;
-  if (x > 0) return MathLog(x + MathSqrt(x * x + 1));
+  if (x > 0) return MathLog(x + %_MathSqrt(x * x + 1));
   // This is to prevent numerical errors caused by large negative x.
-  return -MathLog(-x + MathSqrt(x * x + 1));
+  return -MathLog(-x + %_MathSqrt(x * x + 1));
 }
 
 // ES6 draft 09-27-13, section 20.2.2.3.
@@ -214,7 +203,7 @@ function MathAcosh(x) {
   if (x < 1) return NAN;
   // Idempotent for NaN and +Infinity.
   if (!NUMBER_IS_FINITE(x)) return x;
-  return MathLog(x + MathSqrt(x + 1) * MathSqrt(x - 1));
+  return MathLog(x + %_MathSqrt(x + 1) * %_MathSqrt(x - 1));
 }
 
 // ES6 draft 09-27-13, section 20.2.2.7.
@@ -256,7 +245,7 @@ function MathHypot(x, y) {  // Function length is 2.
     compensation = (preliminary - sum) - summand;
     sum = preliminary;
   }
-  return MathSqrt(sum) * max;
+  return %_MathSqrt(sum) * max;
 }
 
 // ES6 draft 09-27-13, section 20.2.2.16.
@@ -265,17 +254,8 @@ function MathFroundJS(x) {
 }
 
 // ES6 draft 07-18-14, section 20.2.2.11
-function MathClz32(x) {
-  x = ToUint32(TO_NUMBER_INLINE(x));
-  if (x == 0) return 32;
-  var result = 0;
-  // Binary search.
-  if ((x & 0xFFFF0000) === 0) { x <<= 16; result += 16; };
-  if ((x & 0xFF000000) === 0) { x <<=  8; result +=  8; };
-  if ((x & 0xF0000000) === 0) { x <<=  4; result +=  4; };
-  if ((x & 0xC0000000) === 0) { x <<=  2; result +=  2; };
-  if ((x & 0x80000000) === 0) { x <<=  1; result +=  1; };
-  return result;
+function MathClz32JS(x) {
+  return %_MathClz32(x >>> 0);
 }
 
 // ES6 draft 09-27-13, section 20.2.2.9.
@@ -293,7 +273,7 @@ macro NEWTON_ITERATION_CBRT(x, approx)
 endmacro
 
 function CubeRoot(x) {
-  var approx_hi = MathFloor(%_DoubleHi(x) / 3) + 0x2A9F7893;
+  var approx_hi = MathFloorJS(%_DoubleHi(x) / 3) + 0x2A9F7893;
   var approx = %_ConstructDouble(approx_hi, 0);
   approx = NEWTON_ITERATION_CBRT(x, approx);
   approx = NEWTON_ITERATION_CBRT(x, approx);
@@ -303,75 +283,83 @@ function CubeRoot(x) {
 
 // -------------------------------------------------------------------
 
-function SetUpMath() {
-  %CheckIsBootstrapping();
-
-  %InternalSetPrototype($Math, $Object.prototype);
-  %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.
-    "E", 2.7182818284590452354,
-    // ECMA-262, section 15.8.1.2.
-    "LN10", 2.302585092994046,
-    // ECMA-262, section 15.8.1.3.
-    "LN2", 0.6931471805599453,
-    // ECMA-262, section 15.8.1.4.
-    "LOG2E", 1.4426950408889634,
-    "LOG10E", 0.4342944819032518,
-    "PI", 3.1415926535897932,
-    "SQRT1_2", 0.7071067811865476,
-    "SQRT2", 1.4142135623730951
-  ));
-
-  // Set up non-enumerable functions of the Math object and
-  // set their names.
-  InstallFunctions($Math, DONT_ENUM, $Array(
-    "random", MathRandom,
-    "abs", MathAbs,
-    "acos", MathAcosJS,
-    "asin", MathAsinJS,
-    "atan", MathAtanJS,
-    "ceil", MathCeil,
-    "cos", MathCos,       // implemented by third_party/fdlibm
-    "exp", MathExp,
-    "floor", MathFloor,
-    "log", MathLog,
-    "round", MathRound,
-    "sin", MathSin,       // implemented by third_party/fdlibm
-    "sqrt", MathSqrt,
-    "tan", MathTan,       // implemented by third_party/fdlibm
-    "atan2", MathAtan2JS,
-    "pow", MathPow,
-    "max", MathMax,
-    "min", MathMin,
-    "imul", MathImul,
-    "sign", MathSign,
-    "trunc", MathTrunc,
-    "sinh", MathSinh,     // implemented by third_party/fdlibm
-    "cosh", MathCosh,     // implemented by third_party/fdlibm
-    "tanh", MathTanh,
-    "asinh", MathAsinh,
-    "acosh", MathAcosh,
-    "atanh", MathAtanh,
-    "log10", MathLog10,   // implemented by third_party/fdlibm
-    "log2", MathLog2,     // implemented by third_party/fdlibm
-    "hypot", MathHypot,
-    "fround", MathFroundJS,
-    "clz32", MathClz32,
-    "cbrt", MathCbrt,
-    "log1p", MathLog1p,   // implemented by third_party/fdlibm
-    "expm1", MathExpm1    // implemented by third_party/fdlibm
-  ));
-
-  %SetInlineBuiltinFlag(MathCeil);
-  %SetInlineBuiltinFlag(MathRandom);
-  %SetInlineBuiltinFlag(MathSin);
-  %SetInlineBuiltinFlag(MathCos);
-}
+// Instance class name can only be set on functions. That is the only
+// purpose for MathConstructor.
+function MathConstructor() {}
 
-SetUpMath();
+var Math = new MathConstructor();
+
+%InternalSetPrototype(Math, GlobalObject.prototype);
+%AddNamedProperty(global, "Math", Math, DONT_ENUM);
+%FunctionSetInstanceClassName(MathConstructor, 'Math');
+
+%AddNamedProperty(Math, symbolToStringTag, "Math", READ_ONLY | DONT_ENUM);
+
+// Set up math constants.
+InstallConstants(Math, GlobalArray(
+  // ECMA-262, section 15.8.1.1.
+  "E", 2.7182818284590452354,
+  // ECMA-262, section 15.8.1.2.
+  "LN10", 2.302585092994046,
+  // ECMA-262, section 15.8.1.3.
+  "LN2", 0.6931471805599453,
+  // ECMA-262, section 15.8.1.4.
+  "LOG2E", 1.4426950408889634,
+  "LOG10E", 0.4342944819032518,
+  "PI", 3.1415926535897932,
+  "SQRT1_2", 0.7071067811865476,
+  "SQRT2", 1.4142135623730951
+));
+
+// Set up non-enumerable functions of the Math object and
+// set their names.
+InstallFunctions(Math, DONT_ENUM, GlobalArray(
+  "random", MathRandom,
+  "abs", MathAbs,
+  "acos", MathAcosJS,
+  "asin", MathAsinJS,
+  "atan", MathAtanJS,
+  "ceil", MathCeil,
+  "exp", MathExp,
+  "floor", MathFloorJS,
+  "log", MathLog,
+  "round", MathRound,
+  "sqrt", MathSqrtJS,
+  "atan2", MathAtan2JS,
+  "pow", MathPowJS,
+  "max", MathMax,
+  "min", MathMin,
+  "imul", MathImul,
+  "sign", MathSign,
+  "trunc", MathTrunc,
+  "tanh", MathTanh,
+  "asinh", MathAsinh,
+  "acosh", MathAcosh,
+  "atanh", MathAtanh,
+  "hypot", MathHypot,
+  "fround", MathFroundJS,
+  "clz32", MathClz32JS,
+  "cbrt", MathCbrt
+));
+
+%SetInlineBuiltinFlag(MathAbs);
+%SetInlineBuiltinFlag(MathAcosJS);
+%SetInlineBuiltinFlag(MathAsinJS);
+%SetInlineBuiltinFlag(MathAtanJS);
+%SetInlineBuiltinFlag(MathAtan2JS);
+%SetInlineBuiltinFlag(MathCeil);
+%SetInlineBuiltinFlag(MathClz32JS);
+%SetInlineBuiltinFlag(MathFloorJS);
+%SetInlineBuiltinFlag(MathRandom);
+%SetInlineBuiltinFlag(MathSign);
+%SetInlineBuiltinFlag(MathSqrtJS);
+%SetInlineBuiltinFlag(MathTrunc);
+
+// Expose to the global scope.
+$abs = MathAbs;
+$exp = MathExp;
+$floor = MathFloorJS;
+$max = MathMax;
+$min = MathMin;
+
+})();
index b49556c..95110bb 100644 (file)
@@ -8,7 +8,8 @@ var kMessages = {
   // Error
   cyclic_proto:                  ["Cyclic __proto__ value"],
   code_gen_from_strings:         ["%0"],
-  constructor_special_method:    ["Class constructor may not be an accessor"],
+  constructor_is_generator:      ["Class constructor may not be a generator"],
+  constructor_is_accessor:       ["Class constructor may not be an accessor"],
   // TypeError
   generator_running:             ["Generator is already running"],
   unexpected_token:              ["Unexpected token ", "%0"],
@@ -24,6 +25,7 @@ var kMessages = {
   unterminated_regexp:           ["Invalid regular expression: missing /"],
   unterminated_template:         ["Unterminated template literal"],
   unterminated_template_expr:    ["Missing } in template expression"],
+  unterminated_arg_list:         ["missing ) after argument list"],
   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"],
@@ -50,6 +52,8 @@ var kMessages = {
   no_setter_in_callback:         ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
   apply_non_function:            ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
   apply_wrong_args:              ["Function.prototype.apply: Arguments list has wrong type"],
+  reflect_apply_wrong_args:      ["Reflect.apply: Arguments list has wrong type"],
+  reflect_construct_wrong_args:  ["Reflect.construct: Arguments list has wrong type"],
   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"],
@@ -80,7 +84,7 @@ var kMessages = {
   observe_non_object:            ["Object.", "%0", " cannot ", "%0", " non-object"],
   observe_non_function:          ["Object.", "%0", " cannot deliver to non-function"],
   observe_callback_frozen:       ["Object.observe cannot deliver to a frozen function object"],
-  observe_invalid_accept:        ["Object.observe accept must be an array of strings."],
+  observe_invalid_accept:        ["Third argument to Object.observe must be an array of strings."],
   observe_type_non_string:       ["Invalid changeRecord with non-string 'type' property"],
   observe_perform_non_string:    ["Invalid non-string changeType"],
   observe_perform_non_function:  ["Cannot perform non-function"],
@@ -155,29 +159,36 @@ var kMessages = {
   template_octal_literal:        ["Octal literals are not allowed in template strings."],
   strict_delete:                 ["Delete of an unqualified identifier in strict mode."],
   strict_delete_property:        ["Cannot delete property '", "%0", "' of ", "%1"],
-  strict_const:                  ["Use of const in strict mode."],
   strict_function:               ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
   strict_read_only_property:     ["Cannot assign to read only property '", "%0", "' of ", "%1"],
   strict_cannot_assign:          ["Cannot assign to read only '", "%0", "' in strict mode"],
   strict_poison_pill:            ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
   strict_caller:                 ["Illegal access to a strict mode caller function."],
-  strong_arguments:              ["Please don't use 'arguments' in strong mode, use '...args' instead"],
-  strong_equal:                  ["Please don't use '==' or '!=' in strong mode, use '===' or '!==' instead"],
-  strong_delete:                 ["Please don't use 'delete' in strong mode, use maps or sets instead"],
-  strong_var:                    ["Please don't use 'var' in strong mode, use 'let' or 'const' instead"],
-  strong_for_in:                 ["Please don't use 'for'-'in' loops in strong mode, use 'for'-'of' instead"],
-  strong_empty:                  ["Please don't use empty sub-statements in strong mode, make them explicit with '{}' instead"],
+  strong_ellision:               ["In strong mode, arrays with holes are deprecated, use maps instead"],
+  strong_arguments:              ["In strong mode, 'arguments' is deprecated, use '...args' instead"],
+  strong_equal:                  ["In strong mode, '==' and '!=' are deprecated, use '===' and '!==' instead"],
+  strong_delete:                 ["In strong mode, 'delete' is deprecated, use maps or sets instead"],
+  strong_var:                    ["In strong mode, 'var' is deprecated, use 'let' or 'const' instead"],
+  strong_for_in:                 ["In strong mode, 'for'-'in' loops are deprecated, use 'for'-'of' instead"],
+  strong_empty:                  ["In strong mode, empty sub-statements are deprecated, make them explicit with '{}' instead"],
+  strong_use_before_declaration: ["In strong mode, declaring variable '", "%0", "' before its use is required"],
+  strong_unbound_global:         ["In strong mode, using an undeclared global variable '", "%0", "' is not allowed"],
+  strong_super_call_missing:     ["In strong mode, invoking the super constructor in a subclass is required"],
+  strong_super_call_duplicate:   ["In strong mode, invoking the super constructor multiple times is deprecated"],
+  strong_super_call_nested:      ["In strong mode, invoking the super constructor nested inside another statement or expression is deprecated"],
+  strong_constructor_return_value: ["In strong mode, returning a value from a constructor is deprecated"],
+  strong_constructor_return_misplaced: ["In strong mode, returning from a constructor before its super constructor invocation is deprecated"],
   sloppy_lexical:                ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode"],
   malformed_arrow_function_parameter_list: ["Malformed arrow function parameter list"],
   generator_poison_pill:         ["'caller' and 'arguments' properties may not be accessed on generator functions."],
   cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"],
   redef_external_array_element:  ["Cannot redefine a property of an object with external array elements"],
-  harmony_const_assign:          ["Assignment to constant variable."],
+  const_assign:                  ["Assignment to constant variable."],
   symbol_to_string:              ["Cannot convert a Symbol value to a string"],
   symbol_to_primitive:           ["Cannot convert a Symbol wrapper object to a primitive value"],
   symbol_to_number:              ["Cannot convert a Symbol value to a number"],
-  invalid_module_path:           ["Module does not export '", "%0", "', or export is not itself a module"],
   module_export_undefined:       ["Export '", "%0", "' is not defined in module"],
+  duplicate_export:              ["Duplicate export of '", "%0", "'"],
   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"],
@@ -232,7 +243,7 @@ function NoSideEffectToString(obj) {
     }
     return str;
   }
-  if (IS_SYMBOL(obj)) return %_CallFunction(obj, SymbolToString);
+  if (IS_SYMBOL(obj)) return %_CallFunction(obj, $symbolToString);
   if (IS_OBJECT(obj)
       && %GetDataProperty(obj, "toString") === DefaultObjectToString) {
     var constructor = %GetDataProperty(obj, "constructor");
@@ -342,7 +353,6 @@ function GetSourceLine(message) {
   var start_position = %MessageGetStartPosition(message);
   var location = script.locationFromPosition(start_position, true);
   if (location == null) return "";
-  location.restrict();
   return location.sourceText();
 }
 
@@ -439,7 +449,7 @@ function ScriptLocationFromPosition(position,
   var line_ends = this.line_ends;
   var start = line == 0 ? 0 : line_ends[line - 1] + 1;
   var end = line_ends[line];
-  if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
+  if (end > 0 && %_CallFunction(this.source, end - 1, $stringCharAt) == '\r') {
     end--;
   }
   var column = position - start;
@@ -562,7 +572,7 @@ function ScriptSourceLine(opt_line) {
   var line_ends = this.line_ends;
   var start = line == 0 ? 0 : line_ends[line - 1] + 1;
   var end = line_ends[line];
-  return %_CallFunction(this.source, start, end, StringSubstring);
+  return %_CallFunction(this.source, start, end, $stringSubstring);
 }
 
 
@@ -643,57 +653,6 @@ function SourceLocation(script, position, line, column, start, end) {
   this.end = end;
 }
 
-var kLineLengthLimit = 78;
-
-/**
- * Restrict source location start and end positions to make the source slice
- * no more that a certain number of characters wide.
- * @param {number} opt_limit The with limit of the source text with a default
- *     of 78
- * @param {number} opt_before The number of characters to prefer before the
- *     position with a default value of 10 less that the limit
- */
-function SourceLocationRestrict(opt_limit, opt_before) {
-  // Find the actual limit to use.
-  var limit;
-  var before;
-  if (!IS_UNDEFINED(opt_limit)) {
-    limit = opt_limit;
-  } else {
-    limit = kLineLengthLimit;
-  }
-  if (!IS_UNDEFINED(opt_before)) {
-    before = opt_before;
-  } else {
-    // If no before is specified center for small limits and perfer more source
-    // before the the position that after for longer limits.
-    if (limit <= 20) {
-      before = $floor(limit / 2);
-    } else {
-      before = limit - 10;
-    }
-  }
-  if (before >= limit) {
-    before = limit - 1;
-  }
-
-  // If the [start, end[ interval is too big we restrict
-  // it in one or both ends. We make sure to always produce
-  // restricted intervals of maximum allowed size.
-  if (this.end - this.start > limit) {
-    var start_limit = this.position - before;
-    var end_limit = this.position + limit - before;
-    if (this.start < start_limit && end_limit < this.end) {
-      this.start = start_limit;
-      this.end = end_limit;
-    } else if (this.start < start_limit) {
-      this.start = this.end - limit;
-    } else {
-      this.end = this.start + limit;
-    }
-  }
-}
-
 
 /**
  * Get the source text for a SourceLocation
@@ -704,14 +663,13 @@ function SourceLocationSourceText() {
   return %_CallFunction(this.script.source,
                         this.start,
                         this.end,
-                        StringSubstring);
+                        $stringSubstring);
 }
 
 
 SetUpLockedPrototype(SourceLocation,
   $Array("script", "position", "line", "column", "start", "end"),
   $Array(
-    "restrict", SourceLocationRestrict,
     "sourceText", SourceLocationSourceText
  )
 );
@@ -752,7 +710,7 @@ function SourceSliceSourceText() {
   return %_CallFunction(this.script.source,
                         this.from_position,
                         this.to_position,
-                        StringSubstring);
+                        $stringSubstring);
 }
 
 SetUpLockedPrototype(SourceSlice,
@@ -768,7 +726,6 @@ function GetPositionInLine(message) {
   var start_position = %MessageGetStartPosition(message);
   var location = script.locationFromPosition(start_position, false);
   if (location == null) return -1;
-  location.restrict();
   return start_position - location.start;
 }
 
@@ -830,16 +787,13 @@ function CallSiteGetFunction() {
 
 function CallSiteGetFunctionName() {
   // See if the function knows its own name
-  var name = GET_PRIVATE(this, CallSiteFunctionKey).name;
-  if (name) {
-    return name;
-  }
-  name = %FunctionGetInferredName(GET_PRIVATE(this, CallSiteFunctionKey));
+  var fun = GET_PRIVATE(this, CallSiteFunctionKey);
+  var name = %FunctionGetDebugName(fun);
   if (name) {
     return name;
   }
   // Maybe this is an evaluation?
-  var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
+  var script = %FunctionGetScript(fun);
   if (script && script.compilation_type == COMPILATION_TYPE_EVAL) {
     return "eval";
   }
@@ -966,12 +920,12 @@ function CallSiteToString() {
     var methodName = this.getMethodName();
     if (functionName) {
       if (typeName &&
-          %_CallFunction(functionName, typeName, StringIndexOfJS) != 0) {
+          %_CallFunction(functionName, typeName, $stringIndexOf) != 0) {
         line += typeName + ".";
       }
       line += functionName;
       if (methodName &&
-          (%_CallFunction(functionName, "." + methodName, StringIndexOfJS) !=
+          (%_CallFunction(functionName, "." + methodName, $stringIndexOf) !=
            functionName.length - methodName.length - 1)) {
         line += " [as " + methodName + "]";
       }
index 1fdb3e9..7b6b3f8 100644 (file)
@@ -200,6 +200,39 @@ Address Assembler::break_address_from_return_address(Address pc) {
 }
 
 
+void Assembler::set_target_internal_reference_encoded_at(Address pc,
+                                                         Address target) {
+  // Encoded internal references are lui/ori load of 32-bit abolute address.
+  Instr instr_lui = Assembler::instr_at(pc + 0 * Assembler::kInstrSize);
+  Instr instr_ori = Assembler::instr_at(pc + 1 * Assembler::kInstrSize);
+  DCHECK(Assembler::IsLui(instr_lui));
+  DCHECK(Assembler::IsOri(instr_ori));
+  instr_lui &= ~kImm16Mask;
+  instr_ori &= ~kImm16Mask;
+  int32_t imm = reinterpret_cast<int32_t>(target);
+  DCHECK((imm & 3) == 0);
+  Assembler::instr_at_put(pc + 0 * Assembler::kInstrSize,
+                          instr_lui | ((imm >> kLuiShift) & kImm16Mask));
+  Assembler::instr_at_put(pc + 1 * Assembler::kInstrSize,
+                          instr_ori | (imm & kImm16Mask));
+
+  // Currently used only by deserializer, and all code will be flushed
+  // after complete deserialization, no need to flush on each reference.
+}
+
+
+void Assembler::deserialization_set_target_internal_reference_at(
+    Address pc, Address target, RelocInfo::Mode mode) {
+  if (mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
+    DCHECK(IsLui(instr_at(pc)));
+    set_target_internal_reference_encoded_at(pc, target);
+  } else {
+    DCHECK(mode == RelocInfo::INTERNAL_REFERENCE);
+    Memory::Address_at(pc) = target;
+  }
+}
+
+
 Object* RelocInfo::target_object() {
   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
   return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_));
@@ -229,12 +262,35 @@ void RelocInfo::set_target_object(Object* target,
 }
 
 
-Address RelocInfo::target_reference() {
+Address RelocInfo::target_external_reference() {
   DCHECK(rmode_ == EXTERNAL_REFERENCE);
   return Assembler::target_address_at(pc_, host_);
 }
 
 
+Address RelocInfo::target_internal_reference() {
+  if (rmode_ == INTERNAL_REFERENCE) {
+    return Memory::Address_at(pc_);
+  } else {
+    // Encoded internal references are lui/ori load of 32-bit abolute address.
+    DCHECK(rmode_ == INTERNAL_REFERENCE_ENCODED);
+    Instr instr_lui = Assembler::instr_at(pc_ + 0 * Assembler::kInstrSize);
+    Instr instr_ori = Assembler::instr_at(pc_ + 1 * Assembler::kInstrSize);
+    DCHECK(Assembler::IsLui(instr_lui));
+    DCHECK(Assembler::IsOri(instr_ori));
+    int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
+    imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
+    return reinterpret_cast<Address>(imm);
+  }
+}
+
+
+Address RelocInfo::target_internal_reference_address() {
+  DCHECK(rmode_ == INTERNAL_REFERENCE || rmode_ == INTERNAL_REFERENCE_ENCODED);
+  return reinterpret_cast<Address>(pc_);
+}
+
+
 Address RelocInfo::target_runtime_entry(Assembler* origin) {
   DCHECK(IsRuntimeEntry(rmode_));
   return target_address();
@@ -307,8 +363,8 @@ Address RelocInfo::call_address() {
   DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
   // The pc_ offset of 0 assumes mips patched return sequence per
-  // debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or
-  // debug break slot per BreakLocationIterator::SetDebugBreakAtSlot().
+  // debug-mips.cc BreakLocation::SetDebugBreakAtReturn(), or
+  // debug break slot per BreakLocation::SetDebugBreakAtSlot().
   return Assembler::target_address_at(pc_, host_);
 }
 
@@ -317,8 +373,8 @@ void RelocInfo::set_call_address(Address target) {
   DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
   // The pc_ offset of 0 assumes mips patched return sequence per
-  // debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or
-  // debug break slot per BreakLocationIterator::SetDebugBreakAtSlot().
+  // debug-mips.cc BreakLocation::SetDebugBreakAtReturn(), or
+  // debug break slot per BreakLocation::SetDebugBreakAtSlot().
   Assembler::set_target_address_at(pc_, host_, target);
   if (host() != NULL) {
     Object* target_code = Code::GetCodeFromTargetAddress(target);
@@ -346,11 +402,16 @@ void RelocInfo::set_call_object(Object* target) {
 
 
 void RelocInfo::WipeOut() {
-  DCHECK(IsEmbeddedObject(rmode_) ||
-         IsCodeTarget(rmode_) ||
-         IsRuntimeEntry(rmode_) ||
-         IsExternalReference(rmode_));
-  Assembler::set_target_address_at(pc_, host_, NULL);
+  DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
+         IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
+         IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_));
+  if (IsInternalReference(rmode_)) {
+    Memory::Address_at(pc_) = NULL;
+  } else if (IsInternalReferenceEncoded(rmode_)) {
+    Assembler::set_target_internal_reference_encoded_at(pc_, nullptr);
+  } else {
+    Assembler::set_target_address_at(pc_, host_, NULL);
+  }
 }
 
 
@@ -383,6 +444,9 @@ void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
     visitor->VisitCell(this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     visitor->VisitExternalReference(this);
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE ||
+             mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
+    visitor->VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     visitor->VisitCodeAgeSequence(this);
   } else if (((RelocInfo::IsJSReturn(mode) &&
@@ -408,6 +472,9 @@ void RelocInfo::Visit(Heap* heap) {
     StaticVisitor::VisitCell(heap, this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     StaticVisitor::VisitExternalReference(this);
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE ||
+             mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
+    StaticVisitor::VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     StaticVisitor::VisitCodeAgeSequence(heap, this);
   } else if (heap->isolate()->debug()->has_break_points() &&
index e7cfd57..c26a851 100644 (file)
@@ -40,7 +40,6 @@
 #include "src/base/bits.h"
 #include "src/base/cpu.h"
 #include "src/mips/assembler-mips-inl.h"
-#include "src/serialize.h"
 
 namespace v8 {
 namespace internal {
@@ -214,27 +213,6 @@ bool RelocInfo::IsInConstantPool() {
 }
 
 
-// Patch the code at the current address with the supplied instructions.
-void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
-  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_MIPS();
-}
-
-
 // -----------------------------------------------------------------------------
 // Implementation of Operand and MemOperand.
 // See assembler-mips-inl.h for inlined constructors.
@@ -663,14 +641,14 @@ bool Assembler::IsAndImmediate(Instr instr) {
 }
 
 
-int Assembler::target_at(int32_t pos, bool is_internal) {
+int Assembler::target_at(int pos, bool is_internal) {
   Instr instr = instr_at(pos);
   if (is_internal) {
     if (instr == 0) {
       return kEndOfChain;
     } else {
       int32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
-      int32_t delta = instr_address - instr;
+      int delta = static_cast<int>(instr_address - instr);
       DCHECK(pos > delta);
       return pos - delta;
     }
@@ -684,6 +662,8 @@ int Assembler::target_at(int32_t pos, bool is_internal) {
        return (imm18 + pos);
      }
   }
+  // Check we have a branch or jump instruction.
+  DCHECK(IsBranch(instr) || IsJ(instr) || IsLui(instr));
   // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
   // the compiler uses arithmectic shifts for signed integers.
   if (IsBranch(instr)) {
@@ -711,7 +691,7 @@ int Assembler::target_at(int32_t pos, bool is_internal) {
       DCHECK(pos > delta);
       return pos - delta;
     }
-  } else if (IsJ(instr)) {
+  } else {
     int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
     if (imm28 == kEndOfJumpChain) {
       // EndOfChain sentinel is returned directly, not relative to pc or pos.
@@ -719,13 +699,10 @@ int Assembler::target_at(int32_t pos, bool is_internal) {
     } else {
       uint32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
       instr_address &= kImm28Mask;
-      int32_t delta = instr_address - imm28;
+      int delta = static_cast<int>(instr_address - imm28);
       DCHECK(pos > delta);
       return pos - delta;
     }
-  } else {
-    UNREACHABLE();
-    return 0;
   }
 }
 
@@ -747,6 +724,7 @@ void Assembler::target_at_put(int32_t pos, int32_t target_pos,
     return;
   }
 
+  DCHECK(IsBranch(instr) || IsJ(instr) || IsLui(instr));
   if (IsBranch(instr)) {
     int32_t imm18 = target_pos - (pos + kBranchPCOffset);
     DCHECK((imm18 & 3) == 0);
@@ -770,7 +748,7 @@ void Assembler::target_at_put(int32_t pos, int32_t target_pos,
                  instr_lui | ((imm & kHiMask) >> kLuiShift));
     instr_at_put(pos + 1 * Assembler::kInstrSize,
                  instr_ori | (imm & kImm16Mask));
-  } else if (IsJ(instr)) {
+  } else {
     uint32_t imm28 = reinterpret_cast<uint32_t>(buffer_) + target_pos;
     imm28 &= kImm28Mask;
     DCHECK((imm28 & 3) == 0);
@@ -780,8 +758,6 @@ void Assembler::target_at_put(int32_t pos, int32_t target_pos,
     DCHECK(is_uint26(imm26));
 
     instr_at_put(pos, instr | (imm26 & kImm26Mask));
-  } else {
-    UNREACHABLE();
   }
 }
 
index 89af82a..d86f0d7 100644 (file)
@@ -41,8 +41,8 @@
 #include <set>
 
 #include "src/assembler.h"
+#include "src/compiler.h"
 #include "src/mips/constants-mips.h"
-#include "src/serialize.h"
 
 namespace v8 {
 namespace internal {
@@ -546,6 +546,11 @@ class Assembler : public AssemblerBase {
         target);
   }
 
+  // This sets the internal reference at the pc.
+  inline static void deserialization_set_target_internal_reference_at(
+      Address pc, Address target,
+      RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
+
   // Size of an instruction.
   static const int kInstrSize = sizeof(Instr);
 
@@ -590,6 +595,8 @@ class Assembler : public AssemblerBase {
   // Number of instructions used for the JS return sequence. The constant is
   // used by the debugger to patch the JS return sequence.
   static const int kJSReturnSequenceInstructions = 7;
+  static const int kJSReturnSequenceLength =
+      kJSReturnSequenceInstructions * kInstrSize;
   static const int kDebugBreakSlotInstructions = 4;
   static const int kDebugBreakSlotLength =
       kDebugBreakSlotInstructions * kInstrSize;
@@ -1020,7 +1027,7 @@ class Assembler : public AssemblerBase {
 
   // Record a deoptimization reason that can be used by a log or cpu profiler.
   // Use --trace-deopt to enable.
-  void RecordDeoptReason(const int reason, const int raw_position);
+  void RecordDeoptReason(const int reason, const SourcePosition position);
 
 
   static int RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
@@ -1129,10 +1136,10 @@ class Assembler : public AssemblerBase {
   int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; }
 
   // Decode branch instruction at pos and return branch target pos.
-  int target_at(int32_t pos, bool is_internal);
+  int target_at(int pos, bool is_internal);
 
   // Patch branch instruction at pos to branch to given branch target pos.
-  void target_at_put(int32_t pos, int32_t target_pos, bool is_internal);
+  void target_at_put(int pos, int target_pos, bool is_internal);
 
   // Say if we need to relocate with this mode.
   bool MustUseReg(RelocInfo::Mode rmode);
@@ -1184,6 +1191,9 @@ class Assembler : public AssemblerBase {
   }
 
  private:
+  inline static void set_target_internal_reference_encoded_at(Address pc,
+                                                              Address target);
+
   // Buffer size and constant pool distance are checked together at regular
   // intervals of kBufferCheckInterval emitted bytes.
   static const int kBufferCheckInterval = 1*KB/2;
index 42a0bbe..9bdc1e1 100644 (file)
@@ -941,7 +941,9 @@ static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
   // Push function as parameter to the runtime call.
   __ Push(a1, a1);
   // Whether to compile in a background thread.
-  __ Push(masm->isolate()->factory()->ToBoolean(concurrent));
+  __ LoadRoot(
+      at, concurrent ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex);
+  __ push(at);
 
   __ CallRuntime(Runtime::kCompileOptimized, 2);
   // Restore receiver.
@@ -1349,49 +1351,100 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
 }
 
 
-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;
+static void Generate_CheckStackOverflow(MacroAssembler* masm,
+                                        const int calleeOffset) {
+  // 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(a2, Heap::kRealStackLimitRootIndex);
+  // Make a2 the space we have left. The stack might already be overflowed
+  // here which will cause a2 to become negative.
+  __ Subu(a2, sp, a2);
+  // Check if the arguments will overflow the stack.
+  __ sll(t3, v0, kPointerSizeLog2 - kSmiTagSize);
+  // Signed comparison.
+  __ Branch(&okay, gt, a2, Operand(t3));
+
+  // Out of stack space.
+  __ lw(a1, MemOperand(fp, calleeOffset));
+  __ Push(a1, v0);
+  __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+
+  __ bind(&okay);
+}
+
+
+static void Generate_PushAppliedArguments(MacroAssembler* masm,
+                                          const int argumentsOffset,
+                                          const int indexOffset,
+                                          const int limitOffset) {
+  Label entry, loop;
+  __ lw(a0, MemOperand(fp, indexOffset));
+  __ Branch(&entry);
+
+  // Load the current argument from the arguments array and push it to the
+  // stack.
+  // a0: current argument index
+  __ bind(&loop);
+  __ lw(a1, MemOperand(fp, argumentsOffset));
+  __ Push(a1, a0);
+
+  // Call the runtime to access the property in the arguments array.
+  __ CallRuntime(Runtime::kGetProperty, 2);
+  __ push(v0);
+
+  // Use inline caching to access the arguments.
+  __ lw(a0, MemOperand(fp, indexOffset));
+  __ Addu(a0, a0, Operand(1 << kSmiTagSize));
+  __ sw(a0, MemOperand(fp, indexOffset));
+
+  // Test if the copy loop has finished copying all the elements from the
+  // arguments object.
+  __ bind(&entry);
+  __ lw(a1, MemOperand(fp, limitOffset));
+  __ Branch(&loop, ne, a0, Operand(a1));
+
+  // On exit, the pushed arguments count is in a0, untagged
+  __ SmiUntag(a0);
+}
+
+
+// Used by FunctionApply and ReflectApply
+static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
+  const int kFormalParameters = targetIsArgument ? 3 : 2;
+  const int kStackSize = kFormalParameters + 1;
 
   {
     FrameScope frame_scope(masm, StackFrame::INTERNAL);
+    const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize;
+    const int kReceiverOffset = kArgumentsOffset + kPointerSize;
+    const int kFunctionOffset = kReceiverOffset + kPointerSize;
+
     __ lw(a0, MemOperand(fp, kFunctionOffset));  // Get the function.
     __ push(a0);
-    __ lw(a0, MemOperand(fp, kArgsOffset));  // Get the args array.
+    __ lw(a0, MemOperand(fp, kArgumentsOffset));  // Get the args array.
     __ push(a0);
     // Returns (in v0) number of arguments to copy to stack as Smi.
-    __ 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(a2, Heap::kRealStackLimitRootIndex);
-    // Make a2 the space we have left. The stack might already be overflowed
-    // here which will cause a2 to become negative.
-    __ subu(a2, sp, a2);
-    // Check if the arguments will overflow the stack.
-    __ sll(t3, v0, kPointerSizeLog2 - kSmiTagSize);
-    __ Branch(&okay, gt, a2, Operand(t3));  // Signed comparison.
-
-    // Out of stack space.
-    __ lw(a1, MemOperand(fp, kFunctionOffset));
-    __ Push(a1, v0);
-    __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
-    // End of stack check.
+    if (targetIsArgument) {
+      __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION);
+    } else {
+      __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
+    }
+
+    // Returns the result in v0.
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
 
     // Push current limit and index.
-    __ bind(&okay);
+    const int kIndexOffset =
+        StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
+    const int kLimitOffset =
+        StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
     __ mov(a1, zero_reg);
     __ Push(v0, a1);  // Limit and initial index.
 
     // Get the receiver.
-    __ lw(a0, MemOperand(fp, kRecvOffset));
+    __ lw(a0, MemOperand(fp, kReceiverOffset));
 
     // Check that the function is a JS function (otherwise it must be a proxy).
     Label push_receiver;
@@ -1447,36 +1500,12 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
     __ push(a0);
 
     // Copy all arguments from the array to the stack.
-    Label entry, loop;
-    __ lw(a0, MemOperand(fp, kIndexOffset));
-    __ Branch(&entry);
-
-    // Load the current argument from the arguments array and push it to the
-    // stack.
-    // a0: current argument index
-    __ bind(&loop);
-    __ lw(a1, MemOperand(fp, kArgsOffset));
-    __ Push(a1, a0);
-
-    // Call the runtime to access the property in the arguments array.
-    __ CallRuntime(Runtime::kGetProperty, 2);
-    __ push(v0);
-
-    // Use inline caching to access the arguments.
-    __ lw(a0, MemOperand(fp, kIndexOffset));
-    __ Addu(a0, a0, Operand(1 << kSmiTagSize));
-    __ sw(a0, MemOperand(fp, kIndexOffset));
-
-    // Test if the copy loop has finished copying all the elements from the
-    // arguments object.
-    __ bind(&entry);
-    __ lw(a1, MemOperand(fp, kLimitOffset));
-    __ Branch(&loop, ne, a0, Operand(a1));
+    Generate_PushAppliedArguments(
+        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
 
     // Call the function.
     Label call_proxy;
     ParameterCount actual(a0);
-    __ sra(a0, a0, kSmiTagSize);
     __ lw(a1, MemOperand(fp, kFunctionOffset));
     __ GetObjectType(a1, a2, a2);
     __ Branch(&call_proxy, ne, a2, Operand(JS_FUNCTION_TYPE));
@@ -1485,7 +1514,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
 
     frame_scope.GenerateLeaveFrame();
     __ Ret(USE_DELAY_SLOT);
-    __ Addu(sp, sp, Operand(3 * kPointerSize));  // In delay slot.
+    __ Addu(sp, sp, Operand(kStackSize * kPointerSize));  // In delay slot.
 
     // Call the function proxy.
     __ bind(&call_proxy);
@@ -1499,7 +1528,89 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
   }
 
   __ Ret(USE_DELAY_SLOT);
-  __ Addu(sp, sp, Operand(3 * kPointerSize));  // In delay slot.
+  __ Addu(sp, sp, Operand(kStackSize * kPointerSize));  // In delay slot.
+}
+
+
+static void Generate_ConstructHelper(MacroAssembler* masm) {
+  const int kFormalParameters = 3;
+  const int kStackSize = kFormalParameters + 1;
+
+  {
+    FrameScope frame_scope(masm, StackFrame::INTERNAL);
+    const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize;
+    const int kArgumentsOffset = kNewTargetOffset + kPointerSize;
+    const int kFunctionOffset = kArgumentsOffset + kPointerSize;
+
+    // If newTarget is not supplied, set it to constructor
+    Label validate_arguments;
+    __ lw(a0, MemOperand(fp, kNewTargetOffset));
+    __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
+    __ Branch(&validate_arguments, ne, a0, Operand(at));
+    __ lw(a0, MemOperand(fp, kFunctionOffset));
+    __ sw(a0, MemOperand(fp, kNewTargetOffset));
+
+    // Validate arguments
+    __ bind(&validate_arguments);
+    __ lw(a0, MemOperand(fp, kFunctionOffset));  // get the function
+    __ push(a0);
+    __ lw(a0, MemOperand(fp, kArgumentsOffset));  // get the args array
+    __ push(a0);
+    __ lw(a0, MemOperand(fp, kNewTargetOffset));  // get the new.target
+    __ push(a0);
+    // Returns argument count in v0.
+    __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION);
+
+    // Returns result in v0.
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
+
+    // Push current limit and index.
+    const int kIndexOffset =
+        StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
+    const int kLimitOffset =
+        StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
+    __ push(v0);  // limit
+    __ mov(a1, zero_reg);  // initial index
+    __ push(a1);
+    // Push newTarget and callee functions
+    __ lw(a0, MemOperand(fp, kNewTargetOffset));
+    __ push(a0);
+    __ lw(a0, MemOperand(fp, kFunctionOffset));
+    __ push(a0);
+
+    // Copy all arguments from the array to the stack.
+    Generate_PushAppliedArguments(
+        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
+
+    // Use undefined feedback vector
+    __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
+    __ lw(a1, MemOperand(fp, kFunctionOffset));
+
+    // Call the function.
+    CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
+    __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
+
+    __ Drop(1);
+
+    // Leave internal frame.
+  }
+  __ jr(ra);
+  __ Addu(sp, sp, Operand(kStackSize * kPointerSize));  // In delay slot.
+}
+
+
+void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+  Generate_ApplyHelper(masm, false);
+}
+
+
+void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
+  Generate_ApplyHelper(masm, true);
+}
+
+
+void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
+  Generate_ConstructHelper(masm);
 }
 
 
index c4fc383..837b5a4 100644 (file)
@@ -12,6 +12,7 @@
 #include "src/codegen.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
@@ -1121,13 +1122,12 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   __ LoadRoot(t0, Heap::kExceptionRootIndex);
   __ Branch(&exception_returned, eq, t0, Operand(v0));
 
-  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;
+    ExternalReference pending_exception_address(
+        Isolate::kPendingExceptionAddress, isolate());
     __ li(a2, Operand(pending_exception_address));
     __ lw(a2, MemOperand(a2));
     __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
@@ -1147,25 +1147,52 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // Handling of exception.
   __ bind(&exception_returned);
 
-  // Retrieve the pending exception.
-  __ li(a2, Operand(pending_exception_address));
-  __ lw(v0, MemOperand(a2));
-
-  // Clear the pending exception.
-  __ li(a3, Operand(isolate()->factory()->the_hole_value()));
-  __ sw(a3, MemOperand(a2));
-
-  // Special handling of termination exceptions which are uncatchable
-  // by javascript code.
-  Label throw_termination_exception;
-  __ LoadRoot(t0, Heap::kTerminationExceptionRootIndex);
-  __ Branch(&throw_termination_exception, eq, v0, Operand(t0));
-
-  // Handle normal exception.
-  __ Throw(v0);
+  ExternalReference pending_handler_context_address(
+      Isolate::kPendingHandlerContextAddress, isolate());
+  ExternalReference pending_handler_code_address(
+      Isolate::kPendingHandlerCodeAddress, isolate());
+  ExternalReference pending_handler_offset_address(
+      Isolate::kPendingHandlerOffsetAddress, isolate());
+  ExternalReference pending_handler_fp_address(
+      Isolate::kPendingHandlerFPAddress, isolate());
+  ExternalReference pending_handler_sp_address(
+      Isolate::kPendingHandlerSPAddress, isolate());
+
+  // Ask the runtime for help to determine the handler. This will set v0 to
+  // contain the current pending exception, don't clobber it.
+  ExternalReference find_handler(Runtime::kFindExceptionHandler, isolate());
+  {
+    FrameScope scope(masm, StackFrame::MANUAL);
+    __ PrepareCallCFunction(3, 0, a0);
+    __ mov(a0, zero_reg);
+    __ mov(a1, zero_reg);
+    __ li(a2, Operand(ExternalReference::isolate_address(isolate())));
+    __ CallCFunction(find_handler, 3);
+  }
 
-  __ bind(&throw_termination_exception);
-  __ ThrowUncatchable(v0);
+  // Retrieve the handler context, SP and FP.
+  __ li(cp, Operand(pending_handler_context_address));
+  __ lw(cp, MemOperand(cp));
+  __ li(sp, Operand(pending_handler_sp_address));
+  __ lw(sp, MemOperand(sp));
+  __ li(fp, Operand(pending_handler_fp_address));
+  __ lw(fp, MemOperand(fp));
+
+  // If the handler is a JS frame, restore the context to the frame. Note that
+  // the context will be set to (cp == 0) for non-JS frames.
+  Label zero;
+  __ Branch(&zero, eq, cp, Operand(zero_reg));
+  __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  __ bind(&zero);
+
+  // Compute the handler entry address and jump to it.
+  __ li(a1, Operand(pending_handler_code_address));
+  __ lw(a1, MemOperand(a1));
+  __ li(a2, Operand(pending_handler_offset_address));
+  __ lw(a2, MemOperand(a2));
+  __ Addu(a1, a1, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Addu(t9, a1, a2);
+  __ Jump(t9);
 }
 
 
@@ -1252,7 +1279,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   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
+  // fp will be invalid because the PushStackHandler below sets it to 0 to
   // signal the existence of the JSEntry frame.
   __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
                                       isolate)));
@@ -1261,10 +1288,9 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ b(&exit);  // b exposes branch delay slot.
   __ nop();   // Branch delay slot nop.
 
-  // Invoke: Link this frame into the handler chain.  There's only one
-  // handler block in this code object, so its index is 0.
+  // Invoke: Link this frame into the handler chain.
   __ bind(&invoke);
-  __ PushTryHandler(StackHandler::JS_ENTRY, 0);
+  __ PushStackHandler();
   // If an exception not caught by another handler occurs, this handler
   // returns control to the code after the bal(&invoke) above, which
   // restores all kCalleeSaved registers (including cp and fp) to their
@@ -1309,7 +1335,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ Call(t9);
 
   // Unlink this frame from the handler chain.
-  __ PopTryHandler();
+  __ PopStackHandler();
 
   __ bind(&exit);  // v0 holds result
   // Check if the current stack frame is marked as the outermost JS frame.
@@ -1352,12 +1378,8 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
   Register result = v0;
   DCHECK(!scratch.is(receiver) && !scratch.is(index));
   DCHECK(!FLAG_vector_ics ||
-         (!scratch.is(VectorLoadICDescriptor::VectorRegister()) &&
-          result.is(VectorLoadICDescriptor::SlotRegister())));
+         !scratch.is(VectorLoadICDescriptor::VectorRegister()));
 
-  // 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.
@@ -1368,7 +1390,7 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
   __ Ret();
 
   StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
+  char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&miss);
   PropertyAccessCompiler::TailCallBuiltin(
@@ -1938,8 +1960,11 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
   __ bind(&adaptor_frame);
   __ lw(a1, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset));
   if (has_new_target()) {
+    Label skip_decrement;
+    __ Branch(&skip_decrement, eq, a1, Operand(Smi::FromInt(0)));
     // Subtract 1 from smi-tagged arguments count.
     __ Subu(a1, a1, Operand(2));
+    __ bind(&skip_decrement);
   }
   __ sw(a1, MemOperand(sp, 0));
   __ sll(at, a1, kPointerSizeLog2 - kSmiTagSize);
@@ -2054,7 +2079,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   // 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);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 #else  // V8_INTERPRETED_REGEXP
 
   // Stack frame on entry.
@@ -2338,17 +2363,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   __ lw(v0, MemOperand(a2, 0));
   __ Branch(&runtime, eq, v0, Operand(a1));
 
-  __ sw(a1, MemOperand(a2, 0));  // Clear pending exception.
-
-  // Check if the exception is a termination. If so, throw as uncatchable.
-  __ LoadRoot(a0, Heap::kTerminationExceptionRootIndex);
-  Label termination_exception;
-  __ Branch(&termination_exception, eq, v0, Operand(a0));
-
-  __ Throw(v0);
-
-  __ bind(&termination_exception);
-  __ ThrowUncatchable(v0);
+  // For exception, throw the exception again.
+  __ TailCallRuntime(Runtime::kRegExpExecReThrow, 4, 1);
 
   __ bind(&failure);
   // For failure and exception return null.
@@ -2444,7 +2460,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
 
   // Do the runtime call to execute the regexp.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 
   // Deferred code for string handling.
   // (6) Not a long external string?  If yes, go to (8).
@@ -3031,7 +3047,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
 
 
 void StringCharCodeAtGenerator::GenerateSlow(
-    MacroAssembler* masm,
+    MacroAssembler* masm, EmbedMode embed_mode,
     const RuntimeCallHelper& call_helper) {
   __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
 
@@ -3045,7 +3061,12 @@ void StringCharCodeAtGenerator::GenerateSlow(
               DONT_DO_SMI_CHECK);
   call_helper.BeforeCall(masm);
   // Consumed by runtime conversion function:
-  __ Push(object_, index_);
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ Push(VectorLoadICDescriptor::VectorRegister(),
+            VectorLoadICDescriptor::SlotRegister(), object_, index_);
+  } else {
+    __ Push(object_, index_);
+  }
   if (index_flags_ == STRING_INDEX_IS_NUMBER) {
     __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
   } else {
@@ -3056,9 +3077,13 @@ void StringCharCodeAtGenerator::GenerateSlow(
 
   // Save the conversion result before the pop instructions below
   // have a chance to overwrite it.
-
   __ Move(index_, v0);
-  __ pop(object_);
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ Pop(VectorLoadICDescriptor::SlotRegister(),
+           VectorLoadICDescriptor::VectorRegister(), object_);
+  } else {
+    __ pop(object_);
+  }
   // Reload the instance type.
   __ lw(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
   __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
@@ -3385,7 +3410,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
 
   // Just jump to runtime to create the sub string.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kSubString, 3, 1);
+  __ TailCallRuntime(Runtime::kSubStringRT, 3, 1);
 
   __ bind(&single_char);
   // v0: original string
@@ -3579,7 +3604,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
   StringHelper::GenerateCompareFlatOneByteStrings(masm, a1, a0, a2, a3, t0, t1);
 
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+  __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
 }
 
 
@@ -3889,7 +3914,7 @@ void CompareICStub::GenerateStrings(MacroAssembler* masm) {
   if (equality) {
     __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
   } else {
-    __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+    __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
   }
 
   __ bind(&miss);
@@ -4529,15 +4554,15 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
 
 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorLoadStub stub(isolate(), state());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawLoadStub stub(isolate(), state());
+  stub.GenerateForTrampoline(masm);
 }
 
 
 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorKeyedLoadStub stub(isolate());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawKeyedLoadStub stub(isolate());
+  stub.GenerateForTrampoline(masm);
 }
 
 
@@ -4555,6 +4580,243 @@ void CallIC_ArrayTrampolineStub::Generate(MacroAssembler* masm) {
 }
 
 
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+                             Register key, Register vector, Register slot,
+                             Register feedback, Register scratch1,
+                             Register scratch2, Register scratch3,
+                             bool is_polymorphic, Label* miss) {
+  // feedback initially contains the feedback array
+  Label next_loop, prepare_next;
+  Label load_smi_map, compare_map;
+  Label start_polymorphic;
+
+  Register receiver_map = scratch1;
+  Register cached_map = scratch2;
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &load_smi_map);
+  __ lw(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ bind(&compare_map);
+  __ lw(cached_map,
+        FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+  __ lw(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ Branch(&start_polymorphic, ne, receiver_map, Operand(cached_map));
+  // found, now call handler.
+  Register handler = feedback;
+  __ lw(handler, FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+  __ Addu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(t9);
+
+
+  Register length = scratch3;
+  __ bind(&start_polymorphic);
+  __ lw(length, FieldMemOperand(feedback, FixedArray::kLengthOffset));
+  if (!is_polymorphic) {
+    // If the IC could be monomorphic we have to make sure we don't go past the
+    // end of the feedback array.
+    __ Branch(miss, eq, length, Operand(Smi::FromInt(2)));
+  }
+
+  Register too_far = length;
+  Register pointer_reg = feedback;
+
+  // +-----+------+------+-----+-----+ ... ----+
+  // | map | len  | wm0  | h0  | wm1 |      hN |
+  // +-----+------+------+-----+-----+ ... ----+
+  //                 0      1     2        len-1
+  //                              ^              ^
+  //                              |              |
+  //                         pointer_reg      too_far
+  //                         aka feedback     scratch3
+  // also need receiver_map (aka scratch1)
+  // use cached_map (scratch2) to look in the weak map values.
+  __ sll(at, length, kPointerSizeLog2 - kSmiTagSize);
+  __ Addu(too_far, feedback, Operand(at));
+  __ Addu(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ Addu(pointer_reg, feedback,
+          Operand(FixedArray::OffsetOfElementAt(2) - kHeapObjectTag));
+
+  __ bind(&next_loop);
+  __ lw(cached_map, MemOperand(pointer_reg));
+  __ lw(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ Branch(&prepare_next, ne, receiver_map, Operand(cached_map));
+  __ lw(handler, MemOperand(pointer_reg, kPointerSize));
+  __ Addu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(t9);
+
+  __ bind(&prepare_next);
+  __ Addu(pointer_reg, pointer_reg, Operand(kPointerSize * 2));
+  __ Branch(&next_loop, lt, pointer_reg, Operand(too_far));
+
+  // We exhausted our array of map handler pairs.
+  __ jmp(miss);
+
+  __ bind(&load_smi_map);
+  __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
+  __ jmp(&compare_map);
+}
+
+
+static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+                                  Register key, Register vector, Register slot,
+                                  Register weak_cell, Register scratch,
+                                  Label* miss) {
+  // feedback initially contains the feedback array
+  Label compare_smi_map;
+  Register receiver_map = scratch;
+  Register cached_map = weak_cell;
+
+  // Move the weak map into the weak_cell register.
+  __ lw(cached_map, FieldMemOperand(weak_cell, WeakCell::kValueOffset));
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &compare_smi_map);
+  __ lw(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ Branch(miss, ne, cached_map, Operand(receiver_map));
+
+  Register handler = weak_cell;
+  __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+  __ Addu(handler, vector, Operand(at));
+  __ lw(handler,
+        FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ Addu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(t9);
+
+  // In microbenchmarks, it made sense to unroll this code so that the call to
+  // the handler is duplicated for a HeapObject receiver and a Smi receiver.
+  __ bind(&compare_smi_map);
+  __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
+  __ Branch(miss, ne, at, Operand(weak_cell));
+  __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+  __ Addu(handler, vector, Operand(at));
+  __ lw(handler,
+        FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ Addu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(t9);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // a1
+  Register name = VectorLoadICDescriptor::NameRegister();          // a2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // a3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // a0
+  Register feedback = t0;
+  Register scratch1 = t1;
+
+  __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+  __ Addu(feedback, vector, Operand(at));
+  __ lw(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ lw(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ LoadRoot(at, Heap::kWeakCellMapRootIndex);
+  __ Branch(&try_array, ne, at, Operand(scratch1));
+  HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback, scratch1,
+                        &miss);
+
+  // Is it a fixed array?
+  __ bind(&try_array);
+  __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+  __ Branch(&not_array, ne, at, Operand(scratch1));
+  HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, t4,
+                   t5, true, &miss);
+
+  __ bind(&not_array);
+  __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
+  __ Branch(&miss, ne, at, Operand(feedback));
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, code_flags,
+                                               false, receiver, name, feedback,
+                                               scratch1, t4, t5);
+
+  __ bind(&miss);
+  LoadIC::GenerateMiss(masm);
+}
+
+
+void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // a1
+  Register key = VectorLoadICDescriptor::NameRegister();           // a2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // a3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // a0
+  Register feedback = t0;
+  Register scratch1 = t1;
+
+  __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+  __ Addu(feedback, vector, Operand(at));
+  __ lw(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ lw(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ LoadRoot(at, Heap::kWeakCellMapRootIndex);
+  __ Branch(&try_array, ne, at, Operand(scratch1));
+  __ JumpIfNotSmi(key, &miss);
+  HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, scratch1,
+                        &miss);
+
+  __ bind(&try_array);
+  // Is it a fixed array?
+  __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+  __ Branch(&not_array, ne, at, Operand(scratch1));
+  // We have a polymorphic element handler.
+  __ JumpIfNotSmi(key, &miss);
+
+  Label polymorphic, try_poly_name;
+  __ bind(&polymorphic);
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, t4,
+                   t5, true, &miss);
+
+  __ bind(&not_array);
+  // Is it generic?
+  __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
+  __ Branch(&try_poly_name, ne, at, Operand(feedback));
+  Handle<Code> megamorphic_stub =
+      KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+  __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET);
+
+  __ bind(&try_poly_name);
+  // We might have a name in feedback, and a fixed array in the next slot.
+  __ Branch(&miss, ne, key, Operand(feedback));
+  // If the name comparison succeeded, we know we have a fixed array with
+  // at least one map/handler pair.
+  __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+  __ Addu(feedback, vector, Operand(at));
+  __ lw(feedback,
+        FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, t4,
+                   t5, false, &miss);
+
+  __ bind(&miss);
+  KeyedLoadIC::GenerateMiss(masm);
+}
+
+
 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
   if (masm->isolate()->function_entry_hook() != NULL) {
     ProfileEntryHookStub stub(masm->isolate());
@@ -5011,7 +5273,6 @@ static void CallApiFunctionAndReturn(
   }
 
   Label promote_scheduled_exception;
-  Label exception_handled;
   Label delete_allocated_handles;
   Label leave_exit_frame;
   Label return_value_loaded;
@@ -5032,13 +5293,8 @@ static void CallApiFunctionAndReturn(
   __ lw(at, MemOperand(s3, kLimitOffset));
   __ Branch(&delete_allocated_handles, ne, s1, Operand(at));
 
-  // Check if the function scheduled an exception.
+  // Leave the API exit frame.
   __ bind(&leave_exit_frame);
-  __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
-  __ li(at, Operand(ExternalReference::scheduled_exception_address(isolate)));
-  __ lw(t1, MemOperand(at));
-  __ Branch(&promote_scheduled_exception, ne, t0, Operand(t1));
-  __ bind(&exception_handled);
 
   bool restore_context = context_restore_operand != NULL;
   if (restore_context) {
@@ -5051,16 +5307,20 @@ static void CallApiFunctionAndReturn(
   } else {
     __ li(s0, Operand(stack_space));
   }
-  __ LeaveExitFrame(false, s0, !restore_context, EMIT_RETURN,
+  __ LeaveExitFrame(false, s0, !restore_context, NO_EMIT_RETURN,
                     stack_space_offset != kInvalidStackOffset);
 
+  // Check if the function scheduled an exception.
+  __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
+  __ li(at, Operand(ExternalReference::scheduled_exception_address(isolate)));
+  __ lw(t1, MemOperand(at));
+  __ Branch(&promote_scheduled_exception, ne, t0, Operand(t1));
+
+  __ Ret();
+
+  // Re-throw by promoting a scheduled exception.
   __ bind(&promote_scheduled_exception);
-  {
-    FrameScope frame(masm, StackFrame::INTERNAL);
-    __ CallExternalReference(
-        ExternalReference(Runtime::kPromoteScheduledException, isolate), 0);
-  }
-  __ jmp(&exception_handled);
+  __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
 
   // HandleScope limit has changed. Delete allocated extensions.
   __ bind(&delete_allocated_handles);
index 5b3591c..a14fac8 100644 (file)
 namespace v8 {
 namespace internal {
 
-bool BreakLocationIterator::IsDebugBreakAtReturn() {
-  return Debug::IsDebugBreakAtReturn(rinfo());
-}
-
-
-void BreakLocationIterator::SetDebugBreakAtReturn() {
+void BreakLocation::SetDebugBreakAtReturn() {
   // Mips return sequence:
   // mov sp, fp
   // lw fp, sp(0)
@@ -31,7 +26,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
 
   // Make sure this constant matches the number if instrucntions we emit.
   DCHECK(Assembler::kJSReturnSequenceInstructions == 7);
-  CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
+  CodePatcher patcher(pc(), Assembler::kJSReturnSequenceInstructions);
   // li and Call pseudo-instructions emit two instructions each.
   patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>(
       debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry())));
@@ -45,29 +40,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
 }
 
 
-// Restore the JS frame exit code.
-void BreakLocationIterator::ClearDebugBreakAtReturn() {
-  rinfo()->PatchCode(original_rinfo()->pc(),
-                     Assembler::kJSReturnSequenceInstructions);
-}
-
-
-// A debug break in the exit code is identified by the JS frame exit code
-// having been patched with li/call psuedo-instrunction (liu/ori/jalr).
-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() {
+void BreakLocation::SetDebugBreakAtSlot() {
   DCHECK(IsDebugBreakSlot());
   // Patch the code changing the debug break slot code from:
   //   nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1)
@@ -77,20 +50,13 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
   // to a call to the debug break slot code.
   //   li t9, address   (lui t9 / ori t9 instruction pair)
   //   call t9          (jalr t9 / nop instruction pair)
-  CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
+  CodePatcher patcher(pc(), Assembler::kDebugBreakSlotInstructions);
   patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>(
       debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry())));
   patcher.masm()->Call(v8::internal::t9);
 }
 
 
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
-  DCHECK(IsDebugBreakSlot());
-  rinfo()->PatchCode(original_rinfo()->pc(),
-                     Assembler::kDebugBreakSlotInstructions);
-}
-
-
 #define __ ACCESS_MASM(masm)
 
 
index 3dfc64a..ab237c3 100644 (file)
@@ -132,7 +132,7 @@ bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
 
 // This code tries to be close to ia32 code so that any changes can be
 // easily ported.
-void Deoptimizer::EntryGenerator::Generate() {
+void Deoptimizer::TableEntryGenerator::Generate() {
   GeneratePrologue();
 
   // Unlike on ARM we don't save all the registers, just the useful ones.
index 5666f64..633a887 100644 (file)
@@ -205,11 +205,6 @@ inline Object* JavaScriptFrame::function_slot_object() const {
 }
 
 
-inline void StackHandler::SetFp(Address slot, Address fp) {
-  Memory::Address_at(slot) = fp;
-}
-
-
 } }  // namespace v8::internal
 
 #endif
index ee8475a..9f36552 100644 (file)
@@ -115,7 +115,8 @@ class JumpPatchSite BASE_EMBEDDED {
 void FullCodeGenerator::Generate() {
   CompilationInfo* info = info_;
   handler_table_ =
-      isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
+      Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray(
+          HandlerTable::LengthForRange(function()->handler_count()), TENURED));
 
   profiling_counter_ = isolate()->factory()->NewCell(
       Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
@@ -204,7 +205,7 @@ void FullCodeGenerator::Generate() {
     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_script_scope()) {
+    if (info->scope()->is_script_scope()) {
       __ push(a1);
       __ Push(info->scope()->GetScopeInfo(info->isolate()));
       __ CallRuntime(Runtime::kNewScriptContext, 2);
@@ -249,6 +250,11 @@ void FullCodeGenerator::Generate() {
     }
   }
 
+  ArgumentsAccessStub::HasNewTarget has_new_target =
+      IsSubclassConstructor(info->function()->kind())
+          ? ArgumentsAccessStub::HAS_NEW_TARGET
+          : ArgumentsAccessStub::NO_NEW_TARGET;
+
   // Possibly allocate RestParameters
   int rest_index;
   Variable* rest_param = scope()->rest_parameter(&rest_index);
@@ -257,6 +263,11 @@ void FullCodeGenerator::Generate() {
 
     int num_parameters = info->scope()->num_parameters();
     int offset = num_parameters * kPointerSize;
+    if (has_new_target == ArgumentsAccessStub::HAS_NEW_TARGET) {
+      --num_parameters;
+      ++rest_index;
+    }
+
     __ Addu(a3, fp,
             Operand(StandardFrameConstants::kCallerSPOffset + offset));
     __ li(a2, Operand(Smi::FromInt(num_parameters)));
@@ -291,10 +302,6 @@ void FullCodeGenerator::Generate() {
     //   function, receiver address, parameter count.
     // The stub will rewrite receiever and parameter count if the previous
     // stack frame was an arguments adapter frame.
-    ArgumentsAccessStub::HasNewTarget has_new_target =
-        IsSubclassConstructor(info->function()->kind())
-            ? ArgumentsAccessStub::HAS_NEW_TARGET
-            : ArgumentsAccessStub::NO_NEW_TARGET;
     ArgumentsAccessStub::Type type;
     if (is_strict(language_mode()) || !is_simple_parameter_list()) {
       type = ArgumentsAccessStub::NEW_STRICT;
@@ -1513,7 +1520,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
         __ li(VectorLoadICDescriptor::SlotRegister(),
               Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
       }
-      CallLoadIC(CONTEXTUAL);
+      CallGlobalLoadIC(var->name());
       context()->Plug(v0);
       break;
     }
@@ -2161,7 +2168,6 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
       __ bind(&l_catch);
       __ mov(a0, v0);
-      handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
       __ LoadRoot(load_name, Heap::kthrow_stringRootIndex);  // "throw"
       __ lw(a3, MemOperand(sp, 1 * kPointerSize));           // iter
       __ Push(load_name, a3, a0);                     // "throw", iter, except
@@ -2172,17 +2178,18 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       // re-boxing.
       __ bind(&l_try);
       __ pop(a0);                                        // result
-      __ PushTryHandler(StackHandler::CATCH, expr->index());
-      const int handler_size = StackHandlerConstants::kSize;
+      EnterTryBlock(expr->index(), &l_catch);
+      const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ push(a0);                                       // result
       __ jmp(&l_suspend);
       __ bind(&l_continuation);
       __ mov(a0, v0);
       __ jmp(&l_resume);
       __ bind(&l_suspend);
-      const int generator_object_depth = kPointerSize + handler_size;
+      const int generator_object_depth = kPointerSize + try_block_size;
       __ lw(a0, MemOperand(sp, generator_object_depth));
       __ push(a0);                                       // g
+      __ Push(Smi::FromInt(expr->index()));              // handler-index
       DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
       __ li(a1, Operand(Smi::FromInt(l_continuation.pos())));
       __ sw(a1, FieldMemOperand(a0, JSGeneratorObject::kContinuationOffset));
@@ -2190,13 +2197,13 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       __ mov(a1, cp);
       __ RecordWriteField(a0, JSGeneratorObject::kContextOffset, a1, a2,
                           kRAHasBeenSaved, kDontSaveFPRegs);
-      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 2);
       __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
       __ pop(v0);                                      // result
       EmitReturnSequence();
       __ mov(a0, v0);
       __ bind(&l_resume);                              // received in a0
-      __ PopTryHandler();
+      ExitTryBlock(expr->index());
 
       // receiver = iter; f = 'next'; arg = received;
       __ bind(&l_next);
@@ -2544,6 +2551,16 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
     }
     __ push(scratch);
     EmitPropertyKey(property, lit->GetIdForProperty(i));
+
+    // The static prototype property is read only. We handle the non computed
+    // property name case in the parser. Since this is the only case where we
+    // need to check for an own read only property we special case this so we do
+    // not need to do this for every property.
+    if (property->is_static() && property->is_computed_name()) {
+      __ CallRuntime(Runtime::kThrowIfStaticPrototype, 1);
+      __ push(v0);
+    }
+
     VisitForStackValue(value);
     EmitSetHomeObjectIfNeeded(value, 2);
 
@@ -2689,24 +2706,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
     __ lw(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()) {
-      __ li(a0, Operand(var->name()));
-      __ Push(v0, cp, a0);  // Context and name.
-      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
-    } else {
-      DCHECK(var->IsStackAllocated() || var->IsContextSlot());
-      Label skip;
-      MemOperand location = VarOperand(var, a1);
-      __ lw(a2, location);
-      __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-      __ Branch(&skip, ne, a2, Operand(at));
-      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());
@@ -2722,6 +2721,22 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
     // Perform the assignment.
     __ bind(&assign);
     EmitStoreToStackLocalOrContextSlot(var, location);
+
+  } else if (var->mode() == CONST && op != Token::INIT_CONST) {
+    // Assignment to const variable needs a write barrier.
+    DCHECK(!var->IsLookupSlot());
+    DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+    Label const_error;
+    MemOperand location = VarOperand(var, a1);
+    __ lw(a3, location);
+    __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+    __ Branch(&const_error, ne, a3, Operand(at));
+    __ li(a3, Operand(var->name()));
+    __ push(a3);
+    __ CallRuntime(Runtime::kThrowReferenceError, 1);
+    __ bind(&const_error);
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
   } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
     if (var->IsLookupSlot()) {
       // Assignment to var.
@@ -2742,8 +2757,31 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
-  } else if (IsSignallingAssignmentToConst(var, op, language_mode())) {
-    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
+  } else if (op == Token::INIT_CONST_LEGACY) {
+    // Const initializers need a write barrier.
+    DCHECK(!var->IsParameter());  // No const parameters.
+    if (var->IsLookupSlot()) {
+      __ li(a0, Operand(var->name()));
+      __ Push(v0, cp, a0);  // Context and name.
+      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
+    } else {
+      DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+      Label skip;
+      MemOperand location = VarOperand(var, a1);
+      __ lw(a2, location);
+      __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+      __ Branch(&skip, ne, a2, Operand(at));
+      EmitStoreToStackLocalOrContextSlot(var, location);
+      __ bind(&skip);
+    }
+
+  } else {
+    DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT_CONST_LEGACY);
+    if (is_strict(language_mode())) {
+      __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+    }
+    // Silently ignore store in sloppy mode.
   }
 }
 
@@ -2877,7 +2915,8 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
     }
     // Push undefined as receiver. This is patched in the method prologue if it
     // is a sloppy mode method.
-    __ Push(isolate()->factory()->undefined_value());
+    __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
+    __ push(at);
   } else {
     // Load the function from the receiver.
     DCHECK(callee->IsProperty());
@@ -3229,7 +3268,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
 
 
 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
-  if (!ValidateSuperCall(expr)) return;
   Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
   GetVar(result_register(), new_target_var);
   __ Push(result_register());
@@ -3739,9 +3777,10 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 
   // Check if the constructor in the map is a JS function.
-  __ lw(v0, FieldMemOperand(v0, Map::kConstructorOffset));
-  __ GetObjectType(v0, a1, a1);
-  __ Branch(&non_function_constructor, ne, a1, Operand(JS_FUNCTION_TYPE));
+  Register instance_type = a2;
+  __ GetMapConstructor(v0, v0, a1, instance_type);
+  __ Branch(&non_function_constructor, ne, instance_type,
+            Operand(JS_FUNCTION_TYPE));
 
   // v0 now contains the constructor function. Grab the
   // instance class name from there.
@@ -4052,7 +4091,7 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
   __ jmp(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&done);
   context()->Plug(result);
@@ -4101,7 +4140,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
   __ jmp(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&done);
   context()->Plug(result);
@@ -4287,7 +4326,7 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
   __ bind(&not_found);
   // Call runtime to perform the lookup.
   __ Push(cache, key);
-  __ CallRuntime(Runtime::kGetFromCache, 2);
+  __ CallRuntime(Runtime::kGetFromCacheRT, 2);
 
   __ bind(&done);
   context()->Plug(v0);
@@ -4573,18 +4612,11 @@ void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
 
 
 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()) {
+    Comment cmnt(masm_, "[ CallRuntime");
     // Push the builtins object as the receiver.
     Register receiver = LoadDescriptor::ReceiverRegister();
     __ lw(receiver, GlobalObjectOperand());
@@ -4607,7 +4639,6 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     __ sw(v0, 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));
     }
@@ -4622,15 +4653,29 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
 
     context()->DropAndPlug(1, v0);
+
   } else {
-    // Push the arguments ("left-to-right").
-    for (int i = 0; i < arg_count; i++) {
-      VisitForStackValue(args->at(i));
-    }
+    const Runtime::Function* function = expr->function();
+    switch (function->function_id) {
+#define CALL_INTRINSIC_GENERATOR(Name)     \
+  case Runtime::kInline##Name: {           \
+    Comment cmnt(masm_, "[ Inline" #Name); \
+    return Emit##Name(expr);               \
+  }
+      FOR_EACH_FULL_CODE_INTRINSIC(CALL_INTRINSIC_GENERATOR)
+#undef CALL_INTRINSIC_GENERATOR
+      default: {
+        Comment cmnt(masm_, "[ CallRuntime for unhandled intrinsic");
+        // 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(v0);
+        // Call the C runtime function.
+        __ CallRuntime(expr->function(), arg_count);
+        context()->Plug(v0);
+      }
+    }
   }
 }
 
@@ -5273,19 +5318,6 @@ void FullCodeGenerator::EnterFinallyBlock() {
   __ li(at, Operand(pending_message_obj));
   __ lw(a1, MemOperand(at));
   __ push(a1);
-
-  ExternalReference has_pending_message =
-      ExternalReference::address_of_has_pending_message(isolate());
-  __ li(at, Operand(has_pending_message));
-  __ lw(a1, MemOperand(at));
-  __ SmiTag(a1);
-  __ push(a1);
-
-  ExternalReference pending_message_script =
-      ExternalReference::address_of_pending_message_script(isolate());
-  __ li(at, Operand(pending_message_script));
-  __ lw(a1, MemOperand(at));
-  __ push(a1);
 }
 
 
@@ -5293,19 +5325,6 @@ void FullCodeGenerator::ExitFinallyBlock() {
   DCHECK(!result_register().is(a1));
   // Restore pending message from stack.
   __ pop(a1);
-  ExternalReference pending_message_script =
-      ExternalReference::address_of_pending_message_script(isolate());
-  __ li(at, Operand(pending_message_script));
-  __ sw(a1, MemOperand(at));
-
-  __ pop(a1);
-  __ SmiUntag(a1);
-  ExternalReference has_pending_message =
-      ExternalReference::address_of_has_pending_message(isolate());
-  __ li(at, Operand(has_pending_message));
-  __ sw(a1, MemOperand(at));
-
-  __ pop(a1);
   ExternalReference pending_message_obj =
       ExternalReference::address_of_pending_message_obj(isolate());
   __ li(at, Operand(pending_message_obj));
@@ -5325,34 +5344,6 @@ void FullCodeGenerator::ExitFinallyBlock() {
 
 #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.
-    __ lw(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
-    __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-  }
-  __ PopTryHandler();
-  __ Call(finally_entry_);
-
-  *stack_depth = 0;
-  *context_length = 0;
-  return previous_;
-}
-
-
-#undef __
-
 
 void BackEdgeTable::PatchAt(Code* unoptimized_code,
                             Address pc,
index b8cae81..ec6c63f 100644 (file)
@@ -227,6 +227,12 @@ void InternalArrayConstructorDescriptor::Initialize(
 }
 
 
+void CompareDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, a1, a0};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
 void CompareNilDescriptor::Initialize(CallInterfaceDescriptorData* data) {
   Register registers[] = {cp, a0};
   data->Initialize(arraysize(registers), registers, NULL);
index 0dea629..d7b3511 100644 (file)
@@ -30,6 +30,7 @@
 #include "src/base/bits.h"
 #include "src/code-factory.h"
 #include "src/code-stubs.h"
+#include "src/cpu-profiler.h"
 #include "src/hydrogen-osr.h"
 #include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
@@ -142,7 +143,7 @@ bool LCodeGen::GeneratePrologue() {
     // 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() && is_sloppy(info_->language_mode()) &&
+    if (graph()->this_has_uses() && is_sloppy(info_->language_mode()) &&
         !info_->is_native()) {
       Label ok;
       int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
@@ -346,50 +347,39 @@ bool LCodeGen::GenerateJumpTable() {
 
       if (table_entry->needs_frame) {
         DCHECK(!info()->saves_caller_doubles());
-        if (needs_frame.is_bound()) {
-          __ Branch(&needs_frame);
-        } else {
-          __ bind(&needs_frame);
-          Comment(";;; call deopt with frame");
-          __ MultiPush(cp.bit() | fp.bit() | ra.bit());
-          // 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());
-          __ li(at, Operand(Smi::FromInt(StackFrame::STUB)));
-          __ push(at);
-          __ Addu(fp, sp,
-                  Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
-          __ bind(&call_deopt_entry);
-          // Add the base address to the offset previously loaded in
-          // entry_offset.
-          __ Addu(entry_offset, entry_offset,
-                  Operand(ExternalReference::ForDeoptEntry(base)));
-          __ Call(entry_offset);
-        }
+        Comment(";;; call deopt with frame");
+        __ MultiPush(cp.bit() | fp.bit() | ra.bit());
+        __ Call(&needs_frame);
       } 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) __ Branch(&call_deopt_entry);
+        __ Call(&call_deopt_entry);
       }
+      info()->LogDeoptCallPosition(masm()->pc_offset(),
+                                   table_entry->deopt_info.inlining_id);
     }
 
-    if (!call_deopt_entry.is_bound()) {
-      Comment(";;; call deopt");
-      __ bind(&call_deopt_entry);
+    if (needs_frame.is_linked()) {
+      __ bind(&needs_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());
+      __ li(at, Operand(Smi::FromInt(StackFrame::STUB)));
+      __ push(at);
+      __ Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+    }
 
-      if (info()->saves_caller_doubles()) {
-        DCHECK(info()->IsStub());
-        RestoreCallerDoubles();
-      }
+    Comment(";;; call deopt");
+    __ bind(&call_deopt_entry);
 
-      // Add the base address to the offset previously loaded in entry_offset.
-      __ Addu(entry_offset, entry_offset,
-              Operand(ExternalReference::ForDeoptEntry(base)));
-      __ Call(entry_offset);
+    if (info()->saves_caller_doubles()) {
+      DCHECK(info()->IsStub());
+      RestoreCallerDoubles();
     }
+
+    // Add the base address to the offset previously loaded in entry_offset.
+    __ Addu(entry_offset, entry_offset,
+            Operand(ExternalReference::ForDeoptEntry(base)));
+    __ Jump(entry_offset);
   }
   __ RecordComment("]");
 
@@ -856,8 +846,8 @@ void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
     __ bind(&skip);
   }
 
-  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
-                                    instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info = MakeDeoptInfo(instr, deopt_reason);
+
   DCHECK(info()->IsStub() || frame_is_built_);
   // Go through jump table if we need to handle condition, build frame, or
   // restore caller doubles.
@@ -865,6 +855,7 @@ void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
       !info()->saves_caller_doubles()) {
     DeoptComment(deopt_info);
     __ Call(entry, RelocInfo::RUNTIME_ENTRY, condition, src1, src2);
+    info()->LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
   } else {
     Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
                                             !frame_is_built_);
@@ -2656,14 +2647,15 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
 
   // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
   // Check if the constructor in the map is a function.
-  __ lw(temp, FieldMemOperand(temp, Map::kConstructorOffset));
+  Register instance_type = scratch1();
+  DCHECK(!instance_type.is(temp));
+  __ GetMapConstructor(temp, temp, temp2, instance_type);
 
   // Objects with a non-function constructor have class 'Object'.
-  __ GetObjectType(temp, temp2, temp2);
   if (String::Equals(class_name, isolate()->factory()->Object_string())) {
-    __ Branch(is_true, ne, temp2, Operand(JS_FUNCTION_TYPE));
+    __ Branch(is_true, ne, instance_type, Operand(JS_FUNCTION_TYPE));
   } else {
-    __ Branch(is_false, ne, temp2, Operand(JS_FUNCTION_TYPE));
+    __ Branch(is_false, ne, instance_type, Operand(JS_FUNCTION_TYPE));
   }
 
   // temp now contains the constructor function. Grab the
@@ -2769,8 +2761,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
   // root array to force relocation to be able to later patch with
   // the cached map.
   Handle<Cell> cell = factory()->NewCell(factory()->the_hole_value());
-  __ li(at, Operand(Handle<Object>(cell)));
-  __ lw(at, FieldMemOperand(at, PropertyCell::kValueOffset));
+  __ li(at, Operand(cell));
+  __ lw(at, FieldMemOperand(at, Cell::kValueOffset));
   __ BranchShort(&cache_miss, ne, map, Operand(at));
   // We use Factory::the_hole_value() on purpose instead of loading from the
   // root array to force relocation to be able to later patch
@@ -2910,17 +2902,6 @@ void LCodeGen::DoReturn(LReturn* instr) {
 }
 
 
-void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
-  Register result = ToRegister(instr->result());
-  __ li(at, Operand(Handle<Object>(instr->hydrogen()->cell().handle())));
-  __ lw(result, FieldMemOperand(at, Cell::kValueOffset));
-  if (instr->hydrogen()->RequiresHoleCheck()) {
-    __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(eq, instr, Deoptimizer::kHole, result, Operand(at));
-  }
-}
-
-
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
@@ -2950,37 +2931,12 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
   }
   ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
-  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode,
+                                                       PREMONOMORPHIC).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
 
-void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
-  Register value = ToRegister(instr->value());
-  Register cell = scratch0();
-
-  // Load the cell.
-  __ li(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.
-    Register payload = ToRegister(instr->temp());
-    __ lw(payload, FieldMemOperand(cell, Cell::kValueOffset));
-    __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(eq, instr, Deoptimizer::kHole, payload, Operand(at));
-  }
-
-  // Store the value.
-  __ sw(value, FieldMemOperand(cell, Cell::kValueOffset));
-  // Cells are always rescanned, so no write barrier here.
-}
-
-
-
 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
   Register context = ToRegister(instr->context());
   Register result = ToRegister(instr->result());
@@ -3077,8 +3033,9 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
   if (FLAG_vector_ics) {
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
-  Handle<Code> ic =
-      CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(
+                        isolate(), NOT_CONTEXTUAL,
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3388,7 +3345,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code();
+  Handle<Code> ic =
+      CodeFactory::KeyedLoadICInOptimizedCode(
+          isolate(), instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -4280,7 +4239,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
   __ li(StoreDescriptor::NameRegister(), Operand(instr->name()));
-  Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->language_mode());
+  Handle<Code> ic =
+      StoreIC::initialize_stub(isolate(), instr->language_mode(),
+                               instr->hydrogen()->initialization_state());
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -4511,8 +4472,9 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
   DCHECK(ToRegister(instr->key()).is(StoreDescriptor::NameRegister()));
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
-  Handle<Code> ic =
-      CodeFactory::KeyedStoreIC(isolate(), instr->language_mode()).code();
+  Handle<Code> ic = CodeFactory::KeyedStoreICInOptimizedCode(
+                        isolate(), instr->language_mode(),
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -5250,7 +5212,7 @@ void LCodeGen::DoCheckValue(LCheckValue* instr) {
   if (isolate()->heap()->InNewSpace(*object)) {
     Register reg = ToRegister(instr->value());
     Handle<Cell> cell = isolate()->factory()->NewCell(object);
-    __ li(at, Operand(Handle<Object>(cell)));
+    __ li(at, Operand(cell));
     __ lw(at, FieldMemOperand(at, Cell::kValueOffset));
     DeoptimizeIf(ne, instr, Deoptimizer::kValueMismatch, reg, Operand(at));
   } else {
index 8d1b45f..b710ef9 100644 (file)
@@ -2087,14 +2087,6 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
 }
 
 
-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 =
@@ -2109,16 +2101,6 @@ LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* 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 =
index 1ccba14..ede4cbe 100644 (file)
@@ -100,7 +100,6 @@ class LCodeGen;
   V(LoadRoot)                                \
   V(LoadFieldByIndex)                        \
   V(LoadFunctionPrototype)                   \
-  V(LoadGlobalCell)                          \
   V(LoadGlobalGeneric)                       \
   V(LoadKeyed)                               \
   V(LoadKeyedGeneric)                        \
@@ -141,7 +140,6 @@ class LCodeGen;
   V(StoreCodeEntry)                          \
   V(StoreContextSlot)                        \
   V(StoreFrameContext)                       \
-  V(StoreGlobalCell)                         \
   V(StoreKeyed)                              \
   V(StoreKeyedGeneric)                       \
   V(StoreNamedField)                         \
@@ -1667,13 +1665,6 @@ class LLoadKeyedGeneric FINAL : public LTemplateInstruction<1, 3, 1> {
 };
 
 
-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,
@@ -1695,21 +1686,6 @@ class LLoadGlobalGeneric FINAL : public LTemplateInstruction<1, 2, 1> {
 };
 
 
-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) {
index 972530e..406348f 100644 (file)
@@ -86,6 +86,7 @@ void MacroAssembler::LoadRoot(Register destination,
 
 void MacroAssembler::StoreRoot(Register source,
                                Heap::RootListIndex index) {
+  DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
   sw(source, MemOperand(s6, index << kPointerSizeLog2));
 }
 
@@ -94,6 +95,7 @@ void MacroAssembler::StoreRoot(Register source,
                                Heap::RootListIndex index,
                                Condition cond,
                                Register src1, const Operand& src2) {
+  DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
   Branch(2, NegateCondition(cond), src1, src2);
   sw(source, MemOperand(s6, index << kPointerSizeLog2));
 }
@@ -1549,6 +1551,18 @@ void MacroAssembler::BranchF(Label* target,
 }
 
 
+void MacroAssembler::FmoveLow(FPURegister dst, Register src_low) {
+  if (IsFp64Mode()) {
+    DCHECK(!src_low.is(at));
+    mfhc1(at, dst);
+    mtc1(src_low, dst);
+    mthc1(at, dst);
+  } else {
+    mtc1(src_low, dst);
+  }
+}
+
+
 void MacroAssembler::Move(FPURegister dst, float imm) {
   li(at, Operand(bit_cast<int32_t>(imm)));
   mtc1(at, dst);
@@ -3221,47 +3235,22 @@ void MacroAssembler::DebugBreak() {
 // ---------------------------------------------------------------------------
 // Exception handling.
 
-void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
-                                    int handler_index) {
+void MacroAssembler::PushStackHandler() {
   // Adjust this code if not the case.
-  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kSize == 1 * 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 a0-a3 and s0.
-  // t1-t3 are available. We will build up the handler from the bottom by
-  // pushing on the stack.
-  // Set up the code object (t1) and the state (t2) for pushing.
-  unsigned state =
-      StackHandler::IndexField::encode(handler_index) |
-      StackHandler::KindField::encode(kind);
-  li(t1, Operand(CodeObject()), CONSTANT_SIZE);
-  li(t2, Operand(state));
-
-  // Push the frame pointer, context, state, and code object.
-  if (kind == StackHandler::JS_ENTRY) {
-    DCHECK_EQ(static_cast<Smi*>(0), Smi::FromInt(0));
-    // The second zero_reg indicates no context.
-    // The first zero_reg is the NULL frame pointer.
-    // The operands are reversed to match the order of MultiPush/Pop.
-    Push(zero_reg, zero_reg, t2, t1);
-  } else {
-    MultiPush(t1.bit() | t2.bit() | cp.bit() | fp.bit());
-  }
 
   // Link the current handler as the next handler.
   li(t2, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
   lw(t1, MemOperand(t2));
   push(t1);
+
   // Set this new handler as the current one.
   sw(sp, MemOperand(t2));
 }
 
 
-void MacroAssembler::PopTryHandler() {
+void MacroAssembler::PopStackHandler() {
   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
   pop(a1);
   Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
@@ -3270,101 +3259,6 @@ void MacroAssembler::PopTryHandler() {
 }
 
 
-void MacroAssembler::JumpToHandlerEntry() {
-  // 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.
-  lw(a3, FieldMemOperand(a1, Code::kHandlerTableOffset));  // Handler table.
-  Addu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
-  srl(a2, a2, StackHandler::kKindWidth);  // Handler index.
-  sll(a2, a2, kPointerSizeLog2);
-  Addu(a2, a3, a2);
-  lw(a2, MemOperand(a2));  // Smi-tagged offset.
-  Addu(a1, a1, Operand(Code::kHeaderSize - kHeapObjectTag));  // Code start.
-  sra(t9, a2, kSmiTagSize);
-  Addu(t9, t9, a1);
-  Jump(t9);  // Jump.
-}
-
-
-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);
-
-  // The exception is expected in v0.
-  Move(v0, value);
-
-  // Drop the stack pointer to the top of the top handler.
-  li(a3, Operand(ExternalReference(Isolate::kHandlerAddress,
-                                   isolate())));
-  lw(sp, MemOperand(a3));
-
-  // Restore the next handler.
-  pop(a2);
-  sw(a2, MemOperand(a3));
-
-  // Get the code object (a1) and state (a2).  Restore the context and frame
-  // pointer.
-  MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit());
-
-  // 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.
-  Label done;
-  Branch(&done, eq, cp, Operand(zero_reg));
-  sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-  bind(&done);
-
-  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 v0.
-  if (!value.is(v0)) {
-    mov(v0, value);
-  }
-  // Drop the stack pointer to the top of the top stack handler.
-  li(a3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
-  lw(sp, MemOperand(a3));
-
-  // Unwind the handlers until the ENTRY handler is found.
-  Label fetch_next, check_kind;
-  jmp(&check_kind);
-  bind(&fetch_next);
-  lw(sp, MemOperand(sp, StackHandlerConstants::kNextOffset));
-
-  bind(&check_kind);
-  STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
-  lw(a2, MemOperand(sp, StackHandlerConstants::kStateOffset));
-  And(a2, a2, Operand(StackHandler::KindField::kMask));
-  Branch(&fetch_next, ne, a2, Operand(zero_reg));
-
-  // Set the top handler address to next handler past the top ENTRY handler.
-  pop(a2);
-  sw(a2, MemOperand(a3));
-
-  // Get the code object (a1) and state (a2).  Clear the context and frame
-  // pointer (0 was saved in the handler).
-  MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit());
-
-  JumpToHandlerEntry();
-}
-
-
 void MacroAssembler::Allocate(int object_size,
                               Register result,
                               Register scratch1,
@@ -4321,6 +4215,20 @@ void MacroAssembler::IsObjectNameType(Register object,
 // Support functions.
 
 
+void MacroAssembler::GetMapConstructor(Register result, Register map,
+                                       Register temp, Register temp2) {
+  Label done, loop;
+  lw(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
+  bind(&loop);
+  JumpIfSmi(result, &done);
+  GetObjectType(result, temp, temp2);
+  Branch(&done, ne, temp2, Operand(MAP_TYPE));
+  lw(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset));
+  Branch(&loop);
+  bind(&done);
+}
+
+
 void MacroAssembler::TryGetFunctionPrototype(Register function,
                                              Register result,
                                              Register scratch,
@@ -4373,7 +4281,7 @@ void MacroAssembler::TryGetFunctionPrototype(Register function,
     // Non-instance prototype: Fetch prototype from constructor field
     // in initial map.
     bind(&non_instance);
-    lw(result, FieldMemOperand(result, Map::kConstructorOffset));
+    GetMapConstructor(result, result, scratch, scratch);
   }
 
   // All done.
index 02845e2..481c7d4 100644 (file)
@@ -241,10 +241,16 @@ class MacroAssembler: public Assembler {
     Mfhc1(dst_high, src);
   }
 
+  inline void FmoveHigh(FPURegister dst, Register src_high) {
+    Mthc1(src_high, dst);
+  }
+
   inline void FmoveLow(Register dst_low, FPURegister src) {
     mfc1(dst_low, src);
   }
 
+  void FmoveLow(FPURegister dst, Register src_low);
+
   inline void Move(FPURegister dst, Register src_low, Register src_high) {
     mtc1(src_low, dst);
     Mthc1(src_high, dst);
@@ -963,19 +969,12 @@ class MacroAssembler: public Assembler {
   // -------------------------------------------------------------------------
   // Exception handling.
 
-  // Push a new try handler and link into try handler chain.
-  void PushTryHandler(StackHandler::Kind kind, int handler_index);
+  // Push a new stack handler and link into stack handler chain.
+  void PushStackHandler();
 
-  // Unlink the stack handler on top of the stack from the try handler chain.
+  // Unlink the stack handler on top of the stack from the stack 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);
+  void PopStackHandler();
 
   // Copies a fixed number of fields of heap objects from src to dst.
   void CopyFields(Register dst, Register src, RegList temps, int field_count);
@@ -998,6 +997,11 @@ class MacroAssembler: public Assembler {
   // -------------------------------------------------------------------------
   // Support functions.
 
+  // Machine code version of Map::GetConstructor().
+  // |temp| holds |result|'s map when done, and |temp2| its instance type.
+  void GetMapConstructor(Register result, Register map, Register temp,
+                         Register temp2);
+
   // 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
@@ -1649,10 +1653,6 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
                           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);
index 79f337d..7ea3841 100644 (file)
@@ -1935,7 +1935,7 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
             // Logical right-rotate of a word by a fixed number of bits. This
             // is special case of SRL instruction, added in MIPS32 Release 2.
             // RS field is equal to 00001.
-            *alu_out = (rt_u >> sa) | (rt_u << (32 - sa));
+            *alu_out = base::bits::RotateRight32(rt_u, sa);
           }
           break;
         case SRA:
@@ -1953,7 +1953,7 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
             // Logical right-rotate of a word by a variable number of bits.
             // This is special case od SRLV instruction, added in MIPS32
             // Release 2. SA field is equal to 00001.
-            *alu_out = (rt_u >> rs_u) | (rt_u << (32 - rs_u));
+            *alu_out = base::bits::RotateRight32(rt_u, rs_u);
           }
           break;
         case SRAV:
index dede337..76117d0 100644 (file)
@@ -194,6 +194,43 @@ Address Assembler::break_address_from_return_address(Address pc) {
 }
 
 
+void Assembler::set_target_internal_reference_encoded_at(Address pc,
+                                                         Address target) {
+  // Encoded internal references are lui/ori load of 48-bit absolute address.
+  Instr instr_lui = Assembler::instr_at(pc + 0 * Assembler::kInstrSize);
+  Instr instr_ori = Assembler::instr_at(pc + 1 * Assembler::kInstrSize);
+  Instr instr_ori2 = Assembler::instr_at(pc + 3 * Assembler::kInstrSize);
+  DCHECK(Assembler::IsLui(instr_lui));
+  DCHECK(Assembler::IsOri(instr_ori));
+  DCHECK(Assembler::IsOri(instr_ori2));
+  instr_lui &= ~kImm16Mask;
+  instr_ori &= ~kImm16Mask;
+  instr_ori2 &= ~kImm16Mask;
+  int64_t imm = reinterpret_cast<int64_t>(target);
+  DCHECK((imm & 3) == 0);
+  Assembler::instr_at_put(pc + 0 * Assembler::kInstrSize,
+                          instr_lui | ((imm >> 32) & kImm16Mask));
+  Assembler::instr_at_put(pc + 1 * Assembler::kInstrSize,
+                          instr_ori | ((imm >> 16) & kImm16Mask));
+  Assembler::instr_at_put(pc + 3 * Assembler::kInstrSize,
+                          instr_ori | (imm & kImm16Mask));
+  // Currently used only by deserializer, and all code will be flushed
+  // after complete deserialization, no need to flush on each reference.
+}
+
+
+void Assembler::deserialization_set_target_internal_reference_at(
+    Address pc, Address target, RelocInfo::Mode mode) {
+  if (mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
+    DCHECK(IsLui(instr_at(pc)));
+    set_target_internal_reference_encoded_at(pc, target);
+  } else {
+    DCHECK(mode == RelocInfo::INTERNAL_REFERENCE);
+    Memory::Address_at(pc) = target;
+  }
+}
+
+
 Object* RelocInfo::target_object() {
   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
   return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_));
@@ -223,12 +260,38 @@ void RelocInfo::set_target_object(Object* target,
 }
 
 
-Address RelocInfo::target_reference() {
+Address RelocInfo::target_external_reference() {
   DCHECK(rmode_ == EXTERNAL_REFERENCE);
   return Assembler::target_address_at(pc_, host_);
 }
 
 
+Address RelocInfo::target_internal_reference() {
+  if (rmode_ == INTERNAL_REFERENCE) {
+    return Memory::Address_at(pc_);
+  } else {
+    // Encoded internal references are lui/ori load of 48-bit absolute address.
+    DCHECK(rmode_ == INTERNAL_REFERENCE_ENCODED);
+    Instr instr_lui = Assembler::instr_at(pc_ + 0 * Assembler::kInstrSize);
+    Instr instr_ori = Assembler::instr_at(pc_ + 1 * Assembler::kInstrSize);
+    Instr instr_ori2 = Assembler::instr_at(pc_ + 3 * Assembler::kInstrSize);
+    DCHECK(Assembler::IsLui(instr_lui));
+    DCHECK(Assembler::IsOri(instr_ori));
+    DCHECK(Assembler::IsOri(instr_ori2));
+    int64_t imm = (instr_lui & static_cast<int64_t>(kImm16Mask)) << 32;
+    imm |= (instr_ori & static_cast<int64_t>(kImm16Mask)) << 16;
+    imm |= (instr_ori2 & static_cast<int64_t>(kImm16Mask));
+    return reinterpret_cast<Address>(imm);
+  }
+}
+
+
+Address RelocInfo::target_internal_reference_address() {
+  DCHECK(rmode_ == INTERNAL_REFERENCE || rmode_ == INTERNAL_REFERENCE_ENCODED);
+  return reinterpret_cast<Address>(pc_);
+}
+
+
 Address RelocInfo::target_runtime_entry(Assembler* origin) {
   DCHECK(IsRuntimeEntry(rmode_));
   return target_address();
@@ -301,8 +364,8 @@ Address RelocInfo::call_address() {
   DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
   // The pc_ offset of 0 assumes mips patched return sequence per
-  // debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or
-  // debug break slot per BreakLocationIterator::SetDebugBreakAtSlot().
+  // debug-mips.cc BreakLocation::SetDebugBreakAtReturn(), or
+  // debug break slot per BreakLocation::SetDebugBreakAtSlot().
   return Assembler::target_address_at(pc_, host_);
 }
 
@@ -311,8 +374,8 @@ void RelocInfo::set_call_address(Address target) {
   DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
   // The pc_ offset of 0 assumes mips patched return sequence per
-  // debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or
-  // debug break slot per BreakLocationIterator::SetDebugBreakAtSlot().
+  // debug-mips.cc BreakLocation::SetDebugBreakAtReturn(), or
+  // debug break slot per BreakLocation::SetDebugBreakAtSlot().
   Assembler::set_target_address_at(pc_, host_, target);
   if (host() != NULL) {
     Object* target_code = Code::GetCodeFromTargetAddress(target);
@@ -340,11 +403,16 @@ void RelocInfo::set_call_object(Object* target) {
 
 
 void RelocInfo::WipeOut() {
-  DCHECK(IsEmbeddedObject(rmode_) ||
-         IsCodeTarget(rmode_) ||
-         IsRuntimeEntry(rmode_) ||
-         IsExternalReference(rmode_));
-  Assembler::set_target_address_at(pc_, host_, NULL);
+  DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
+         IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
+         IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_));
+  if (IsInternalReference(rmode_)) {
+    Memory::Address_at(pc_) = NULL;
+  } else if (IsInternalReferenceEncoded(rmode_)) {
+    Assembler::set_target_internal_reference_encoded_at(pc_, nullptr);
+  } else {
+    Assembler::set_target_address_at(pc_, host_, NULL);
+  }
 }
 
 
@@ -380,6 +448,9 @@ void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
     visitor->VisitCell(this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     visitor->VisitExternalReference(this);
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE ||
+             mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
+    visitor->VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     visitor->VisitCodeAgeSequence(this);
   } else if (((RelocInfo::IsJSReturn(mode) &&
@@ -405,6 +476,9 @@ void RelocInfo::Visit(Heap* heap) {
     StaticVisitor::VisitCell(heap, this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     StaticVisitor::VisitExternalReference(this);
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE ||
+             mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
+    StaticVisitor::VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     StaticVisitor::VisitCodeAgeSequence(heap, this);
   } else if (heap->isolate()->debug()->has_break_points() &&
index 4ce970d..9501371 100644 (file)
 // modified significantly by Google Inc.
 // Copyright 2012 the V8 project authors. All rights reserved.
 
-
 #include "src/v8.h"
 
 #if V8_TARGET_ARCH_MIPS64
 
 #include "src/base/cpu.h"
 #include "src/mips64/assembler-mips64-inl.h"
-#include "src/serialize.h"
 
 namespace v8 {
 namespace internal {
@@ -192,27 +190,6 @@ bool RelocInfo::IsInConstantPool() {
 }
 
 
-// Patch the code at the current address with the supplied instructions.
-void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
-  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_MIPS();
-}
-
-
 // -----------------------------------------------------------------------------
 // Implementation of Operand and MemOperand.
 // See assembler-mips-inl.h for inlined constructors.
@@ -635,7 +612,7 @@ bool Assembler::IsAndImmediate(Instr instr) {
 }
 
 
-int64_t Assembler::target_at(int64_t pos, bool is_internal) {
+int Assembler::target_at(int pos, bool is_internal) {
   if (is_internal) {
     int64_t* p = reinterpret_cast<int64_t*>(buffer_ + pos);
     int64_t address = *p;
@@ -643,7 +620,8 @@ int64_t Assembler::target_at(int64_t pos, bool is_internal) {
       return kEndOfChain;
     } else {
       int64_t instr_address = reinterpret_cast<int64_t>(p);
-      int64_t delta = instr_address - address;
+      DCHECK(instr_address - address < INT_MAX);
+      int delta = static_cast<int>(instr_address - address);
       DCHECK(pos > delta);
       return pos - delta;
     }
@@ -689,7 +667,8 @@ int64_t Assembler::target_at(int64_t pos, bool is_internal) {
       return kEndOfChain;
     } else {
       uint64_t instr_address = reinterpret_cast<int64_t>(buffer_ + pos);
-      int64_t delta = instr_address - imm;
+      DCHECK(instr_address - imm < INT_MAX);
+      int delta = static_cast<int>(instr_address - imm);
       DCHECK(pos > delta);
       return pos - delta;
     }
@@ -701,7 +680,7 @@ int64_t Assembler::target_at(int64_t pos, bool is_internal) {
     } else {
       uint64_t instr_address = reinterpret_cast<int64_t>(buffer_ + pos);
       instr_address &= kImm28Mask;
-      int64_t delta = instr_address - imm28;
+      int delta = static_cast<int>(instr_address - imm28);
       DCHECK(pos > delta);
       return pos - delta;
     }
@@ -709,8 +688,7 @@ int64_t Assembler::target_at(int64_t pos, bool is_internal) {
 }
 
 
-void Assembler::target_at_put(int64_t pos, int64_t target_pos,
-                              bool is_internal) {
+void Assembler::target_at_put(int pos, int target_pos, bool is_internal) {
   if (is_internal) {
     uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos;
     *reinterpret_cast<uint64_t*>(buffer_ + pos) = imm;
@@ -796,7 +774,7 @@ void Assembler::print(Label* L) {
 
 void Assembler::bind_to(Label* L, int pos) {
   DCHECK(0 <= pos && pos <= pc_offset());  // Must have valid binding position.
-  int32_t trampoline_pos = kInvalidSlotPos;
+  int trampoline_pos = kInvalidSlotPos;
   bool is_internal = false;
   if (L->is_linked() && !trampoline_emitted_) {
     unbound_labels_count_--;
@@ -804,8 +782,8 @@ void Assembler::bind_to(Label* L, int pos) {
   }
 
   while (L->is_linked()) {
-    int32_t fixup_pos = L->pos();
-    int32_t dist = pos - fixup_pos;
+    int fixup_pos = L->pos();
+    int dist = pos - fixup_pos;
     is_internal = internal_reference_positions_.find(fixup_pos) !=
                   internal_reference_positions_.end();
     next(L, is_internal);  // Call next before overwriting link with target at
index 5ad98f6..1ca1a87 100644 (file)
@@ -41,8 +41,8 @@
 #include <set>
 
 #include "src/assembler.h"
+#include "src/compiler.h"
 #include "src/mips64/constants-mips64.h"
-#include "src/serialize.h"
 
 namespace v8 {
 namespace internal {
@@ -539,6 +539,11 @@ class Assembler : public AssemblerBase {
         target);
   }
 
+  // This sets the internal reference at the pc.
+  inline static void deserialization_set_target_internal_reference_at(
+      Address pc, Address target,
+      RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
+
   // Size of an instruction.
   static const int kInstrSize = sizeof(Instr);
 
@@ -554,14 +559,11 @@ class Assembler : public AssemblerBase {
   static const int kSpecialTargetSize = 0;
 
   // Number of consecutive instructions used to store 32bit/64bit constant.
-  // Before jump-optimizations, this constant was used in
-  // RelocInfo::target_address_address() function to tell serializer address of
-  // the instruction that follows LUI/ORI instruction pair. Now, with new jump
-  // optimization, where jump-through-register instruction that usually
-  // follows LUI/ORI pair is substituted with J/JAL, this constant equals
-  // to 3 instructions (LUI+ORI+J/JAL/JR/JALR).
-  static const int kInstructionsFor32BitConstant = 3;
-  static const int kInstructionsFor64BitConstant = 5;
+  // This constant was used in RelocInfo::target_address_address() function
+  // to tell serializer address of the instruction that follows
+  // LUI/ORI instruction pair.
+  static const int kInstructionsFor32BitConstant = 2;
+  static const int kInstructionsFor64BitConstant = 4;
 
   // Distance between the instruction referring to the address of the call
   // target and the return address.
@@ -584,6 +586,8 @@ class Assembler : public AssemblerBase {
   // Number of instructions used for the JS return sequence. The constant is
   // used by the debugger to patch the JS return sequence.
   static const int kJSReturnSequenceInstructions = 7;
+  static const int kJSReturnSequenceLength =
+      kJSReturnSequenceInstructions * kInstrSize;
   static const int kDebugBreakSlotInstructions = 6;
   static const int kDebugBreakSlotLength =
       kDebugBreakSlotInstructions * kInstrSize;
@@ -1060,7 +1064,7 @@ class Assembler : public AssemblerBase {
 
   // Record a deoptimization reason that can be used by a log or cpu profiler.
   // Use --trace-deopt to enable.
-  void RecordDeoptReason(const int reason, const int raw_position);
+  void RecordDeoptReason(const int reason, const SourcePosition position);
 
   static int RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
                                        intptr_t pc_delta);
@@ -1165,13 +1169,16 @@ class Assembler : public AssemblerBase {
   // the relocation info.
   TypeFeedbackId recorded_ast_id_;
 
+  inline static void set_target_internal_reference_encoded_at(Address pc,
+                                                              Address target);
+
   int64_t buffer_space() const { return reloc_info_writer.pos() - pc_; }
 
   // Decode branch instruction at pos and return branch target pos.
-  int64_t target_at(int64_t pos, bool is_internal);
+  int target_at(int pos, bool is_internal);
 
   // Patch branch instruction at pos to branch to given branch target pos.
-  void target_at_put(int64_t pos, int64_t target_pos, bool is_internal);
+  void target_at_put(int pos, int target_pos, bool is_internal);
 
   // Say if we need to relocate with this mode.
   bool MustUseReg(RelocInfo::Mode rmode);
index 89fda10..24d4a80 100644 (file)
@@ -950,7 +950,9 @@ static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
   // Push function as parameter to the runtime call.
   __ Push(a1, a1);
   // Whether to compile in a background thread.
-  __ Push(masm->isolate()->factory()->ToBoolean(concurrent));
+  __ LoadRoot(
+      at, concurrent ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex);
+  __ push(at);
 
   __ CallRuntime(Runtime::kCompileOptimized, 2);
   // Restore receiver.
@@ -1357,49 +1359,100 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
 }
 
 
-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;
+static void Generate_CheckStackOverflow(MacroAssembler* masm,
+                                        const int calleeOffset) {
+  // 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(a2, Heap::kRealStackLimitRootIndex);
+  // Make a2 the space we have left. The stack might already be overflowed
+  // here which will cause a2 to become negative.
+  __ dsubu(a2, sp, a2);
+  // Check if the arguments will overflow the stack.
+  __ SmiScale(a7, v0, kPointerSizeLog2);
+  __ Branch(&okay, gt, a2, Operand(a7));  // Signed comparison.
+
+  // Out of stack space.
+  __ ld(a1, MemOperand(fp, calleeOffset));
+  __ Push(a1, v0);
+  __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+
+  __ bind(&okay);
+}
+
+
+static void Generate_PushAppliedArguments(MacroAssembler* masm,
+                                          const int argumentsOffset,
+                                          const int indexOffset,
+                                          const int limitOffset) {
+  Label entry, loop;
+  __ ld(a0, MemOperand(fp, indexOffset));
+  __ Branch(&entry);
+
+  // Load the current argument from the arguments array and push it to the
+  // stack.
+  // a0: current argument index
+  __ bind(&loop);
+  __ ld(a1, MemOperand(fp, argumentsOffset));
+  __ Push(a1, a0);
+
+  // Call the runtime to access the property in the arguments array.
+  __ CallRuntime(Runtime::kGetProperty, 2);
+  __ push(v0);
+
+  // Use inline caching to access the arguments.
+  __ ld(a0, MemOperand(fp, indexOffset));
+  __ Daddu(a0, a0, Operand(Smi::FromInt(1)));
+  __ sd(a0, MemOperand(fp, indexOffset));
+
+  // Test if the copy loop has finished copying all the elements from the
+  // arguments object.
+  __ bind(&entry);
+  __ ld(a1, MemOperand(fp, limitOffset));
+  __ Branch(&loop, ne, a0, Operand(a1));
+
+  // On exit, the pushed arguments count is in a0, untagged
+  __ SmiUntag(a0);
+}
+
+
+// Used by FunctionApply and ReflectApply
+static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
+  const int kFormalParameters = targetIsArgument ? 3 : 2;
+  const int kStackSize = kFormalParameters + 1;
 
   {
     FrameScope frame_scope(masm, StackFrame::INTERNAL);
+    const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize;
+    const int kReceiverOffset = kArgumentsOffset + kPointerSize;
+    const int kFunctionOffset = kReceiverOffset + kPointerSize;
+
     __ ld(a0, MemOperand(fp, kFunctionOffset));  // Get the function.
     __ push(a0);
-    __ ld(a0, MemOperand(fp, kArgsOffset));  // Get the args array.
+    __ ld(a0, MemOperand(fp, kArgumentsOffset));  // Get the args array.
     __ push(a0);
+
     // Returns (in v0) number of arguments to copy to stack as Smi.
-    __ 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(a2, Heap::kRealStackLimitRootIndex);
-    // Make a2 the space we have left. The stack might already be overflowed
-    // here which will cause a2 to become negative.
-    __ dsubu(a2, sp, a2);
-    // Check if the arguments will overflow the stack.
-    __ SmiScale(a7, v0, kPointerSizeLog2);
-    __ Branch(&okay, gt, a2, Operand(a7));  // Signed comparison.
-
-    // Out of stack space.
-    __ ld(a1, MemOperand(fp, kFunctionOffset));
-    __ Push(a1, v0);
-    __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
-    // End of stack check.
+    if (targetIsArgument) {
+      __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION);
+    } else {
+      __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
+    }
+
+    // Returns the result in v0.
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
 
     // Push current limit and index.
-    __ bind(&okay);
+    const int kIndexOffset =
+        StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
+    const int kLimitOffset =
+        StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
     __ mov(a1, zero_reg);
     __ Push(v0, a1);  // Limit and initial index.
 
     // Get the receiver.
-    __ ld(a0, MemOperand(fp, kRecvOffset));
+    __ ld(a0, MemOperand(fp, kReceiverOffset));
 
     // Check that the function is a JS function (otherwise it must be a proxy).
     Label push_receiver;
@@ -1455,36 +1508,12 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
     __ push(a0);
 
     // Copy all arguments from the array to the stack.
-    Label entry, loop;
-    __ ld(a0, MemOperand(fp, kIndexOffset));
-    __ Branch(&entry);
-
-    // Load the current argument from the arguments array and push it to the
-    // stack.
-    // a0: current argument index
-    __ bind(&loop);
-    __ ld(a1, MemOperand(fp, kArgsOffset));
-    __ Push(a1, a0);
-
-    // Call the runtime to access the property in the arguments array.
-    __ CallRuntime(Runtime::kGetProperty, 2);
-    __ push(v0);
-
-    // Use inline caching to access the arguments.
-    __ ld(a0, MemOperand(fp, kIndexOffset));
-    __ Daddu(a0, a0, Operand(Smi::FromInt(1)));
-    __ sd(a0, MemOperand(fp, kIndexOffset));
-
-    // Test if the copy loop has finished copying all the elements from the
-    // arguments object.
-    __ bind(&entry);
-    __ ld(a1, MemOperand(fp, kLimitOffset));
-    __ Branch(&loop, ne, a0, Operand(a1));
+    Generate_PushAppliedArguments(
+        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
 
     // Call the function.
     Label call_proxy;
     ParameterCount actual(a0);
-    __ SmiUntag(a0);
     __ ld(a1, MemOperand(fp, kFunctionOffset));
     __ GetObjectType(a1, a2, a2);
     __ Branch(&call_proxy, ne, a2, Operand(JS_FUNCTION_TYPE));
@@ -1493,7 +1522,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
 
     frame_scope.GenerateLeaveFrame();
     __ Ret(USE_DELAY_SLOT);
-    __ Daddu(sp, sp, Operand(3 * kPointerSize));  // In delay slot.
+    __ Daddu(sp, sp, Operand(kStackSize * kPointerSize));  // In delay slot.
 
     // Call the function proxy.
     __ bind(&call_proxy);
@@ -1507,7 +1536,89 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
   }
 
   __ Ret(USE_DELAY_SLOT);
-  __ Daddu(sp, sp, Operand(3 * kPointerSize));  // In delay slot.
+  __ Daddu(sp, sp, Operand(kStackSize * kPointerSize));  // In delay slot.
+}
+
+
+static void Generate_ConstructHelper(MacroAssembler* masm) {
+  const int kFormalParameters = 3;
+  const int kStackSize = kFormalParameters + 1;
+
+  {
+    FrameScope frame_scope(masm, StackFrame::INTERNAL);
+    const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize;
+    const int kArgumentsOffset = kNewTargetOffset + kPointerSize;
+    const int kFunctionOffset = kArgumentsOffset + kPointerSize;
+
+    // If newTarget is not supplied, set it to constructor
+    Label validate_arguments;
+    __ ld(a0, MemOperand(fp, kNewTargetOffset));
+    __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
+    __ Branch(&validate_arguments, ne, a0, Operand(at));
+    __ ld(a0, MemOperand(fp, kFunctionOffset));
+    __ sd(a0, MemOperand(fp, kNewTargetOffset));
+
+    // Validate arguments
+    __ bind(&validate_arguments);
+    __ ld(a0, MemOperand(fp, kFunctionOffset));  // get the function
+    __ push(a0);
+    __ ld(a0, MemOperand(fp, kArgumentsOffset));  // get the args array
+    __ push(a0);
+    __ ld(a0, MemOperand(fp, kNewTargetOffset));  // get the new.target
+    __ push(a0);
+    // Returns argument count in v0.
+    __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION);
+
+    // Returns result in v0.
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
+
+    // Push current limit and index.
+    const int kIndexOffset =
+        StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
+    const int kLimitOffset =
+        StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
+    __ push(v0);  // limit
+    __ mov(a1, zero_reg);  // initial index
+    __ push(a1);
+    // Push newTarget and callee functions
+    __ ld(a0, MemOperand(fp, kNewTargetOffset));
+    __ push(a0);
+    __ ld(a0, MemOperand(fp, kFunctionOffset));
+    __ push(a0);
+
+    // Copy all arguments from the array to the stack.
+    Generate_PushAppliedArguments(
+        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
+
+    // Use undefined feedback vector
+    __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
+    __ ld(a1, MemOperand(fp, kFunctionOffset));
+
+    // Call the function.
+    CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
+    __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
+
+    __ Drop(1);
+
+    // Leave internal frame.
+  }
+  __ jr(ra);
+  __ Daddu(sp, sp, Operand(kStackSize * kPointerSize));  // In delay slot.
+}
+
+
+void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+  Generate_ApplyHelper(masm, false);
+}
+
+
+void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
+  Generate_ApplyHelper(masm, true);
+}
+
+
+void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
+  Generate_ConstructHelper(masm);
 }
 
 
index 1a0b972..560e2c6 100644 (file)
@@ -11,6 +11,7 @@
 #include "src/codegen.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
@@ -1116,13 +1117,12 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   __ LoadRoot(a4, Heap::kExceptionRootIndex);
   __ Branch(&exception_returned, eq, a4, Operand(v0));
 
-  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;
+    ExternalReference pending_exception_address(
+        Isolate::kPendingExceptionAddress, isolate());
     __ li(a2, Operand(pending_exception_address));
     __ ld(a2, MemOperand(a2));
     __ LoadRoot(a4, Heap::kTheHoleValueRootIndex);
@@ -1142,25 +1142,52 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // Handling of exception.
   __ bind(&exception_returned);
 
-  // Retrieve the pending exception.
-  __ li(a2, Operand(pending_exception_address));
-  __ ld(v0, MemOperand(a2));
-
-  // Clear the pending exception.
-  __ li(a3, Operand(isolate()->factory()->the_hole_value()));
-  __ sd(a3, MemOperand(a2));
-
-  // Special handling of termination exceptions which are uncatchable
-  // by javascript code.
-  Label throw_termination_exception;
-  __ LoadRoot(a4, Heap::kTerminationExceptionRootIndex);
-  __ Branch(&throw_termination_exception, eq, v0, Operand(a4));
-
-  // Handle normal exception.
-  __ Throw(v0);
+  ExternalReference pending_handler_context_address(
+      Isolate::kPendingHandlerContextAddress, isolate());
+  ExternalReference pending_handler_code_address(
+      Isolate::kPendingHandlerCodeAddress, isolate());
+  ExternalReference pending_handler_offset_address(
+      Isolate::kPendingHandlerOffsetAddress, isolate());
+  ExternalReference pending_handler_fp_address(
+      Isolate::kPendingHandlerFPAddress, isolate());
+  ExternalReference pending_handler_sp_address(
+      Isolate::kPendingHandlerSPAddress, isolate());
+
+  // Ask the runtime for help to determine the handler. This will set v0 to
+  // contain the current pending exception, don't clobber it.
+  ExternalReference find_handler(Runtime::kFindExceptionHandler, isolate());
+  {
+    FrameScope scope(masm, StackFrame::MANUAL);
+    __ PrepareCallCFunction(3, 0, a0);
+    __ mov(a0, zero_reg);
+    __ mov(a1, zero_reg);
+    __ li(a2, Operand(ExternalReference::isolate_address(isolate())));
+    __ CallCFunction(find_handler, 3);
+  }
 
-  __ bind(&throw_termination_exception);
-  __ ThrowUncatchable(v0);
+  // Retrieve the handler context, SP and FP.
+  __ li(cp, Operand(pending_handler_context_address));
+  __ ld(cp, MemOperand(cp));
+  __ li(sp, Operand(pending_handler_sp_address));
+  __ ld(sp, MemOperand(sp));
+  __ li(fp, Operand(pending_handler_fp_address));
+  __ ld(fp, MemOperand(fp));
+
+  // If the handler is a JS frame, restore the context to the frame. Note that
+  // the context will be set to (cp == 0) for non-JS frames.
+  Label zero;
+  __ Branch(&zero, eq, cp, Operand(zero_reg));
+  __ sd(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  __ bind(&zero);
+
+  // Compute the handler entry address and jump to it.
+  __ li(a1, Operand(pending_handler_code_address));
+  __ ld(a1, MemOperand(a1));
+  __ li(a2, Operand(pending_handler_offset_address));
+  __ ld(a2, MemOperand(a2));
+  __ Daddu(a1, a1, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Daddu(t9, a1, a2);
+  __ Jump(t9);
 }
 
 
@@ -1253,7 +1280,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   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
+  // fp will be invalid because the PushStackHandler below sets it to 0 to
   // signal the existence of the JSEntry frame.
   __ li(a4, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
                                       isolate)));
@@ -1262,10 +1289,9 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ b(&exit);  // b exposes branch delay slot.
   __ nop();   // Branch delay slot nop.
 
-  // Invoke: Link this frame into the handler chain.  There's only one
-  // handler block in this code object, so its index is 0.
+  // Invoke: Link this frame into the handler chain.
   __ bind(&invoke);
-  __ PushTryHandler(StackHandler::JS_ENTRY, 0);
+  __ PushStackHandler();
   // If an exception not caught by another handler occurs, this handler
   // returns control to the code after the bal(&invoke) above, which
   // restores all kCalleeSaved registers (including cp and fp) to their
@@ -1309,7 +1335,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ Call(t9);
 
   // Unlink this frame from the handler chain.
-  __ PopTryHandler();
+  __ PopStackHandler();
 
   __ bind(&exit);  // v0 holds result
   // Check if the current stack frame is marked as the outermost JS frame.
@@ -1352,12 +1378,8 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
   Register result = v0;
   DCHECK(!scratch.is(receiver) && !scratch.is(index));
   DCHECK(!FLAG_vector_ics ||
-         (!scratch.is(VectorLoadICDescriptor::VectorRegister()) &&
-          result.is(VectorLoadICDescriptor::SlotRegister())));
+         !scratch.is(VectorLoadICDescriptor::VectorRegister()));
 
-  // 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.
@@ -1368,7 +1390,7 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
   __ Ret();
 
   StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
+  char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&miss);
   PropertyAccessCompiler::TailCallBuiltin(
@@ -1937,10 +1959,13 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
   __ bind(&adaptor_frame);
   __ ld(a1, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset));
   if (has_new_target()) {
+    Label skip_decrement;
+    __ Branch(&skip_decrement, eq, a1, Operand(Smi::FromInt(0)));
     // Subtract 1 from smi-tagged arguments count.
     __ SmiUntag(a1);
     __ Daddu(a1, a1, Operand(-1));
     __ SmiTag(a1);
+    __ bind(&skip_decrement);
   }
   __ sd(a1, MemOperand(sp, 0));
   __ SmiScale(at, a1, kPointerSizeLog2);
@@ -2058,7 +2083,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   // 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);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 #else  // V8_INTERPRETED_REGEXP
 
   // Stack frame on entry.
@@ -2374,17 +2399,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   __ ld(v0, MemOperand(a2, 0));
   __ Branch(&runtime, eq, v0, Operand(a1));
 
-  __ sd(a1, MemOperand(a2, 0));  // Clear pending exception.
-
-  // Check if the exception is a termination. If so, throw as uncatchable.
-  __ LoadRoot(a0, Heap::kTerminationExceptionRootIndex);
-  Label termination_exception;
-  __ Branch(&termination_exception, eq, v0, Operand(a0));
-
-  __ Throw(v0);
-
-  __ bind(&termination_exception);
-  __ ThrowUncatchable(v0);
+  // For exception, throw the exception again.
+  __ TailCallRuntime(Runtime::kRegExpExecReThrow, 4, 1);
 
   __ bind(&failure);
   // For failure and exception return null.
@@ -2480,7 +2496,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
 
   // Do the runtime call to execute the regexp.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 
   // Deferred code for string handling.
   // (6) Not a long external string?  If yes, go to (8).
@@ -3070,7 +3086,7 @@ void CallICStub::GenerateMiss(MacroAssembler* masm) {
 
 
 void StringCharCodeAtGenerator::GenerateSlow(
-    MacroAssembler* masm,
+    MacroAssembler* masm, EmbedMode embed_mode,
     const RuntimeCallHelper& call_helper) {
   __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
 
@@ -3084,7 +3100,12 @@ void StringCharCodeAtGenerator::GenerateSlow(
               DONT_DO_SMI_CHECK);
   call_helper.BeforeCall(masm);
   // Consumed by runtime conversion function:
-  __ Push(object_, index_);
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ Push(VectorLoadICDescriptor::VectorRegister(),
+            VectorLoadICDescriptor::SlotRegister(), object_, index_);
+  } else {
+    __ Push(object_, index_);
+  }
   if (index_flags_ == STRING_INDEX_IS_NUMBER) {
     __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
   } else {
@@ -3097,7 +3118,12 @@ void StringCharCodeAtGenerator::GenerateSlow(
   // have a chance to overwrite it.
 
   __ Move(index_, v0);
-  __ pop(object_);
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ Pop(VectorLoadICDescriptor::SlotRegister(),
+           VectorLoadICDescriptor::VectorRegister(), object_);
+  } else {
+    __ pop(object_);
+  }
   // Reload the instance type.
   __ ld(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
   __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
@@ -3428,7 +3454,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
 
   // Just jump to runtime to create the sub string.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kSubString, 3, 1);
+  __ TailCallRuntime(Runtime::kSubStringRT, 3, 1);
 
   __ bind(&single_char);
   // v0: original string
@@ -3621,7 +3647,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
   StringHelper::GenerateCompareFlatOneByteStrings(masm, a1, a0, a2, a3, a4, a5);
 
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+  __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
 }
 
 
@@ -3931,7 +3957,7 @@ void CompareICStub::GenerateStrings(MacroAssembler* masm) {
   if (equality) {
     __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
   } else {
-    __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+    __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
   }
 
   __ bind(&miss);
@@ -4548,7 +4574,7 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
   // Array literal has ElementsKind of FAST_*_DOUBLE_ELEMENTS.
   __ bind(&double_elements);
   __ ld(a5, FieldMemOperand(a1, JSObject::kElementsOffset));
-  __ StoreNumberToDoubleElements(a0, a3, a5, a7, t1, a2, &slow_elements);
+  __ StoreNumberToDoubleElements(a0, a3, a5, a7, t1, &slow_elements);
   __ Ret(USE_DELAY_SLOT);
   __ mov(v0, a0);
 }
@@ -4572,15 +4598,15 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
 
 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorLoadStub stub(isolate(), state());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawLoadStub stub(isolate(), state());
+  stub.GenerateForTrampoline(masm);
 }
 
 
 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorKeyedLoadStub stub(isolate());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawKeyedLoadStub stub(isolate());
+  stub.GenerateForTrampoline(masm);
 }
 
 
@@ -4598,6 +4624,243 @@ void CallIC_ArrayTrampolineStub::Generate(MacroAssembler* masm) {
 }
 
 
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+                             Register key, Register vector, Register slot,
+                             Register feedback, Register scratch1,
+                             Register scratch2, Register scratch3,
+                             bool is_polymorphic, Label* miss) {
+  // feedback initially contains the feedback array
+  Label next_loop, prepare_next;
+  Label load_smi_map, compare_map;
+  Label start_polymorphic;
+
+  Register receiver_map = scratch1;
+  Register cached_map = scratch2;
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &load_smi_map);
+  __ ld(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ bind(&compare_map);
+  __ ld(cached_map,
+        FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+  __ ld(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ Branch(&start_polymorphic, ne, receiver_map, Operand(cached_map));
+  // found, now call handler.
+  Register handler = feedback;
+  __ ld(handler, FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+  __ Daddu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(t9);
+
+  Register length = scratch3;
+  __ bind(&start_polymorphic);
+  __ ld(length, FieldMemOperand(feedback, FixedArray::kLengthOffset));
+  if (!is_polymorphic) {
+    // If the IC could be monomorphic we have to make sure we don't go past the
+    // end of the feedback array.
+    __ Branch(miss, eq, length, Operand(Smi::FromInt(2)));
+  }
+
+  Register too_far = length;
+  Register pointer_reg = feedback;
+
+  // +-----+------+------+-----+-----+ ... ----+
+  // | map | len  | wm0  | h0  | wm1 |      hN |
+  // +-----+------+------+-----+-----+ ... ----+
+  //                 0      1     2        len-1
+  //                              ^              ^
+  //                              |              |
+  //                         pointer_reg      too_far
+  //                         aka feedback     scratch3
+  // also need receiver_map (aka scratch1)
+  // use cached_map (scratch2) to look in the weak map values.
+  __ SmiScale(too_far, length, kPointerSizeLog2);
+  __ Daddu(too_far, feedback, Operand(too_far));
+  __ Daddu(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ Daddu(pointer_reg, feedback,
+           Operand(FixedArray::OffsetOfElementAt(2) - kHeapObjectTag));
+
+  __ bind(&next_loop);
+  __ ld(cached_map, MemOperand(pointer_reg));
+  __ ld(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ Branch(&prepare_next, ne, receiver_map, Operand(cached_map));
+  __ ld(handler, MemOperand(pointer_reg, kPointerSize));
+  __ Daddu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(t9);
+
+  __ bind(&prepare_next);
+  __ Daddu(pointer_reg, pointer_reg, Operand(kPointerSize * 2));
+  __ Branch(&next_loop, lt, pointer_reg, Operand(too_far));
+
+  // We exhausted our array of map handler pairs.
+  __ Branch(miss);
+
+  __ bind(&load_smi_map);
+  __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
+  __ Branch(&compare_map);
+}
+
+
+static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+                                  Register key, Register vector, Register slot,
+                                  Register weak_cell, Register scratch,
+                                  Label* miss) {
+  // feedback initially contains the feedback array
+  Label compare_smi_map;
+  Register receiver_map = scratch;
+  Register cached_map = weak_cell;
+
+  // Move the weak map into the weak_cell register.
+  __ ld(cached_map, FieldMemOperand(weak_cell, WeakCell::kValueOffset));
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &compare_smi_map);
+  __ ld(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ Branch(miss, ne, cached_map, Operand(receiver_map));
+
+  Register handler = weak_cell;
+  __ SmiScale(handler, slot, kPointerSizeLog2);
+  __ Daddu(handler, vector, Operand(handler));
+  __ ld(handler,
+        FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ Daddu(t9, handler, Code::kHeaderSize - kHeapObjectTag);
+  __ Jump(t9);
+
+  // In microbenchmarks, it made sense to unroll this code so that the call to
+  // the handler is duplicated for a HeapObject receiver and a Smi receiver.
+  // TODO(mvstanton): does this hold on ARM?
+  __ bind(&compare_smi_map);
+  __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
+  __ Branch(miss, ne, weak_cell, Operand(at));
+  __ SmiScale(handler, slot, kPointerSizeLog2);
+  __ Daddu(handler, vector, Operand(handler));
+  __ ld(handler,
+        FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ Daddu(t9, handler, Code::kHeaderSize - kHeapObjectTag);
+  __ Jump(t9);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // a1
+  Register name = VectorLoadICDescriptor::NameRegister();          // a2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // a3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // a0
+  Register feedback = a4;
+  Register scratch1 = a5;
+
+  __ SmiScale(feedback, slot, kPointerSizeLog2);
+  __ Daddu(feedback, vector, Operand(feedback));
+  __ ld(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ ld(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ LoadRoot(at, Heap::kWeakCellMapRootIndex);
+  __ Branch(&try_array, ne, scratch1, Operand(at));
+  HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback, scratch1,
+                        &miss);
+
+  // Is it a fixed array?
+  __ bind(&try_array);
+  __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+  __ Branch(&not_array, ne, scratch1, Operand(at));
+  HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, a6,
+                   a7, true, &miss);
+
+  __ bind(&not_array);
+  __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
+  __ Branch(&miss, ne, feedback, Operand(at));
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, code_flags,
+                                               false, receiver, name, feedback,
+                                               scratch1, a6, a7);
+
+  __ bind(&miss);
+  LoadIC::GenerateMiss(masm);
+}
+
+
+void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // a1
+  Register key = VectorLoadICDescriptor::NameRegister();           // a2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // a3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // a0
+  Register feedback = a4;
+  Register scratch1 = a5;
+
+  __ SmiScale(feedback, slot, kPointerSizeLog2);
+  __ Daddu(feedback, vector, Operand(feedback));
+  __ ld(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ ld(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ LoadRoot(at, Heap::kWeakCellMapRootIndex);
+  __ Branch(&try_array, ne, scratch1, Operand(at));
+  __ JumpIfNotSmi(key, &miss);
+  HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, scratch1,
+                        &miss);
+
+  __ bind(&try_array);
+  // Is it a fixed array?
+  __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+  __ Branch(&not_array, ne, scratch1, Operand(at));
+  // We have a polymorphic element handler.
+  __ JumpIfNotSmi(key, &miss);
+
+  Label polymorphic, try_poly_name;
+  __ bind(&polymorphic);
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, a6,
+                   a7, true, &miss);
+
+  __ bind(&not_array);
+  // Is it generic?
+  __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
+  __ Branch(&try_poly_name, ne, feedback, Operand(at));
+  Handle<Code> megamorphic_stub =
+      KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+  __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET);
+
+  __ bind(&try_poly_name);
+  // We might have a name in feedback, and a fixed array in the next slot.
+  __ Branch(&miss, ne, key, Operand(feedback));
+  // If the name comparison succeeded, we know we have a fixed array with
+  // at least one map/handler pair.
+  __ SmiScale(feedback, slot, kPointerSizeLog2);
+  __ Daddu(feedback, vector, Operand(feedback));
+  __ ld(feedback,
+        FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, a6,
+                   a7, false, &miss);
+
+  __ bind(&miss);
+  KeyedLoadIC::GenerateMiss(masm);
+}
+
+
 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
   if (masm->isolate()->function_entry_hook() != NULL) {
     ProfileEntryHookStub stub(masm->isolate());
@@ -5056,7 +5319,6 @@ static void CallApiFunctionAndReturn(
   }
 
   Label promote_scheduled_exception;
-  Label exception_handled;
   Label delete_allocated_handles;
   Label leave_exit_frame;
   Label return_value_loaded;
@@ -5077,13 +5339,8 @@ static void CallApiFunctionAndReturn(
   __ ld(at, MemOperand(s3, kLimitOffset));
   __ Branch(&delete_allocated_handles, ne, s1, Operand(at));
 
-  // Check if the function scheduled an exception.
+  // Leave the API exit frame.
   __ bind(&leave_exit_frame);
-  __ LoadRoot(a4, Heap::kTheHoleValueRootIndex);
-  __ li(at, Operand(ExternalReference::scheduled_exception_address(isolate)));
-  __ ld(a5, MemOperand(at));
-  __ Branch(&promote_scheduled_exception, ne, a4, Operand(a5));
-  __ bind(&exception_handled);
 
   bool restore_context = context_restore_operand != NULL;
   if (restore_context) {
@@ -5095,15 +5352,20 @@ static void CallApiFunctionAndReturn(
   } else {
     __ li(s0, Operand(stack_space));
   }
-  __ LeaveExitFrame(false, s0, !restore_context, EMIT_RETURN,
+  __ LeaveExitFrame(false, s0, !restore_context, NO_EMIT_RETURN,
                     stack_space_offset != kInvalidStackOffset);
+
+  // Check if the function scheduled an exception.
+  __ LoadRoot(a4, Heap::kTheHoleValueRootIndex);
+  __ li(at, Operand(ExternalReference::scheduled_exception_address(isolate)));
+  __ ld(a5, MemOperand(at));
+  __ Branch(&promote_scheduled_exception, ne, a4, Operand(a5));
+
+  __ Ret();
+
+  // Re-throw by promoting a scheduled exception.
   __ bind(&promote_scheduled_exception);
-  {
-    FrameScope frame(masm, StackFrame::INTERNAL);
-    __ CallExternalReference(
-        ExternalReference(Runtime::kPromoteScheduledException, isolate), 0);
-  }
-  __ jmp(&exception_handled);
+  __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
 
   // HandleScope limit has changed. Delete allocated extensions.
   __ bind(&delete_allocated_handles);
index 0bb0c4a..8ef247d 100644 (file)
 namespace v8 {
 namespace internal {
 
-bool BreakLocationIterator::IsDebugBreakAtReturn() {
-  return Debug::IsDebugBreakAtReturn(rinfo());
-}
-
-
-void BreakLocationIterator::SetDebugBreakAtReturn() {
+void BreakLocation::SetDebugBreakAtReturn() {
   // Mips return sequence:
   // mov sp, fp
   // lw fp, sp(0)
@@ -31,7 +26,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
 
   // Make sure this constant matches the number if instructions we emit.
   DCHECK(Assembler::kJSReturnSequenceInstructions == 7);
-  CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
+  CodePatcher patcher(pc(), Assembler::kJSReturnSequenceInstructions);
   // li and Call pseudo-instructions emit 6 + 2 instructions.
   patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int64_t>(
       debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry())),
@@ -44,29 +39,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
 }
 
 
-// Restore the JS frame exit code.
-void BreakLocationIterator::ClearDebugBreakAtReturn() {
-  rinfo()->PatchCode(original_rinfo()->pc(),
-                     Assembler::kJSReturnSequenceInstructions);
-}
-
-
-// A debug break in the exit code is identified by the JS frame exit code
-// having been patched with li/call psuedo-instrunction (liu/ori/jalr).
-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() {
+void BreakLocation::SetDebugBreakAtSlot() {
   DCHECK(IsDebugBreakSlot());
   // Patch the code changing the debug break slot code from:
   //   nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1)
@@ -78,7 +51,7 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
   // to a call to the debug break slot code.
   //   li t9, address   (4-instruction sequence on mips64)
   //   call t9          (jalr t9 / nop instruction pair)
-  CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
+  CodePatcher patcher(pc(), Assembler::kDebugBreakSlotInstructions);
   patcher.masm()->li(v8::internal::t9,
       Operand(reinterpret_cast<int64_t>(
           debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry())),
@@ -87,13 +60,6 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
 }
 
 
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
-  DCHECK(IsDebugBreakSlot());
-  rinfo()->PatchCode(original_rinfo()->pc(),
-                     Assembler::kDebugBreakSlotInstructions);
-}
-
-
 #define __ ACCESS_MASM(masm)
 
 
index e77faed..2b55695 100644 (file)
@@ -131,7 +131,7 @@ bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
 
 // This code tries to be close to ia32 code so that any changes can be
 // easily ported.
-void Deoptimizer::EntryGenerator::Generate() {
+void Deoptimizer::TableEntryGenerator::Generate() {
   GeneratePrologue();
 
   // Unlike on ARM we don't save all the registers, just the useful ones.
@@ -329,39 +329,66 @@ void Deoptimizer::EntryGenerator::Generate() {
 
 
 // Maximum size of a table entry generated below.
-const int Deoptimizer::table_entry_size_ = 11 * Assembler::kInstrSize;
+const int Deoptimizer::table_entry_size_ = 2 * Assembler::kInstrSize;
 
 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 table_start;
+  Label table_start, done, done_special, trampoline_jump;
   __ bind(&table_start);
-  for (int i = 0; i < count(); i++) {
-    Label start;
-    __ bind(&start);
-    __ daddiu(sp, sp, -1 * kPointerSize);
-    // Jump over the remaining deopt entries (including this one).
-    // This code is always reached by calling Jump, which puts the target (label
-    // start) into t9.
-    const int remaining_entries = (count() - i) * table_entry_size_;
-    __ Daddu(t9, t9, remaining_entries);
-    // 'at' was clobbered so we can only load the current entry value here.
-    __ li(t8, i);
-    __ jr(t9);  // Expose delay slot.
-    __ sd(t8, MemOperand(sp, 0 * kPointerSize));  // In the delay slot.
-
-    // Pad the rest of the code.
-    while (table_entry_size_ > (masm()->SizeOfCodeGeneratedSince(&start))) {
-      __ nop();
+  int kMaxEntriesBranchReach =
+      (1 << (kImm16Bits - 2)) / (table_entry_size_ / Assembler::kInstrSize);
+
+  if (count() <= kMaxEntriesBranchReach) {
+    // Common case.
+    for (int i = 0; i < count(); i++) {
+      Label start;
+      __ bind(&start);
+      DCHECK(is_int16(i));
+      __ Branch(USE_DELAY_SLOT, &done);  // Expose delay slot.
+      __ li(at, i);                      // In the delay slot.
+
+      DCHECK_EQ(table_entry_size_, masm()->SizeOfCodeGeneratedSince(&start));
     }
 
-    DCHECK_EQ(table_entry_size_, masm()->SizeOfCodeGeneratedSince(&start));
-  }
+    DCHECK_EQ(masm()->SizeOfCodeGeneratedSince(&table_start),
+              count() * table_entry_size_);
+    __ bind(&done);
+    __ Push(at);
+  } else {
+    // Uncommon case, the branch cannot reach.
+    // Create mini trampoline and adjust id constants to get proper value at
+    // the end of table.
+    for (int i = kMaxEntriesBranchReach; i > 1; i--) {
+      Label start;
+      __ bind(&start);
+      DCHECK(is_int16(i));
+      __ Branch(USE_DELAY_SLOT, &trampoline_jump);  // Expose delay slot.
+      __ li(at, -i);                                // In the delay slot.
+      DCHECK_EQ(table_entry_size_, masm()->SizeOfCodeGeneratedSince(&start));
+    }
+    // Entry with id == kMaxEntriesBranchReach - 1.
+    __ bind(&trampoline_jump);
+    __ Branch(USE_DELAY_SLOT, &done_special);
+    __ li(at, -1);
+
+    for (int i = kMaxEntriesBranchReach; i < count(); i++) {
+      Label start;
+      __ bind(&start);
+      DCHECK(is_int16(i));
+      __ Branch(USE_DELAY_SLOT, &done);  // Expose delay slot.
+      __ li(at, i);                      // In the delay slot.
+    }
 
-  DCHECK_EQ(masm()->SizeOfCodeGeneratedSince(&table_start),
-      count() * table_entry_size_);
+    DCHECK_EQ(masm()->SizeOfCodeGeneratedSince(&table_start),
+              count() * table_entry_size_);
+    __ bind(&done_special);
+    __ daddiu(at, at, kMaxEntriesBranchReach);
+    __ bind(&done);
+    __ Push(at);
+  }
 }
 
 
index eaf29c8..be732ef 100644 (file)
@@ -205,11 +205,6 @@ inline Object* JavaScriptFrame::function_slot_object() const {
 }
 
 
-inline void StackHandler::SetFp(Address slot, Address fp) {
-  Memory::Address_at(slot) = fp;
-}
-
-
 } }  // namespace v8::internal
 
 #endif
index 2d8fc15..91d374a 100644 (file)
@@ -115,7 +115,8 @@ class JumpPatchSite BASE_EMBEDDED {
 void FullCodeGenerator::Generate() {
   CompilationInfo* info = info_;
   handler_table_ =
-      isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
+      Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray(
+          HandlerTable::LengthForRange(function()->handler_count()), TENURED));
 
   profiling_counter_ = isolate()->factory()->NewCell(
       Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
@@ -201,7 +202,7 @@ void FullCodeGenerator::Generate() {
     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_script_scope()) {
+    if (info->scope()->is_script_scope()) {
       __ push(a1);
       __ Push(info->scope()->GetScopeInfo(info->isolate()));
       __ CallRuntime(Runtime::kNewScriptContext, 2);
@@ -246,6 +247,11 @@ void FullCodeGenerator::Generate() {
     }
   }
 
+  ArgumentsAccessStub::HasNewTarget has_new_target =
+      IsSubclassConstructor(info->function()->kind())
+          ? ArgumentsAccessStub::HAS_NEW_TARGET
+          : ArgumentsAccessStub::NO_NEW_TARGET;
+
   // Possibly allocate RestParameters
   int rest_index;
   Variable* rest_param = scope()->rest_parameter(&rest_index);
@@ -254,6 +260,11 @@ void FullCodeGenerator::Generate() {
 
     int num_parameters = info->scope()->num_parameters();
     int offset = num_parameters * kPointerSize;
+    if (has_new_target == ArgumentsAccessStub::HAS_NEW_TARGET) {
+      --num_parameters;
+      ++rest_index;
+    }
+
     __ Daddu(a3, fp,
            Operand(StandardFrameConstants::kCallerSPOffset + offset));
     __ li(a2, Operand(Smi::FromInt(num_parameters)));
@@ -288,10 +299,6 @@ void FullCodeGenerator::Generate() {
     //   function, receiver address, parameter count.
     // The stub will rewrite receiever and parameter count if the previous
     // stack frame was an arguments adapter frame.
-    ArgumentsAccessStub::HasNewTarget has_new_target =
-        IsSubclassConstructor(info->function()->kind())
-            ? ArgumentsAccessStub::HAS_NEW_TARGET
-            : ArgumentsAccessStub::NO_NEW_TARGET;
     ArgumentsAccessStub::Type type;
     if (is_strict(language_mode()) || !is_simple_parameter_list()) {
       type = ArgumentsAccessStub::NEW_STRICT;
@@ -1511,7 +1518,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
         __ li(VectorLoadICDescriptor::SlotRegister(),
               Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
       }
-      CallLoadIC(CONTEXTUAL);
+      CallGlobalLoadIC(var->name());
       context()->Plug(v0);
       break;
     }
@@ -2158,7 +2165,6 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
       __ bind(&l_catch);
       __ mov(a0, v0);
-      handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
       __ LoadRoot(a2, Heap::kthrow_stringRootIndex);  // "throw"
       __ ld(a3, MemOperand(sp, 1 * kPointerSize));    // iter
       __ Push(a2, a3, a0);                            // "throw", iter, except
@@ -2169,17 +2175,18 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       // re-boxing.
       __ bind(&l_try);
       __ pop(a0);                                        // result
-      __ PushTryHandler(StackHandler::CATCH, expr->index());
-      const int handler_size = StackHandlerConstants::kSize;
+      EnterTryBlock(expr->index(), &l_catch);
+      const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ push(a0);                                       // result
       __ jmp(&l_suspend);
       __ bind(&l_continuation);
       __ mov(a0, v0);
       __ jmp(&l_resume);
       __ bind(&l_suspend);
-      const int generator_object_depth = kPointerSize + handler_size;
+      const int generator_object_depth = kPointerSize + try_block_size;
       __ ld(a0, MemOperand(sp, generator_object_depth));
       __ push(a0);                                       // g
+      __ Push(Smi::FromInt(expr->index()));              // handler-index
       DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
       __ li(a1, Operand(Smi::FromInt(l_continuation.pos())));
       __ sd(a1, FieldMemOperand(a0, JSGeneratorObject::kContinuationOffset));
@@ -2187,13 +2194,13 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       __ mov(a1, cp);
       __ RecordWriteField(a0, JSGeneratorObject::kContextOffset, a1, a2,
                           kRAHasBeenSaved, kDontSaveFPRegs);
-      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 2);
       __ ld(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
       __ pop(v0);                                      // result
       EmitReturnSequence();
       __ mov(a0, v0);
       __ bind(&l_resume);                              // received in a0
-      __ PopTryHandler();
+      ExitTryBlock(expr->index());
 
       // receiver = iter; f = 'next'; arg = received;
       __ bind(&l_next);
@@ -2542,6 +2549,16 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
     }
     __ push(scratch);
     EmitPropertyKey(property, lit->GetIdForProperty(i));
+
+    // The static prototype property is read only. We handle the non computed
+    // property name case in the parser. Since this is the only case where we
+    // need to check for an own read only property we special case this so we do
+    // not need to do this for every property.
+    if (property->is_static() && property->is_computed_name()) {
+      __ CallRuntime(Runtime::kThrowIfStaticPrototype, 1);
+      __ push(v0);
+    }
+
     VisitForStackValue(value);
     EmitSetHomeObjectIfNeeded(value, 2);
 
@@ -2686,23 +2703,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
     __ li(StoreDescriptor::NameRegister(), Operand(var->name()));
     __ ld(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()) {
-      __ li(a0, Operand(var->name()));
-      __ Push(v0, cp, a0);  // Context and name.
-      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
-    } else {
-      DCHECK(var->IsStackAllocated() || var->IsContextSlot());
-      Label skip;
-      MemOperand location = VarOperand(var, a1);
-      __ ld(a2, location);
-      __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-      __ Branch(&skip, ne, a2, Operand(at));
-      EmitStoreToStackLocalOrContextSlot(var, location);
-      __ bind(&skip);
-    }
 
   } else if (var->mode() == LET && op != Token::INIT_LET) {
     // Non-initializing assignment to let variable needs a write barrier.
@@ -2719,6 +2719,22 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
     // Perform the assignment.
     __ bind(&assign);
     EmitStoreToStackLocalOrContextSlot(var, location);
+
+  } else if (var->mode() == CONST && op != Token::INIT_CONST) {
+    // Assignment to const variable needs a write barrier.
+    DCHECK(!var->IsLookupSlot());
+    DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+    Label const_error;
+    MemOperand location = VarOperand(var, a1);
+    __ ld(a3, location);
+    __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+    __ Branch(&const_error, ne, a3, Operand(at));
+    __ li(a3, Operand(var->name()));
+    __ push(a3);
+    __ CallRuntime(Runtime::kThrowReferenceError, 1);
+    __ bind(&const_error);
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
   } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
     if (var->IsLookupSlot()) {
       // Assignment to var.
@@ -2743,8 +2759,31 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
-  } else if (IsSignallingAssignmentToConst(var, op, language_mode())) {
-    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
+  } else if (op == Token::INIT_CONST_LEGACY) {
+    // Const initializers need a write barrier.
+    DCHECK(!var->IsParameter());  // No const parameters.
+    if (var->IsLookupSlot()) {
+      __ li(a0, Operand(var->name()));
+      __ Push(v0, cp, a0);  // Context and name.
+      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
+    } else {
+      DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+      Label skip;
+      MemOperand location = VarOperand(var, a1);
+      __ ld(a2, location);
+      __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+      __ Branch(&skip, ne, a2, Operand(at));
+      EmitStoreToStackLocalOrContextSlot(var, location);
+      __ bind(&skip);
+    }
+
+  } else {
+    DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT_CONST_LEGACY);
+    if (is_strict(language_mode())) {
+      __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+    }
+    // Silently ignore store in sloppy mode.
   }
 }
 
@@ -2878,7 +2917,8 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
     }
     // Push undefined as receiver. This is patched in the method prologue if it
     // is a sloppy mode method.
-    __ Push(isolate()->factory()->undefined_value());
+    __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
+    __ push(at);
   } else {
     // Load the function from the receiver.
     DCHECK(callee->IsProperty());
@@ -3229,7 +3269,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
 
 
 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
-  if (!ValidateSuperCall(expr)) return;
   Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
   GetVar(result_register(), new_target_var);
   __ Push(result_register());
@@ -3740,9 +3779,10 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 
   // Check if the constructor in the map is a JS function.
-  __ ld(v0, FieldMemOperand(v0, Map::kConstructorOffset));
-  __ GetObjectType(v0, a1, a1);
-  __ Branch(&non_function_constructor, ne, a1, Operand(JS_FUNCTION_TYPE));
+  Register instance_type = a2;
+  __ GetMapConstructor(v0, v0, a1, instance_type);
+  __ Branch(&non_function_constructor, ne, instance_type,
+            Operand(JS_FUNCTION_TYPE));
 
   // v0 now contains the constructor function. Grab the
   // instance class name from there.
@@ -4054,7 +4094,7 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
   __ jmp(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&done);
   context()->Plug(result);
@@ -4103,7 +4143,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
   __ jmp(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&done);
   context()->Plug(result);
@@ -4289,7 +4329,7 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
   __ bind(&not_found);
   // Call runtime to perform the lookup.
   __ Push(cache, key);
-  __ CallRuntime(Runtime::kGetFromCache, 2);
+  __ CallRuntime(Runtime::kGetFromCacheRT, 2);
 
   __ bind(&done);
   context()->Plug(v0);
@@ -4575,18 +4615,11 @@ void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
 
 
 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()) {
+    Comment cmnt(masm_, "[ CallRuntime");
     // Push the builtins object as the receiver.
     Register receiver = LoadDescriptor::ReceiverRegister();
     __ ld(receiver, GlobalObjectOperand());
@@ -4609,7 +4642,6 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     __ sd(v0, 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));
     }
@@ -4625,14 +4657,27 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
 
     context()->DropAndPlug(1, v0);
   } else {
-    // Push the arguments ("left-to-right").
-    for (int i = 0; i < arg_count; i++) {
-      VisitForStackValue(args->at(i));
-    }
+    const Runtime::Function* function = expr->function();
+    switch (function->function_id) {
+#define CALL_INTRINSIC_GENERATOR(Name)     \
+  case Runtime::kInline##Name: {           \
+    Comment cmnt(masm_, "[ Inline" #Name); \
+    return Emit##Name(expr);               \
+  }
+      FOR_EACH_FULL_CODE_INTRINSIC(CALL_INTRINSIC_GENERATOR)
+#undef CALL_INTRINSIC_GENERATOR
+      default: {
+        Comment cmnt(masm_, "[ CallRuntime for unhandled intrinsic");
+        // 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(v0);
+        // Call the C runtime function.
+        __ CallRuntime(expr->function(), arg_count);
+        context()->Plug(v0);
+      }
+    }
   }
 }
 
@@ -5275,19 +5320,6 @@ void FullCodeGenerator::EnterFinallyBlock() {
   __ li(at, Operand(pending_message_obj));
   __ ld(a1, MemOperand(at));
   __ push(a1);
-
-  ExternalReference has_pending_message =
-      ExternalReference::address_of_has_pending_message(isolate());
-  __ li(at, Operand(has_pending_message));
-  __ ld(a1, MemOperand(at));
-  __ SmiTag(a1);
-  __ push(a1);
-
-  ExternalReference pending_message_script =
-      ExternalReference::address_of_pending_message_script(isolate());
-  __ li(at, Operand(pending_message_script));
-  __ ld(a1, MemOperand(at));
-  __ push(a1);
 }
 
 
@@ -5295,19 +5327,6 @@ void FullCodeGenerator::ExitFinallyBlock() {
   DCHECK(!result_register().is(a1));
   // Restore pending message from stack.
   __ pop(a1);
-  ExternalReference pending_message_script =
-      ExternalReference::address_of_pending_message_script(isolate());
-  __ li(at, Operand(pending_message_script));
-  __ sd(a1, MemOperand(at));
-
-  __ pop(a1);
-  __ SmiUntag(a1);
-  ExternalReference has_pending_message =
-      ExternalReference::address_of_has_pending_message(isolate());
-  __ li(at, Operand(has_pending_message));
-  __ sd(a1, MemOperand(at));
-
-  __ pop(a1);
   ExternalReference pending_message_obj =
       ExternalReference::address_of_pending_message_obj(isolate());
   __ li(at, Operand(pending_message_obj));
@@ -5327,34 +5346,6 @@ void FullCodeGenerator::ExitFinallyBlock() {
 
 #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.
-    __ ld(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
-    __ sd(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-  }
-  __ PopTryHandler();
-  __ Call(finally_entry_);
-
-  *stack_depth = 0;
-  *context_length = 0;
-  return previous_;
-}
-
-
-#undef __
-
 
 void BackEdgeTable::PatchAt(Code* unoptimized_code,
                             Address pc,
index 8d1b9f2..b9003af 100644 (file)
@@ -227,6 +227,12 @@ void InternalArrayConstructorDescriptor::Initialize(
 }
 
 
+void CompareDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, a1, a0};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
 void CompareNilDescriptor::Initialize(CallInterfaceDescriptorData* data) {
   Register registers[] = {cp, a0};
   data->Initialize(arraysize(registers), registers, NULL);
index ae2e792..3b19379 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "src/code-factory.h"
 #include "src/code-stubs.h"
+#include "src/cpu-profiler.h"
 #include "src/hydrogen-osr.h"
 #include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
@@ -117,7 +118,7 @@ bool LCodeGen::GeneratePrologue() {
     // 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() && is_sloppy(info_->language_mode()) &&
+    if (graph()->this_has_uses() && is_sloppy(info_->language_mode()) &&
         !info_->is_native()) {
       Label ok;
       int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
@@ -302,7 +303,7 @@ bool LCodeGen::GenerateJumpTable() {
     Comment(";;; -------------------- Jump table --------------------");
   }
   Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
-  Label table_start;
+  Label table_start, call_deopt_entry;
   __ bind(&table_start);
   Label needs_frame;
   for (int i = 0; i < jump_table_.length(); i++) {
@@ -313,29 +314,35 @@ bool LCodeGen::GenerateJumpTable() {
     __ li(t9, Operand(ExternalReference::ForDeoptEntry(entry)));
     if (table_entry->needs_frame) {
       DCHECK(!info()->saves_caller_doubles());
-      if (needs_frame.is_bound()) {
-        __ Branch(&needs_frame);
-      } else {
-        __ bind(&needs_frame);
-        __ MultiPush(cp.bit() | fp.bit() | ra.bit());
-        // 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());
-        __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB)));
-        __ push(scratch0());
-        __ Daddu(fp, sp,
-            Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
-        __ Call(t9);
-      }
+      Comment(";;; call deopt with frame");
+      __ MultiPush(cp.bit() | fp.bit() | ra.bit());
+      __ Call(&needs_frame);
     } else {
-      if (info()->saves_caller_doubles()) {
-        DCHECK(info()->IsStub());
-        RestoreCallerDoubles();
-      }
-      __ Call(t9);
+      __ Call(&call_deopt_entry);
     }
+    info()->LogDeoptCallPosition(masm()->pc_offset(),
+                                 table_entry->deopt_info.inlining_id);
+  }
+  if (needs_frame.is_linked()) {
+    __ bind(&needs_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());
+    __ li(at, Operand(Smi::FromInt(StackFrame::STUB)));
+    __ push(at);
+    __ Daddu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
   }
+
+  Comment(";;; call deopt");
+  __ bind(&call_deopt_entry);
+
+  if (info()->saves_caller_doubles()) {
+    DCHECK(info()->IsStub());
+    RestoreCallerDoubles();
+  }
+  __ Jump(t9);
+
   __ RecordComment("]");
 
   // The deoptimization jump table is the last part of the instruction
@@ -806,8 +813,8 @@ void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
     __ bind(&skip);
   }
 
-  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
-                                    instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info = MakeDeoptInfo(instr, deopt_reason);
+
   DCHECK(info()->IsStub() || frame_is_built_);
   // Go through jump table if we need to handle condition, build frame, or
   // restore caller doubles.
@@ -815,6 +822,7 @@ void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
       !info()->saves_caller_doubles()) {
     DeoptComment(deopt_info);
     __ Call(entry, RelocInfo::RUNTIME_ENTRY, condition, src1, src2);
+    info()->LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
   } else {
     Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
                                             !frame_is_built_);
@@ -2362,9 +2370,8 @@ void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
 
   Register scratch = scratch0();
   __ FmoveHigh(scratch, input_reg);
-  __ dsll32(scratch, scratch, 0);  // FmoveHigh (mfhc1) sign-extends.
-  __ dsrl32(scratch, scratch, 0);  // Use only low 32-bits.
-  EmitBranch(instr, eq, scratch, Operand(kHoleNanUpper32));
+  EmitBranch(instr, eq, scratch,
+             Operand(static_cast<int32_t>(kHoleNanUpper32)));
 }
 
 
@@ -2617,14 +2624,15 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
 
   // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
   // Check if the constructor in the map is a function.
-  __ ld(temp, FieldMemOperand(temp, Map::kConstructorOffset));
+  Register instance_type = scratch1();
+  DCHECK(!instance_type.is(temp));
+  __ GetMapConstructor(temp, temp, temp2, instance_type);
 
   // Objects with a non-function constructor have class 'Object'.
-  __ GetObjectType(temp, temp2, temp2);
   if (String::Equals(class_name, isolate()->factory()->Object_string())) {
-    __ Branch(is_true, ne, temp2, Operand(JS_FUNCTION_TYPE));
+    __ Branch(is_true, ne, instance_type, Operand(JS_FUNCTION_TYPE));
   } else {
-    __ Branch(is_false, ne, temp2, Operand(JS_FUNCTION_TYPE));
+    __ Branch(is_false, ne, instance_type, Operand(JS_FUNCTION_TYPE));
   }
 
   // temp now contains the constructor function. Grab the
@@ -2730,8 +2738,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
   // root array to force relocation to be able to later patch with
   // the cached map.
   Handle<Cell> cell = factory()->NewCell(factory()->the_hole_value());
-  __ li(at, Operand(Handle<Object>(cell)));
-  __ ld(at, FieldMemOperand(at, PropertyCell::kValueOffset));
+  __ li(at, Operand(cell));
+  __ ld(at, FieldMemOperand(at, Cell::kValueOffset));
   __ BranchShort(&cache_miss, ne, map, Operand(at));
   // We use Factory::the_hole_value() on purpose instead of loading from the
   // root array to force relocation to be able to later patch
@@ -2871,17 +2879,6 @@ void LCodeGen::DoReturn(LReturn* instr) {
 }
 
 
-void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
-  Register result = ToRegister(instr->result());
-  __ li(at, Operand(Handle<Object>(instr->hydrogen()->cell().handle())));
-  __ ld(result, FieldMemOperand(at, Cell::kValueOffset));
-  if (instr->hydrogen()->RequiresHoleCheck()) {
-    __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(eq, instr, Deoptimizer::kHole, result, Operand(at));
-  }
-}
-
-
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
@@ -2911,36 +2908,12 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
   }
   ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
-  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode,
+                                                       PREMONOMORPHIC).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
 
-void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
-  Register value = ToRegister(instr->value());
-  Register cell = scratch0();
-
-  // Load the cell.
-  __ li(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.
-    Register payload = ToRegister(instr->temp());
-    __ ld(payload, FieldMemOperand(cell, Cell::kValueOffset));
-    __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(eq, instr, Deoptimizer::kHole, payload, Operand(at));
-  }
-
-  // Store the value.
-  __ sd(value, FieldMemOperand(cell, Cell::kValueOffset));
-  // Cells are always rescanned, so no write barrier here.
-}
-
-
 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
   Register context = ToRegister(instr->context());
   Register result = ToRegister(instr->result());
@@ -3052,8 +3025,9 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
   if (FLAG_vector_ics) {
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
-  Handle<Code> ic =
-      CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(
+                        isolate(), NOT_CONTEXTUAL,
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3275,9 +3249,9 @@ void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
   __ ldc1(result, MemOperand(scratch));
 
   if (instr->hydrogen()->RequiresHoleCheck()) {
-    __ lwu(scratch, MemOperand(scratch, sizeof(kHoleNanLower32)));
+    __ FmoveHigh(scratch, result);
     DeoptimizeIf(eq, instr, Deoptimizer::kHole, scratch,
-                 Operand(kHoleNanUpper32));
+                 Operand(static_cast<int32_t>(kHoleNanUpper32)));
   }
 }
 
@@ -3404,7 +3378,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code();
+  Handle<Code> ic =
+      CodeFactory::KeyedLoadICInOptimizedCode(
+          isolate(), instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -4312,7 +4288,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
   __ li(StoreDescriptor::NameRegister(), Operand(instr->name()));
-  Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->language_mode());
+  Handle<Code> ic =
+      StoreIC::initialize_stub(isolate(), instr->language_mode(),
+                               instr->hydrogen()->initialization_state());
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -4473,22 +4451,11 @@ void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
   }
 
   if (instr->NeedsCanonicalization()) {
-    Label is_nan;
-    // Check for NaN. All NaNs must be canonicalized.
-    __ BranchF(NULL, &is_nan, eq, value, value);
-    __ Branch(&not_nan);
-
-    // Only load canonical NaN if the comparison above set the overflow.
-    __ bind(&is_nan);
-    __ LoadRoot(at, Heap::kNanValueRootIndex);
-    __ ldc1(double_scratch, FieldMemOperand(at, HeapNumber::kValueOffset));
+    __ FPUCanonicalizeNaN(double_scratch, value);
     __ sdc1(double_scratch, MemOperand(scratch, 0));
-    __ Branch(&done);
+  } else {
+    __ sdc1(value, MemOperand(scratch, 0));
   }
-
-  __ bind(&not_nan);
-  __ sdc1(value, MemOperand(scratch, 0));
-  __ bind(&done);
 }
 
 
@@ -4576,8 +4543,9 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
   DCHECK(ToRegister(instr->key()).is(StoreDescriptor::NameRegister()));
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
-  Handle<Code> ic =
-      CodeFactory::KeyedStoreIC(isolate(), instr->language_mode()).code();
+  Handle<Code> ic = CodeFactory::KeyedStoreICInOptimizedCode(
+                        isolate(), instr->language_mode(),
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -5281,7 +5249,7 @@ void LCodeGen::DoCheckValue(LCheckValue* instr) {
   if (isolate()->heap()->InNewSpace(*object)) {
     Register reg = ToRegister(instr->value());
     Handle<Cell> cell = isolate()->factory()->NewCell(object);
-    __ li(at, Operand(Handle<Object>(cell)));
+    __ li(at, Operand(cell));
     __ ld(at, FieldMemOperand(at, Cell::kValueOffset));
     DeoptimizeIf(ne, instr, Deoptimizer::kValueMismatch, reg, Operand(at));
   } else {
index 1e48881..60a837e 100644 (file)
@@ -2085,14 +2085,6 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
 }
 
 
-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 =
@@ -2107,16 +2099,6 @@ LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* 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 =
index afc84ef..6eed2c2 100644 (file)
@@ -100,7 +100,6 @@ class LCodeGen;
   V(LoadRoot)                                \
   V(LoadFieldByIndex)                        \
   V(LoadFunctionPrototype)                   \
-  V(LoadGlobalCell)                          \
   V(LoadGlobalGeneric)                       \
   V(LoadKeyed)                               \
   V(LoadKeyedGeneric)                        \
@@ -140,7 +139,6 @@ class LCodeGen;
   V(StoreCodeEntry)                          \
   V(StoreContextSlot)                        \
   V(StoreFrameContext)                       \
-  V(StoreGlobalCell)                         \
   V(StoreKeyed)                              \
   V(StoreKeyedGeneric)                       \
   V(StoreNamedField)                         \
@@ -1665,13 +1663,6 @@ class LLoadKeyedGeneric FINAL : public LTemplateInstruction<1, 3, 1> {
 };
 
 
-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,
@@ -1693,21 +1684,6 @@ class LLoadGlobalGeneric FINAL : public LTemplateInstruction<1, 2, 1> {
 };
 
 
-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) {
index 4a2261b..1b8e4c0 100644 (file)
@@ -89,6 +89,7 @@ void MacroAssembler::LoadRoot(Register destination,
 
 void MacroAssembler::StoreRoot(Register source,
                                Heap::RootListIndex index) {
+  DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
   sd(source, MemOperand(s6, index << kPointerSizeLog2));
 }
 
@@ -97,6 +98,7 @@ void MacroAssembler::StoreRoot(Register source,
                                Heap::RootListIndex index,
                                Condition cond,
                                Register src1, const Operand& src2) {
+  DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
   Branch(2, NegateCondition(cond), src1, src2);
   sd(source, MemOperand(s6, index << kPointerSizeLog2));
 }
@@ -1717,6 +1719,14 @@ void MacroAssembler::BranchF(Label* target,
 }
 
 
+void MacroAssembler::FmoveLow(FPURegister dst, Register src_low) {
+  DCHECK(!src_low.is(at));
+  mfhc1(at, dst);
+  mtc1(src_low, dst);
+  mthc1(at, dst);
+}
+
+
 void MacroAssembler::Move(FPURegister dst, float imm) {
   li(at, Operand(bit_cast<int32_t>(imm)));
   mtc1(at, dst);
@@ -2112,7 +2122,7 @@ void MacroAssembler::BranchShort(int16_t offset, Condition cond, Register rs,
       // 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);
@@ -2120,7 +2130,7 @@ void MacroAssembler::BranchShort(int16_t offset, Condition cond, Register rs,
         break;
       case Ugreater_equal:
         if (r2.is(zero_reg)) {
-          bgez(rs, offset);
+          b(offset);
         } else {
           sltu(scratch, rs, r2);
           beq(scratch, zero_reg, offset);
@@ -2137,7 +2147,7 @@ void MacroAssembler::BranchShort(int16_t offset, Condition cond, Register rs,
         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);
@@ -2227,7 +2237,7 @@ void MacroAssembler::BranchShort(int16_t offset, Condition cond, Register rs,
       // Unsigned comparison.
       case Ugreater:
         if (rt.imm64_ == 0) {
-          bgtz(rs, offset);
+          bne(rs, zero_reg, offset);
         } else {
           r2 = scratch;
           li(r2, rt);
@@ -2237,7 +2247,7 @@ void MacroAssembler::BranchShort(int16_t offset, Condition cond, Register rs,
         break;
       case Ugreater_equal:
         if (rt.imm64_ == 0) {
-          bgez(rs, offset);
+          b(offset);
         } else if (is_int16(rt.imm64_)) {
           sltiu(scratch, rs, rt.imm64_);
           beq(scratch, zero_reg, offset);
@@ -2264,7 +2274,7 @@ void MacroAssembler::BranchShort(int16_t offset, Condition cond, Register rs,
         break;
       case Uless_equal:
         if (rt.imm64_ == 0) {
-          b(offset);
+          beq(rs, zero_reg, offset);
         } else {
           r2 = scratch;
           li(r2, rt);
@@ -2366,7 +2376,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
       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);
@@ -2376,7 +2386,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
       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);
@@ -2396,7 +2406,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
       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);
@@ -2518,7 +2528,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
       case Ugreater_equal:
         if (rt.imm64_ == 0) {
           offset = shifted_branch_offset(L, false);
-          bgez(rs, offset);
+          b(offset);
         } else if (is_int16(rt.imm64_)) {
           sltiu(scratch, rs, rt.imm64_);
           offset = shifted_branch_offset(L, false);
@@ -3212,150 +3222,31 @@ void MacroAssembler::DebugBreak() {
 // ---------------------------------------------------------------------------
 // Exception handling.
 
-void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
-                                    int handler_index) {
+void MacroAssembler::PushStackHandler() {
   // Adjust this code if not the case.
-  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kSize == 1 * 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 a0-a3 and s0.
-  // a5-a7 are available. We will build up the handler from the bottom by
-  // pushing on the stack.
-  // Set up the code object (a5) and the state (a6) for pushing.
-  unsigned state =
-      StackHandler::IndexField::encode(handler_index) |
-      StackHandler::KindField::encode(kind);
-  li(a5, Operand(CodeObject()), CONSTANT_SIZE);
-  li(a6, Operand(state));
-
-  // Push the frame pointer, context, state, and code object.
-  if (kind == StackHandler::JS_ENTRY) {
-    DCHECK_EQ(static_cast<Smi*>(0), Smi::FromInt(0));
-    // The second zero_reg indicates no context.
-    // The first zero_reg is the NULL frame pointer.
-    // The operands are reversed to match the order of MultiPush/Pop.
-    Push(zero_reg, zero_reg, a6, a5);
-  } else {
-    MultiPush(a5.bit() | a6.bit() | cp.bit() | fp.bit());
-  }
 
   // Link the current handler as the next handler.
   li(a6, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
   ld(a5, MemOperand(a6));
   push(a5);
+
   // Set this new handler as the current one.
   sd(sp, MemOperand(a6));
 }
 
 
-void MacroAssembler::PopTryHandler() {
+void MacroAssembler::PopStackHandler() {
   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
   pop(a1);
-  Daddu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+  Daddu(sp, sp, Operand(static_cast<int64_t>(StackHandlerConstants::kSize -
+                                             kPointerSize)));
   li(at, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
   sd(a1, MemOperand(at));
 }
 
 
-void MacroAssembler::JumpToHandlerEntry() {
-  // 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.
-  ld(a3, FieldMemOperand(a1, Code::kHandlerTableOffset));
-  Daddu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
-  dsrl(a2, a2, StackHandler::kKindWidth);  // Handler index.
-  dsll(a2, a2, kPointerSizeLog2);
-  Daddu(a2, a3, a2);
-  ld(a2, MemOperand(a2));  // Smi-tagged offset.
-  Daddu(a1, a1, Operand(Code::kHeaderSize - kHeapObjectTag));  // Code start.
-  dsra32(t9, a2, 0);
-  Daddu(t9, t9, a1);
-  Jump(t9);  // Jump.
-}
-
-
-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);
-
-  // The exception is expected in v0.
-  Move(v0, value);
-
-  // Drop the stack pointer to the top of the top handler.
-  li(a3, Operand(ExternalReference(Isolate::kHandlerAddress,
-                                   isolate())));
-  ld(sp, MemOperand(a3));
-
-  // Restore the next handler.
-  pop(a2);
-  sd(a2, MemOperand(a3));
-
-  // Get the code object (a1) and state (a2).  Restore the context and frame
-  // pointer.
-  MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit());
-
-  // 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.
-  Label done;
-  Branch(&done, eq, cp, Operand(zero_reg));
-  sd(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-  bind(&done);
-
-  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 v0.
-  if (!value.is(v0)) {
-    mov(v0, value);
-  }
-  // Drop the stack pointer to the top of the top stack handler.
-  li(a3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
-  ld(sp, MemOperand(a3));
-
-  // Unwind the handlers until the ENTRY handler is found.
-  Label fetch_next, check_kind;
-  jmp(&check_kind);
-  bind(&fetch_next);
-  ld(sp, MemOperand(sp, StackHandlerConstants::kNextOffset));
-
-  bind(&check_kind);
-  STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
-  ld(a2, MemOperand(sp, StackHandlerConstants::kStateOffset));
-  And(a2, a2, Operand(StackHandler::KindField::kMask));
-  Branch(&fetch_next, ne, a2, Operand(zero_reg));
-
-  // Set the top handler address to next handler past the top ENTRY handler.
-  pop(a2);
-  sd(a2, MemOperand(a3));
-
-  // Get the code object (a1) and state (a2).  Clear the context and frame
-  // pointer (0 was saved in the handler).
-  MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit());
-
-  JumpToHandlerEntry();
-}
-
-
 void MacroAssembler::Allocate(int object_size,
                               Register result,
                               Register scratch1,
@@ -3865,69 +3756,42 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg,
                                                  Register elements_reg,
                                                  Register scratch1,
                                                  Register scratch2,
-                                                 Register scratch3,
                                                  Label* fail,
                                                  int elements_offset) {
-  Label smi_value, maybe_nan, have_double_value, is_nan, done;
-  Register mantissa_reg = scratch2;
-  Register exponent_reg = scratch3;
+  Label smi_value, done;
 
   // Handle smi values specially.
   JumpIfSmi(value_reg, &smi_value);
 
-  // Ensure that the object is a heap number
+  // Ensure that the object is a heap number.
   CheckMap(value_reg,
            scratch1,
            Heap::kHeapNumberMapRootIndex,
            fail,
            DONT_DO_SMI_CHECK);
 
-  // Check for nan: all NaN values have a value greater (signed) than 0x7ff00000
-  // in the exponent.
-  li(scratch1, Operand(kHoleNanUpper32 & HeapNumber::kExponentMask));
-  lw(exponent_reg, FieldMemOperand(value_reg, HeapNumber::kExponentOffset));
-  Branch(&maybe_nan, ge, exponent_reg, Operand(scratch1));
-
-  lwu(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
-
-  bind(&have_double_value);
-  // dsll(scratch1, key_reg, kDoubleSizeLog2 - kSmiTagSize);
-  dsra(scratch1, key_reg, 32 - kDoubleSizeLog2);
-  Daddu(scratch1, scratch1, elements_reg);
-  sw(mantissa_reg, FieldMemOperand(
-     scratch1, FixedDoubleArray::kHeaderSize - elements_offset));
-  uint32_t offset = FixedDoubleArray::kHeaderSize - elements_offset +
-      sizeof(kHoleNanLower32);
-  sw(exponent_reg, FieldMemOperand(scratch1, offset));
-  jmp(&done);
-
-  bind(&maybe_nan);
-  // Could be NaN, Infinity or -Infinity. If fraction is not zero, it's NaN,
-  // otherwise it's Infinity or -Infinity, and the non-NaN code path applies.
-  lw(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
-  Branch(&have_double_value, eq, mantissa_reg, Operand(zero_reg));
-  bind(&is_nan);
-  // Load canonical NaN for storing into the double array.
-  LoadRoot(at, Heap::kNanValueRootIndex);
-  lw(mantissa_reg, FieldMemOperand(at, HeapNumber::kMantissaOffset));
-  lw(exponent_reg, FieldMemOperand(at, HeapNumber::kExponentOffset));
-  jmp(&have_double_value);
+  // Double value, turn potential sNaN into qNan.
+  DoubleRegister double_result = f0;
+  DoubleRegister double_scratch = f2;
+
+  ldc1(double_result, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
+  Branch(USE_DELAY_SLOT, &done);  // Canonicalization is one instruction.
+  FPUCanonicalizeNaN(double_result, double_result);
 
   bind(&smi_value);
+  // scratch1 is now effective address of the double element.
+  // Untag and transfer.
+  dsrl32(at, value_reg, 0);
+  mtc1(at, double_scratch);
+  cvt_d_w(double_result, double_scratch);
+
+  bind(&done);
   Daddu(scratch1, elements_reg,
       Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag -
               elements_offset));
-  // dsll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
   dsra(scratch2, key_reg, 32 - kDoubleSizeLog2);
   Daddu(scratch1, scratch1, scratch2);
-  // scratch1 is now effective address of the double element
-
-  Register untagged_value = elements_reg;
-  SmiUntag(untagged_value, value_reg);
-  mtc1(untagged_value, f2);
-  cvt_d_w(f0, f2);
-  sdc1(f0, MemOperand(scratch1, 0));
-  bind(&done);
+  sdc1(double_result, MemOperand(scratch1, 0));
 }
 
 
@@ -3999,6 +3863,10 @@ void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
   ld(value, FieldMemOperand(value, WeakCell::kValueOffset));
 }
 
+void MacroAssembler::FPUCanonicalizeNaN(const DoubleRegister dst,
+                                        const DoubleRegister src) {
+  sub_d(dst, src, kDoubleRegZero);
+}
 
 void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
                                    Label* miss) {
@@ -4267,6 +4135,20 @@ void MacroAssembler::IsObjectNameType(Register object,
 // Support functions.
 
 
+void MacroAssembler::GetMapConstructor(Register result, Register map,
+                                       Register temp, Register temp2) {
+  Label done, loop;
+  ld(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
+  bind(&loop);
+  JumpIfSmi(result, &done);
+  GetObjectType(result, temp, temp2);
+  Branch(&done, ne, temp2, Operand(MAP_TYPE));
+  ld(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset));
+  Branch(&loop);
+  bind(&done);
+}
+
+
 void MacroAssembler::TryGetFunctionPrototype(Register function,
                                              Register result,
                                              Register scratch,
@@ -4319,7 +4201,7 @@ void MacroAssembler::TryGetFunctionPrototype(Register function,
     // Non-instance prototype: Fetch prototype from constructor field
     // in initial map.
     bind(&non_instance);
-    ld(result, FieldMemOperand(result, Map::kConstructorOffset));
+    GetMapConstructor(result, result, scratch, scratch);
   }
 
   // All done.
index 1e25b33..6088b61 100644 (file)
@@ -262,10 +262,16 @@ class MacroAssembler: public Assembler {
     mfhc1(dst_high, src);
   }
 
+  inline void FmoveHigh(FPURegister dst, Register src_high) {
+    mthc1(src_high, dst);
+  }
+
   inline void FmoveLow(Register dst_low, FPURegister src) {
     mfc1(dst_low, src);
   }
 
+  void FmoveLow(FPURegister dst, Register src_low);
+
   inline void Move(FPURegister dst, Register src_low, Register src_high) {
     mtc1(src_low, dst);
     mthc1(src_high, dst);
@@ -993,19 +999,12 @@ class MacroAssembler: public Assembler {
   // -------------------------------------------------------------------------
   // Exception handling.
 
-  // Push a new try handler and link into try handler chain.
-  void PushTryHandler(StackHandler::Kind kind, int handler_index);
+  // Push a new stack handler and link into stack handler chain.
+  void PushStackHandler();
 
-  // Unlink the stack handler on top of the stack from the try handler chain.
+  // Unlink the stack handler on top of the stack from the stack 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);
+  void PopStackHandler();
 
   // Copies a fixed number of fields of heap objects from src to dst.
   void CopyFields(Register dst, Register src, RegList temps, int field_count);
@@ -1028,6 +1027,11 @@ class MacroAssembler: public Assembler {
   // -------------------------------------------------------------------------
   // Support functions.
 
+  // Machine code version of Map::GetConstructor().
+  // |temp| holds |result|'s map when done, and |temp2| its instance type.
+  void GetMapConstructor(Register result, Register map, Register temp,
+                         Register temp2);
+
   // 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
@@ -1069,7 +1073,6 @@ class MacroAssembler: public Assembler {
                                    Register elements_reg,
                                    Register scratch1,
                                    Register scratch2,
-                                   Register scratch3,
                                    Label* fail,
                                    int elements_offset = 0);
 
@@ -1116,6 +1119,10 @@ class MacroAssembler: public Assembler {
                        Handle<WeakCell> cell, Handle<Code> success,
                        SmiCheckType smi_check_type);
 
+  // If the value is a NaN, canonicalize the value else, do nothing.
+  void FPUCanonicalizeNaN(const DoubleRegister dst, const DoubleRegister src);
+
+
   // Get value of the weak cell.
   void GetWeakValue(Register value, Handle<WeakCell> cell);
 
@@ -1715,10 +1722,6 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
                           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);
index bb39b97..9ca57f6 100644 (file)
@@ -1995,7 +1995,7 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
           *return_addr_reg = instr->RdValue();
           break;
         case SLL:
-          *alu_out = (int32_t)rt << sa;
+          *alu_out = static_cast<int32_t>(rt) << sa;
           break;
         case DSLL:
           *alu_out = rt << sa;
@@ -2007,12 +2007,14 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
           if (rs_reg == 0) {
             // Regular logical right shift of a word by a fixed number of
             // bits instruction. RS field is always equal to 0.
-            *alu_out = (uint32_t)rt_u >> sa;
+            // Sign-extend the 32-bit result.
+            *alu_out = static_cast<int32_t>(static_cast<uint32_t>(rt_u) >> sa);
           } else {
             // Logical right-rotate of a word by a fixed number of bits. This
             // is special case of SRL instruction, added in MIPS32 Release 2.
             // RS field is equal to 00001.
-            *alu_out = ((uint32_t)rt_u >> sa) | ((uint32_t)rt_u << (32 - sa));
+            *alu_out = static_cast<int32_t>(
+                base::bits::RotateRight32((uint32_t)rt_u, sa));
           }
           break;
         case DSRL:
@@ -2040,13 +2042,13 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
           if (sa == 0) {
             // Regular logical right-shift of a word by a variable number of
             // bits instruction. SA field is always equal to 0.
-            *alu_out = (uint32_t)rt_u >> rs;
+            *alu_out = static_cast<int32_t>((uint32_t)rt_u >> rs);
           } else {
             // Logical right-rotate of a word by a variable number of bits.
             // This is special case od SRLV instruction, added in MIPS32
             // Release 2. SA field is equal to 00001.
-            *alu_out =
-                ((uint32_t)rt_u >> rs_u) | ((uint32_t)rt_u << (32 - rs_u));
+            *alu_out = static_cast<int32_t>(
+                base::bits::RotateRight32((uint32_t)rt_u, rs_u));
           }
           break;
         case DSRLV:
@@ -2058,7 +2060,7 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
             // Logical right-rotate of a word by a variable number of bits.
             // This is special case od SRLV instruction, added in MIPS32
             // Release 2. SA field is equal to 00001.
-            *alu_out = (rt_u >> rs_u) | (rt_u << (32 - rs_u));
+            *alu_out = base::bits::RotateRight32(rt_u, rs_u);
           }
           break;
         case SRAV:
@@ -2974,7 +2976,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
       alu_out = (rs < se_imm16) ? 1 : 0;
       break;
     case SLTIU:
-      alu_out = (rs_u < static_cast<uint32_t>(se_imm16)) ? 1 : 0;
+      alu_out = (rs_u < static_cast<uint64_t>(se_imm16)) ? 1 : 0;
       break;
     case ANDI:
         alu_out = rs & oe_imm16;
index 1848e4f..bfaac73 100644 (file)
@@ -657,7 +657,7 @@ SymbolMirror.prototype.description = function() {
 
 
 SymbolMirror.prototype.toText = function() {
-  return %_CallFunction(this.value_, builtins.SymbolToString);
+  return %_CallFunction(this.value_, builtins.$symbolToString);
 }
 
 
index eb01cf0..267c398 100644 (file)
 namespace v8 {
 namespace internal {
 
-// ---------------------------------------------------------------------------
-// Addition.
 
-void ModuleDescriptor::Add(const AstRawString* name, Zone* zone, bool* ok) {
-  void* key = const_cast<AstRawString*>(name);
+void ModuleDescriptor::AddLocalExport(const AstRawString* export_name,
+                                      const AstRawString* local_name,
+                                      Zone* zone, bool* ok) {
+  void* key = const_cast<AstRawString*>(export_name);
 
-  ZoneHashMap** map = &exports_;
   ZoneAllocationPolicy allocator(zone);
 
-  if (*map == nullptr) {
-    *map = new (zone->New(sizeof(ZoneHashMap)))
-        ZoneHashMap(ZoneHashMap::PointersMatch,
-                    ZoneHashMap::kDefaultHashMapCapacity, allocator);
+  if (exports_ == nullptr) {
+    exports_ = new (zone->New(sizeof(ZoneHashMap))) ZoneHashMap(
+        AstRawString::Compare, ZoneHashMap::kDefaultHashMapCapacity, allocator);
   }
 
   ZoneHashMap::Entry* p =
-      (*map)->Lookup(key, name->hash(), !IsFrozen(), allocator);
+      exports_->Lookup(key, export_name->hash(), !IsFrozen(), allocator);
   if (p == nullptr || p->value != nullptr) {
     *ok = false;
   }
 
-  p->value = key;
+  p->value = const_cast<AstRawString*>(local_name);
+}
+
+
+const AstRawString* ModuleDescriptor::LookupLocalExport(
+    const AstRawString* export_name, Zone* zone) {
+  if (exports_ == nullptr) return nullptr;
+  ZoneAllocationPolicy allocator(zone);
+  ZoneHashMap::Entry* entry =
+      exports_->Lookup(const_cast<AstRawString*>(export_name),
+                       export_name->hash(), false, allocator);
+  if (entry == nullptr) return nullptr;
+  DCHECK_NOT_NULL(entry->value);
+  return static_cast<const AstRawString*>(entry->value);
 }
 }
 }  // namespace v8::internal
index ac04e47..7dd7e26 100644 (file)
@@ -28,7 +28,8 @@ class ModuleDescriptor : public ZoneObject {
 
   // Add a name to the list of exports. If it already exists, or this descriptor
   // is frozen, that's an error.
-  void Add(const AstRawString* name, Zone* zone, bool* ok);
+  void AddLocalExport(const AstRawString* export_name,
+                      const AstRawString* local_name, Zone* zone, bool* ok);
 
   // Do not allow any further refinements, directly or through unification.
   void Freeze() { frozen_ = true; }
@@ -57,6 +58,9 @@ class ModuleDescriptor : public ZoneObject {
     return index_;
   }
 
+  const AstRawString* LookupLocalExport(const AstRawString* export_name,
+                                        Zone* zone);
+
   // ---------------------------------------------------------------------------
   // Iterators.
 
@@ -67,10 +71,14 @@ class ModuleDescriptor : public ZoneObject {
   class Iterator {
    public:
     bool done() const { return entry_ == NULL; }
-    const AstRawString* name() const {
+    const AstRawString* export_name() const {
       DCHECK(!done());
       return static_cast<const AstRawString*>(entry_->key);
     }
+    const AstRawString* local_name() const {
+      DCHECK(!done());
+      return static_cast<const AstRawString*>(entry_->value);
+    }
     void Advance() { entry_ = exports_->Next(entry_); }
 
    private:
index 01ce805..3ba917e 100644 (file)
@@ -271,7 +271,7 @@ function ConvertAcceptListToTypeMap(arg) {
     return arg;
 
   if (!IS_SPEC_OBJECT(arg))
-    throw MakeTypeError("observe_accept_invalid");
+    throw MakeTypeError("observe_invalid_accept");
 
   var len = ToInteger(arg.length);
   if (len < 0) len = 0;
index 78a07c7..f06e7b6 100644 (file)
@@ -289,9 +289,11 @@ void JSObject::JSObjectVerify() {
         if (r.IsSmi()) DCHECK(value->IsSmi());
         if (r.IsHeapObject()) DCHECK(value->IsHeapObject());
         HeapType* field_type = descriptors->GetFieldType(i);
+        bool type_is_none = field_type->Is(HeapType::None());
+        bool type_is_any = HeapType::Any()->Is(field_type);
         if (r.IsNone()) {
-          CHECK(field_type->Is(HeapType::None()));
-        } else if (!HeapType::Any()->Is(field_type)) {
+          CHECK(type_is_none);
+        } else if (!type_is_any && !(type_is_none && r.IsHeapObject())) {
           CHECK(!field_type->NowStable() || field_type->NowContains(value));
         }
       }
@@ -320,10 +322,8 @@ void Map::MapVerify() {
   VerifyHeapPointer(prototype());
   VerifyHeapPointer(instance_descriptors());
   SLOW_DCHECK(instance_descriptors()->IsSortedNoDuplicates());
-  if (HasTransitionArray()) {
-    SLOW_DCHECK(transitions()->IsSortedNoDuplicates());
-    SLOW_DCHECK(transitions()->IsConsistentWithBackPointers(this));
-  }
+  SLOW_DCHECK(TransitionArray::IsSortedNoDuplicates(this));
+  SLOW_DCHECK(TransitionArray::IsConsistentWithBackPointers(this));
   // TODO(ishell): turn it back to SLOW_DCHECK.
   CHECK(!FLAG_unbox_double_fields ||
         layout_descriptor()->IsConsistentWithMap(this));
@@ -344,7 +344,6 @@ void Map::VerifyOmittedMapChecks() {
   if (!FLAG_omit_map_checks_for_leaf_maps) return;
   if (!is_stable() ||
       is_deprecated() ||
-      HasTransitionArray() ||
       is_dictionary_map()) {
     CHECK_EQ(0, dependent_code()->number_of_entries(
         DependentCode::kPrototypeCheckGroup));
@@ -426,7 +425,6 @@ void JSGeneratorObject::JSGeneratorObjectVerify() {
   VerifyObjectField(kReceiverOffset);
   VerifyObjectField(kOperandStackOffset);
   VerifyObjectField(kContinuationOffset);
-  VerifyObjectField(kStackHandlerIndexOffset);
 }
 
 
@@ -646,7 +644,6 @@ void Cell::CellVerify() {
 void PropertyCell::PropertyCellVerify() {
   CHECK(IsPropertyCell());
   VerifyObjectField(kValueOffset);
-  VerifyObjectField(kTypeOffset);
 }
 
 
@@ -1208,14 +1205,28 @@ bool TransitionArray::IsSortedNoDuplicates(int valid_entries) {
 }
 
 
+// static
+bool TransitionArray::IsSortedNoDuplicates(Map* map) {
+  Object* raw_transitions = map->raw_transitions();
+  if (IsFullTransitionArray(raw_transitions)) {
+    return TransitionArray::cast(raw_transitions)->IsSortedNoDuplicates();
+  }
+  // Simple and non-existent transitions are always sorted.
+  return true;
+}
+
+
 static bool CheckOneBackPointer(Map* current_map, Object* target) {
   return !target->IsMap() || Map::cast(target)->GetBackPointer() == current_map;
 }
 
 
-bool TransitionArray::IsConsistentWithBackPointers(Map* current_map) {
-  for (int i = 0; i < number_of_transitions(); ++i) {
-    if (!CheckOneBackPointer(current_map, GetTarget(i))) return false;
+// static
+bool TransitionArray::IsConsistentWithBackPointers(Map* map) {
+  Object* transitions = map->raw_transitions();
+  for (int i = 0; i < TransitionArray::NumberOfTransitions(transitions); ++i) {
+    Map* target = TransitionArray::GetTarget(transitions, i);
+    if (!CheckOneBackPointer(map, target)) return false;
   }
   return true;
 }
index 926e1c7..67d64c4 100644 (file)
@@ -51,12 +51,6 @@ Smi* PropertyDetails::AsSmi() const {
 }
 
 
-PropertyDetails PropertyDetails::AsDeleted() const {
-  Smi* smi = Smi::FromInt(value_ | DeletedField::encode(1));
-  return PropertyDetails(smi);
-}
-
-
 int PropertyDetails::field_width_in_words() const {
   DCHECK(location() == kField);
   if (!FLAG_unbox_double_fields) return 1;
@@ -719,6 +713,9 @@ bool Object::IsDescriptorArray() const {
 }
 
 
+bool Object::IsArrayList() const { return IsFixedArray(); }
+
+
 bool Object::IsLayoutDescriptor() const {
   return IsSmi() || IsFixedTypedArrayBase();
 }
@@ -758,6 +755,14 @@ bool Object::IsDeoptimizationOutputData() const {
 }
 
 
+bool Object::IsHandlerTable() const {
+  if (!IsFixedArray()) return false;
+  // There's actually no way to see the difference between a fixed array and
+  // a handler table array.
+  return true;
+}
+
+
 bool Object::IsDependentCode() const {
   if (!IsFixedArray()) return false;
   // There's actually no way to see the difference between a fixed array and
@@ -1877,41 +1882,6 @@ void JSObject::initialize_elements() {
 }
 
 
-Handle<String> Map::ExpectedTransitionKey(Handle<Map> map) {
-  DisallowHeapAllocation no_gc;
-  if (!map->HasTransitionArray()) return Handle<String>::null();
-  TransitionArray* transitions = map->transitions();
-  if (!transitions->IsSimpleTransition()) return Handle<String>::null();
-  int transition = TransitionArray::kSimpleTransitionIndex;
-  PropertyDetails details = transitions->GetTargetDetails(transition);
-  Name* name = transitions->GetKey(transition);
-  if (details.type() != DATA) return Handle<String>::null();
-  if (details.attributes() != NONE) return Handle<String>::null();
-  if (!name->IsString()) return Handle<String>::null();
-  return Handle<String>(String::cast(name));
-}
-
-
-Handle<Map> Map::ExpectedTransitionTarget(Handle<Map> map) {
-  DCHECK(!ExpectedTransitionKey(map).is_null());
-  return Handle<Map>(map->transitions()->GetTarget(
-      TransitionArray::kSimpleTransitionIndex));
-}
-
-
-Handle<Map> Map::FindTransitionToField(Handle<Map> map, Handle<Name> key) {
-  DisallowHeapAllocation no_allocation;
-  if (!map->HasTransitionArray()) return Handle<Map>::null();
-  TransitionArray* transitions = map->transitions();
-  int transition = transitions->Search(kData, *key, NONE);
-  if (transition == TransitionArray::kNotFound) return Handle<Map>::null();
-  PropertyDetails details = transitions->GetTargetDetails(transition);
-  if (details.type() != DATA) return Handle<Map>::null();
-  DCHECK_EQ(NONE, details.attributes());
-  return Handle<Map>(transitions->GetTarget(transition));
-}
-
-
 ACCESSORS(Oddball, to_string, String, kToStringOffset)
 ACCESSORS(Oddball, to_number, Object, kToNumberOffset)
 
@@ -1938,16 +1908,7 @@ void Cell::set_value(Object* val, WriteBarrierMode ignored) {
 }
 
 ACCESSORS(PropertyCell, dependent_code, DependentCode, kDependentCodeOffset)
-
-Object* PropertyCell::type_raw() const {
-  return READ_FIELD(this, kTypeOffset);
-}
-
-
-void PropertyCell::set_type_raw(Object* val, WriteBarrierMode ignored) {
-  WRITE_FIELD(this, kTypeOffset, val);
-}
-
+ACCESSORS(PropertyCell, value, Object, kValueOffset)
 
 Object* WeakCell::value() const { return READ_FIELD(this, kValueOffset); }
 
@@ -2139,6 +2100,31 @@ void JSObject::FastPropertyAtPut(FieldIndex index, Object* value) {
 }
 
 
+void JSObject::WriteToField(int descriptor, Object* value) {
+  DisallowHeapAllocation no_gc;
+
+  DescriptorArray* desc = map()->instance_descriptors();
+  PropertyDetails details = desc->GetDetails(descriptor);
+
+  DCHECK(details.type() == DATA);
+
+  FieldIndex index = FieldIndex::ForDescriptor(map(), descriptor);
+  if (details.representation().IsDouble()) {
+    // Nothing more to be done.
+    if (value->IsUninitialized()) return;
+    if (IsUnboxedDoubleField(index)) {
+      RawFastDoublePropertyAtPut(index, value->Number());
+    } else {
+      HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index));
+      DCHECK(box->IsMutableHeapNumber());
+      box->set_value(value->Number());
+    }
+  } else {
+    RawFastPropertyAtPut(index, value);
+  }
+}
+
+
 int JSObject::GetInObjectPropertyOffset(int index) {
   return map()->GetInObjectPropertyOffset(index);
 }
@@ -2371,6 +2357,7 @@ void FixedDoubleArray::FillWithHoles(int from, int to) {
 Object* WeakFixedArray::Get(int index) const {
   Object* raw = FixedArray::cast(this)->get(index + kFirstIndex);
   if (raw->IsSmi()) return raw;
+  DCHECK(raw->IsWeakCell());
   return WeakCell::cast(raw)->value();
 }
 
@@ -2401,6 +2388,39 @@ void WeakFixedArray::set_last_used_index(int index) {
 }
 
 
+int ArrayList::Length() {
+  if (FixedArray::cast(this)->length() == 0) return 0;
+  return Smi::cast(FixedArray::cast(this)->get(kLengthIndex))->value();
+}
+
+
+void ArrayList::SetLength(int length) {
+  return FixedArray::cast(this)->set(kLengthIndex, Smi::FromInt(length));
+}
+
+
+Object* ArrayList::Get(int index) {
+  return FixedArray::cast(this)->get(kFirstIndex + index);
+}
+
+
+Object** ArrayList::Slot(int index) {
+  return data_start() + kFirstIndex + index;
+}
+
+
+void ArrayList::Set(int index, Object* obj) {
+  FixedArray::cast(this)->set(kFirstIndex + index, obj);
+}
+
+
+void ArrayList::Clear(int index, Object* undefined) {
+  DCHECK(undefined->IsUndefined());
+  FixedArray::cast(this)
+      ->set(kFirstIndex + index, undefined, SKIP_WRITE_BARRIER);
+}
+
+
 void ConstantPoolArray::NumberOfEntries::increment(Type type) {
   DCHECK(type < NUMBER_OF_TYPES);
   element_counts_[type]++;
@@ -3037,7 +3057,7 @@ FixedArrayBase* Map::GetInitialElements() {
     return empty_array;
   } else if (has_fixed_typed_array_elements()) {
     FixedTypedArrayBase* empty_array =
-      GetHeap()->EmptyFixedTypedArrayForMap(this);
+        GetHeap()->EmptyFixedTypedArrayForMap(this);
     DCHECK(!GetHeap()->InNewSpace(empty_array));
     return empty_array;
   } else {
@@ -3136,7 +3156,12 @@ int DescriptorArray::GetFieldIndex(int descriptor_number) {
 
 HeapType* DescriptorArray::GetFieldType(int descriptor_number) {
   DCHECK(GetDetails(descriptor_number).location() == kField);
-  return HeapType::cast(GetValue(descriptor_number));
+  Object* value = GetValue(descriptor_number);
+  if (value->IsWeakCell()) {
+    if (WeakCell::cast(value)->cleared()) return HeapType::None();
+    value = WeakCell::cast(value)->value();
+  }
+  return HeapType::cast(value);
 }
 
 
@@ -3294,6 +3319,7 @@ void SeededNumberDictionary::set_requires_slow_elements() {
 
 
 CAST_ACCESSOR(AccessorInfo)
+CAST_ACCESSOR(ArrayList)
 CAST_ACCESSOR(ByteArray)
 CAST_ACCESSOR(Cell)
 CAST_ACCESSOR(Code)
@@ -3324,6 +3350,7 @@ CAST_ACCESSOR(FixedDoubleArray)
 CAST_ACCESSOR(FixedTypedArrayBase)
 CAST_ACCESSOR(Foreign)
 CAST_ACCESSOR(GlobalObject)
+CAST_ACCESSOR(HandlerTable)
 CAST_ACCESSOR(HeapObject)
 CAST_ACCESSOR(JSArray)
 CAST_ACCESSOR(JSArrayBuffer)
@@ -4198,7 +4225,7 @@ void* FixedTypedArrayBase::DataPtr() {
 }
 
 
-int FixedTypedArrayBase::DataSize(InstanceType type) {
+int FixedTypedArrayBase::ElementSize(InstanceType type) {
   int element_size;
   switch (type) {
 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
@@ -4212,7 +4239,12 @@ int FixedTypedArrayBase::DataSize(InstanceType type) {
       UNREACHABLE();
       return 0;
   }
-  return length() * element_size;
+  return element_size;
+}
+
+
+int FixedTypedArrayBase::DataSize(InstanceType type) {
+  return length() * ElementSize(type);
 }
 
 
@@ -4231,6 +4263,11 @@ int FixedTypedArrayBase::TypedArraySize(InstanceType type) {
 }
 
 
+int FixedTypedArrayBase::TypedArraySize(InstanceType type, int length) {
+  return OBJECT_POINTER_ALIGN(kDataOffset + length * ElementSize(type));
+}
+
+
 uint8_t Uint8ArrayTraits::defaultValue() { return 0; }
 
 
@@ -5250,22 +5287,6 @@ void Map::set_prototype(Object* value, WriteBarrierMode mode) {
 }
 
 
-// If the descriptor is using the empty transition array, install a new empty
-// transition array that will have place for an element transition.
-static void EnsureHasTransitionArray(Handle<Map> map) {
-  Handle<TransitionArray> transitions;
-  if (!map->HasTransitionArray()) {
-    transitions = TransitionArray::Allocate(map->GetIsolate(), 0);
-    transitions->set_back_pointer_storage(map->GetBackPointer());
-  } else if (!map->transitions()->IsFullTransitionArray()) {
-    transitions = TransitionArray::ExtendToFullTransitionArray(map);
-  } else {
-    return;
-  }
-  map->set_transitions(*transitions);
-}
-
-
 LayoutDescriptor* Map::layout_descriptor_gc_safe() {
   Object* layout_desc = READ_FIELD(this, kLayoutDecriptorOffset);
   return LayoutDescriptor::cast_gc_safe(layout_desc);
@@ -5360,158 +5381,58 @@ void Map::AppendDescriptor(Descriptor* desc) {
 
 
 Object* Map::GetBackPointer() {
-  Object* object = READ_FIELD(this, kTransitionsOrBackPointerOffset);
-  if (object->IsTransitionArray()) {
-    return TransitionArray::cast(object)->back_pointer_storage();
-  } else {
-    DCHECK(object->IsMap() || object->IsUndefined());
+  Object* object = constructor_or_backpointer();
+  if (object->IsMap()) {
     return object;
   }
+  return GetIsolate()->heap()->undefined_value();
 }
 
 
-bool Map::HasElementsTransition() {
-  return HasTransitionArray() && transitions()->HasElementsTransition();
-}
-
-
-bool Map::HasTransitionArray() const {
-  Object* object = READ_FIELD(this, kTransitionsOrBackPointerOffset);
-  return object->IsTransitionArray();
-}
-
-
-Map* Map::elements_transition_map() {
-  int index =
-      transitions()->SearchSpecial(GetHeap()->elements_transition_symbol());
-  return transitions()->GetTarget(index);
+Map* Map::ElementsTransitionMap() {
+  return TransitionArray::SearchSpecial(
+      this, GetHeap()->elements_transition_symbol());
 }
 
 
-bool Map::CanHaveMoreTransitions() {
-  if (!HasTransitionArray()) return true;
-  return transitions()->number_of_transitions() <
-         TransitionArray::kMaxNumberOfTransitions;
-}
+ACCESSORS(Map, raw_transitions, Object, kTransitionsOffset)
 
 
-Map* Map::GetTransition(int transition_index) {
-  return transitions()->GetTarget(transition_index);
-}
-
-
-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;
-}
-
-
-FixedArray* Map::GetPrototypeTransitions() {
-  if (!HasTransitionArray()) return GetHeap()->empty_fixed_array();
-  if (!transitions()->HasPrototypeTransitions()) {
-    return GetHeap()->empty_fixed_array();
-  }
-  return transitions()->GetPrototypeTransitions();
-}
-
-
-void Map::SetPrototypeTransitions(
-    Handle<Map> map, Handle<FixedArray> proto_transitions) {
-  EnsureHasTransitionArray(map);
-  int old_number_of_transitions = map->NumberOfProtoTransitions();
-  if (Heap::ShouldZapGarbage() && map->HasPrototypeTransitions()) {
-    DCHECK(map->GetPrototypeTransitions() != *proto_transitions);
-    map->ZapPrototypeTransitions();
-  }
-  map->transitions()->SetPrototypeTransitions(*proto_transitions);
-  map->SetNumberOfProtoTransitions(old_number_of_transitions);
-}
-
-
-bool Map::HasPrototypeTransitions() {
-  return HasTransitionArray() && transitions()->HasPrototypeTransitions();
+void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
+  DCHECK(instance_type() >= FIRST_JS_RECEIVER_TYPE);
+  DCHECK((value->IsUndefined() && GetBackPointer()->IsMap()) ||
+         (value->IsMap() && GetBackPointer()->IsUndefined()));
+  DCHECK(!value->IsMap() ||
+         Map::cast(value)->GetConstructor() == constructor_or_backpointer());
+  set_constructor_or_backpointer(value, mode);
 }
 
 
-TransitionArray* Map::transitions() const {
-  DCHECK(HasTransitionArray());
-  Object* object = READ_FIELD(this, kTransitionsOrBackPointerOffset);
-  return TransitionArray::cast(object);
-}
+ACCESSORS(Map, code_cache, Object, kCodeCacheOffset)
+ACCESSORS(Map, dependent_code, DependentCode, kDependentCodeOffset)
+ACCESSORS(Map, weak_cell_cache, Object, kWeakCellCacheOffset)
+ACCESSORS(Map, constructor_or_backpointer, Object,
+          kConstructorOrBackPointerOffset)
 
 
-void Map::set_transitions(TransitionArray* transition_array,
-                          WriteBarrierMode mode) {
-  // Transition arrays are not shared. When one is replaced, it should not
-  // keep referenced objects alive, so we zap it.
-  // When there is another reference to the array somewhere (e.g. a handle),
-  // not zapping turns from a waste of memory into a source of crashes.
-  if (HasTransitionArray()) {
-#ifdef DEBUG
-    for (int i = 0; i < transitions()->number_of_transitions(); i++) {
-      Map* target = transitions()->GetTarget(i);
-      if (target->instance_descriptors() == instance_descriptors()) {
-        Name* key = transitions()->GetKey(i);
-        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
-    DCHECK(transitions() != transition_array);
-    ZapTransitions();
+Object* Map::GetConstructor() const {
+  Object* maybe_constructor = constructor_or_backpointer();
+  // Follow any back pointers.
+  while (maybe_constructor->IsMap()) {
+    maybe_constructor =
+        Map::cast(maybe_constructor)->constructor_or_backpointer();
   }
-
-  WRITE_FIELD(this, kTransitionsOrBackPointerOffset, transition_array);
-  CONDITIONAL_WRITE_BARRIER(
-      GetHeap(), this, kTransitionsOrBackPointerOffset, transition_array, mode);
-}
-
-
-void Map::init_back_pointer(Object* undefined) {
-  DCHECK(undefined->IsUndefined());
-  WRITE_FIELD(this, kTransitionsOrBackPointerOffset, undefined);
+  return maybe_constructor;
 }
 
 
-void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
-  DCHECK(instance_type() >= FIRST_JS_RECEIVER_TYPE);
-  DCHECK((value->IsUndefined() && GetBackPointer()->IsMap()) ||
-         (value->IsMap() && GetBackPointer()->IsUndefined()));
-  Object* object = READ_FIELD(this, kTransitionsOrBackPointerOffset);
-  if (object->IsTransitionArray()) {
-    TransitionArray::cast(object)->set_back_pointer_storage(value);
-  } else {
-    WRITE_FIELD(this, kTransitionsOrBackPointerOffset, value);
-    CONDITIONAL_WRITE_BARRIER(
-        GetHeap(), this, kTransitionsOrBackPointerOffset, value, mode);
-  }
+void Map::SetConstructor(Object* constructor, WriteBarrierMode mode) {
+  // Never overwrite a back pointer with a constructor.
+  DCHECK(!constructor_or_backpointer()->IsMap());
+  set_constructor_or_backpointer(constructor, mode);
 }
 
 
-ACCESSORS(Map, code_cache, Object, kCodeCacheOffset)
-ACCESSORS(Map, dependent_code, DependentCode, kDependentCodeOffset)
-ACCESSORS(Map, constructor, Object, kConstructorOffset)
-
 ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
 ACCESSORS(JSFunction, literals_or_bindings, FixedArray, kLiteralsOffset)
 ACCESSORS(JSFunction, next_function_link, Object, kNextFunctionLinkOffset)
@@ -5551,6 +5472,7 @@ SMI_ACCESSORS(InterceptorInfo, flags, kFlagsOffset)
 BOOL_ACCESSORS(InterceptorInfo, flags, can_intercept_symbols,
                kCanInterceptSymbolsBit)
 BOOL_ACCESSORS(InterceptorInfo, flags, all_can_read, kAllCanReadBit)
+BOOL_ACCESSORS(InterceptorInfo, flags, non_masking, kNonMasking)
 
 ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset)
 ACCESSORS(CallHandlerInfo, data, Object, kDataOffset)
@@ -5671,6 +5593,8 @@ BOOL_ACCESSORS(FunctionTemplateInfo, flag, remove_prototype,
 BOOL_ACCESSORS(FunctionTemplateInfo, flag, do_not_cache,
                kDoNotCacheBit)
 BOOL_ACCESSORS(FunctionTemplateInfo, flag, instantiated, kInstantiatedBit)
+BOOL_ACCESSORS(FunctionTemplateInfo, flag, accept_any_receiver,
+               kAcceptAnyReceiver)
 BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_expression,
                kIsExpressionBit)
 BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_toplevel,
@@ -5854,7 +5778,6 @@ BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_default_constructor,
 
 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)
 
@@ -5932,7 +5855,10 @@ void SharedFunctionInfo::set_scope_info(ScopeInfo* value,
 
 
 bool SharedFunctionInfo::is_compiled() {
-  return code() != GetIsolate()->builtins()->builtin(Builtins::kCompileLazy);
+  Builtins* builtins = GetIsolate()->builtins();
+  DCHECK(code() != builtins->builtin(Builtins::kCompileOptimizedConcurrent));
+  DCHECK(code() != builtins->builtin(Builtins::kCompileOptimized));
+  return code() != builtins->builtin(Builtins::kCompileLazy);
 }
 
 
@@ -6199,7 +6125,12 @@ Object* JSFunction::prototype() {
   DCHECK(has_prototype());
   // If the function's prototype property has been set to a non-JSObject
   // value, that value is stored in the constructor field of the map.
-  if (map()->has_non_instance_prototype()) return map()->constructor();
+  if (map()->has_non_instance_prototype()) {
+    Object* prototype = map()->GetConstructor();
+    // The map must have a prototype in that field, not a back pointer.
+    DCHECK(!prototype->IsMap());
+    return prototype;
+  }
   return instance_prototype();
 }
 
@@ -6210,7 +6141,10 @@ bool JSFunction::should_have_prototype() {
 
 
 bool JSFunction::is_compiled() {
-  return code() != GetIsolate()->builtins()->builtin(Builtins::kCompileLazy);
+  Builtins* builtins = GetIsolate()->builtins();
+  return code() != builtins->builtin(Builtins::kCompileLazy) &&
+         code() != builtins->builtin(Builtins::kCompileOptimized) &&
+         code() != builtins->builtin(Builtins::kCompileOptimizedConcurrent);
 }
 
 
@@ -6267,20 +6201,6 @@ void JSBuiltinsObject::set_javascript_builtin(Builtins::JavaScript id,
 }
 
 
-Code* JSBuiltinsObject::javascript_builtin_code(Builtins::JavaScript id) {
-  DCHECK(id < kJSBuiltinsCount);  // id is unsigned.
-  return Code::cast(READ_FIELD(this, OffsetOfCodeWithId(id)));
-}
-
-
-void JSBuiltinsObject::set_javascript_builtin_code(Builtins::JavaScript id,
-                                                   Code* value) {
-  DCHECK(id < kJSBuiltinsCount);  // id is unsigned.
-  WRITE_FIELD(this, OffsetOfCodeWithId(id), value);
-  DCHECK(!GetHeap()->InNewSpace(value));
-}
-
-
 ACCESSORS(JSProxy, handler, Object, kHandlerOffset)
 ACCESSORS(JSProxy, hash, Object, kHashOffset)
 ACCESSORS(JSFunctionProxy, call_trap, Object, kCallTrapOffset)
@@ -6336,7 +6256,6 @@ ACCESSORS(JSGeneratorObject, context, Context, kContextOffset)
 ACCESSORS(JSGeneratorObject, receiver, Object, kReceiverOffset)
 SMI_ACCESSORS(JSGeneratorObject, continuation, kContinuationOffset)
 ACCESSORS(JSGeneratorObject, operand_stack, FixedArray, kOperandStackOffset)
-SMI_ACCESSORS(JSGeneratorObject, stack_handler_index, kStackHandlerIndexOffset)
 
 bool JSGeneratorObject::is_suspended() {
   DCHECK_LT(kGeneratorExecuting, kGeneratorClosed);
@@ -6942,8 +6861,7 @@ Maybe<bool> JSReceiver::HasProperty(Handle<JSReceiver> object,
     return JSProxy::HasPropertyWithHandler(proxy, name);
   }
   Maybe<PropertyAttributes> result = GetPropertyAttributes(object, name);
-  if (!result.has_value) return Maybe<bool>();
-  return maybe(result.value != ABSENT);
+  return result.IsJust() ? Just(result.FromJust() != ABSENT) : Nothing<bool>();
 }
 
 
@@ -6954,8 +6872,7 @@ Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
     return JSProxy::HasPropertyWithHandler(proxy, name);
   }
   Maybe<PropertyAttributes> result = GetOwnPropertyAttributes(object, name);
-  if (!result.has_value) return Maybe<bool>();
-  return maybe(result.value != ABSENT);
+  return result.IsJust() ? Just(result.FromJust() != ABSENT) : Nothing<bool>();
 }
 
 
@@ -7014,8 +6931,7 @@ Maybe<bool> JSReceiver::HasElement(Handle<JSReceiver> object, uint32_t index) {
   }
   Maybe<PropertyAttributes> result = JSObject::GetElementAttributeWithReceiver(
       Handle<JSObject>::cast(object), object, index, true);
-  if (!result.has_value) return Maybe<bool>();
-  return maybe(result.value != ABSENT);
+  return result.IsJust() ? Just(result.FromJust() != ABSENT) : Nothing<bool>();
 }
 
 
@@ -7027,8 +6943,7 @@ Maybe<bool> JSReceiver::HasOwnElement(Handle<JSReceiver> object,
   }
   Maybe<PropertyAttributes> result = JSObject::GetElementAttributeWithReceiver(
       Handle<JSObject>::cast(object), object, index, false);
-  if (!result.has_value) return Maybe<bool>();
-  return maybe(result.value != ABSENT);
+  return result.IsJust() ? Just(result.FromJust() != ABSENT) : Nothing<bool>();
 }
 
 
@@ -7102,9 +7017,7 @@ void Dictionary<Derived, Shape, Key>::SetEntry(int entry,
                                                Handle<Object> key,
                                                Handle<Object> value,
                                                PropertyDetails details) {
-  DCHECK(!key->IsName() ||
-         details.IsDeleted() ||
-         details.dictionary_index() > 0);
+  DCHECK(!key->IsName() || details.dictionary_index() > 0);
   int index = DerivedHashTable::EntryToIndex(entry);
   DisallowHeapAllocation no_gc;
   WriteBarrierMode mode = FixedArray::GetWriteBarrierMode(no_gc);
index 87f0396..1b31c1b 100644 (file)
@@ -432,11 +432,12 @@ void Map::MapPrint(std::ostream& os) {  // NOLINT
   if (FLAG_unbox_double_fields) {
     os << "\n - layout descriptor: " << Brief(layout_descriptor());
   }
-  if (HasTransitionArray()) {
-    os << "\n - transitions: " << Brief(transitions());
+  if (TransitionArray::NumberOfTransitions(raw_transitions()) > 0) {
+    os << "\n - transitions: ";
+    TransitionArray::PrintTransitions(os, raw_transitions());
   }
   os << "\n - prototype: " << Brief(prototype());
-  os << "\n - constructor: " << Brief(constructor());
+  os << "\n - constructor: " << Brief(GetConstructor());
   os << "\n - code cache: " << Brief(code_cache());
   os << "\n - dependent code: " << Brief(dependent_code());
   os << "\n";
@@ -1138,19 +1139,20 @@ void DescriptorArray::PrintDescriptors(std::ostream& os) {  // NOLINT
 
 void TransitionArray::Print() {
   OFStream os(stdout);
-  this->PrintTransitions(os);
+  TransitionArray::PrintTransitions(os, this);
   os << std::flush;
 }
 
 
-void TransitionArray::PrintTransitions(std::ostream& os,
+void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions,
                                        bool print_header) {  // NOLINT
+  int num_transitions = NumberOfTransitions(transitions);
   if (print_header) {
-    os << "Transition array " << number_of_transitions() << "\n";
+    os << "Transition array " << num_transitions << "\n";
   }
-  for (int i = 0; i < number_of_transitions(); i++) {
-    Name* key = GetKey(i);
-    Map* target = GetTarget(i);
+  for (int i = 0; i < num_transitions; i++) {
+    Name* key = GetKey(transitions, i);
+    Map* target = GetTarget(transitions, i);
     os << "   ";
 #ifdef OBJECT_PRINT
     key->NamePrint(os);
@@ -1158,16 +1160,17 @@ void TransitionArray::PrintTransitions(std::ostream& os,
     key->ShortPrint(os);
 #endif
     os << ": ";
-    if (key == GetHeap()->nonextensible_symbol()) {
+    Heap* heap = key->GetHeap();
+    if (key == heap->nonextensible_symbol()) {
       os << " (transition to non-extensible)";
-    } else if (key == GetHeap()->sealed_symbol()) {
+    } else if (key == heap->sealed_symbol()) {
       os << " (transition to sealed)";
-    } else if (key == GetHeap()->frozen_symbol()) {
+    } else if (key == heap->frozen_symbol()) {
       os << " (transition to frozen)";
-    } else if (key == GetHeap()->elements_transition_symbol()) {
+    } else if (key == heap->elements_transition_symbol()) {
       os << " (transition to " << ElementsKindToString(target->elements_kind())
          << ")";
-    } else if (key == GetHeap()->observed_symbol()) {
+    } else if (key == heap->observed_symbol()) {
       os << " (transition to Object.observe)";
     } else {
       PropertyDetails details = GetTargetDetails(key, target);
@@ -1177,7 +1180,9 @@ void TransitionArray::PrintTransitions(std::ostream& os,
       }
       os << (details.kind() == kData ? "data" : "accessor");
       if (details.location() == kDescriptor) {
-        os << " " << Brief(GetTargetValue(i));
+        Object* value =
+            target->instance_descriptors()->GetValue(target->LastAdded());
+        os << " " << Brief(value);
       }
       os << "), attrs: " << details.attributes();
     }
@@ -1187,8 +1192,7 @@ void TransitionArray::PrintTransitions(std::ostream& os,
 
 
 void JSObject::PrintTransitions(std::ostream& os) {  // NOLINT
-  if (!map()->HasTransitionArray()) return;
-  map()->transitions()->PrintTransitions(os, false);
+  TransitionArray::PrintTransitions(os, map()->raw_transitions());
 }
 #endif  // defined(DEBUG) || defined(OBJECT_PRINT)
 } }  // namespace v8::internal
index 0eda491..77a82e6 100644 (file)
@@ -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 <iomanip>
 #include <sstream>
 
 #include "src/v8.h"
@@ -14,6 +15,7 @@
 #include "src/bootstrapper.h"
 #include "src/code-stubs.h"
 #include "src/codegen.h"
+#include "src/compiler.h"
 #include "src/cpu-profiler.h"
 #include "src/date.h"
 #include "src/debug.h"
@@ -125,12 +127,14 @@ MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
         break;
       }
       case LookupIterator::ACCESS_CHECK:
-        if (it->HasAccess(v8::ACCESS_GET)) break;
+        if (it->HasAccess()) break;
         return JSObject::GetPropertyWithFailedAccessCheck(it);
       case LookupIterator::ACCESSOR:
         return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
                                        it->GetHolder<JSObject>(),
                                        it->GetAccessors());
+      case LookupIterator::INTEGER_INDEXED_EXOTIC:
+        return it->factory()->undefined_value();
       case LookupIterator::DATA:
         return it->GetDataValue();
     }
@@ -155,7 +159,7 @@ Handle<Object> JSObject::GetDataProperty(LookupIterator* it) {
       case LookupIterator::TRANSITION:
         UNREACHABLE();
       case LookupIterator::ACCESS_CHECK:
-        if (it->HasAccess(v8::ACCESS_GET)) continue;
+        if (it->HasAccess()) continue;
       // Fall through.
       case LookupIterator::JSPROXY:
         it->NotFound();
@@ -166,6 +170,8 @@ Handle<Object> JSObject::GetDataProperty(LookupIterator* it) {
         // relevant.
         it->NotFound();
         return it->isolate()->factory()->undefined_value();
+      case LookupIterator::INTEGER_INDEXED_EXOTIC:
+        return it->isolate()->factory()->undefined_value();
       case LookupIterator::DATA:
         return it->GetDataValue();
     }
@@ -219,7 +225,7 @@ bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
   // There is a constraint on the object; check.
   if (!map->IsJSObjectMap()) return false;
   // Fetch the constructor function of the object.
-  Object* cons_obj = map->constructor();
+  Object* cons_obj = map->GetConstructor();
   if (!cons_obj->IsJSFunction()) return false;
   JSFunction* fun = JSFunction::cast(cons_obj);
   // Iterate through the chain of inheriting function templates to
@@ -468,7 +474,7 @@ MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
     if (it->isolate()->has_scheduled_exception()) break;
     if (!result.is_null()) return result;
   }
-  it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_GET);
+  it->isolate()->ReportFailedAccessCheck(checked);
   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
   return it->factory()->undefined_value();
 }
@@ -479,18 +485,18 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
   Handle<JSObject> checked = it->GetHolder<JSObject>();
   while (FindAllCanReadHolder(it)) {
     if (it->state() == LookupIterator::ACCESSOR) {
-      return maybe(it->property_details().attributes());
+      return Just(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;
+    if (result.IsJust() && result.FromJust() != ABSENT) return result;
   }
-  it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS);
+  it->isolate()->ReportFailedAccessCheck(checked);
   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(),
-                                      Maybe<PropertyAttributes>());
-  return maybe(ABSENT);
+                                      Nothing<PropertyAttributes>());
+  return Just(ABSENT);
 }
 
 
@@ -516,7 +522,7 @@ MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck(
                                    it->GetAccessors(), language_mode);
   }
 
-  it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_SET);
+  it->isolate()->ReportFailedAccessCheck(checked);
   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
   return value;
 }
@@ -536,40 +542,30 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object,
 
   int entry = property_dictionary->FindEntry(name);
   if (entry == NameDictionary::kNotFound) {
-    Handle<Object> store_value = value;
     if (object->IsGlobalObject()) {
-      store_value = object->GetIsolate()->factory()->NewPropertyCell(value);
-    }
-
-    property_dictionary = NameDictionary::Add(
-        property_dictionary, name, store_value, details);
+      auto cell = object->GetIsolate()->factory()->NewPropertyCell();
+      cell->set_value(*value);
+      auto cell_type = value->IsUndefined() ? PropertyCellType::kUndefined
+                                            : PropertyCellType::kConstant;
+      details = details.set_cell_type(cell_type);
+      value = cell;
+    }
+    property_dictionary =
+        NameDictionary::Add(property_dictionary, name, value, details);
     object->set_properties(*property_dictionary);
     return;
   }
 
-  PropertyDetails original_details = property_dictionary->DetailsAt(entry);
-  int enumeration_index;
-  // Preserve the enumeration index unless the property was deleted.
-  if (original_details.IsDeleted()) {
-    enumeration_index = property_dictionary->NextEnumerationIndex();
-    property_dictionary->SetNextEnumerationIndex(enumeration_index + 1);
-  } else {
-    enumeration_index = original_details.dictionary_index();
-    DCHECK(enumeration_index > 0);
-  }
-
-  details = PropertyDetails(
-      details.attributes(), details.type(), enumeration_index);
-
   if (object->IsGlobalObject()) {
-    Handle<PropertyCell> cell(
-        PropertyCell::cast(property_dictionary->ValueAt(entry)));
-    PropertyCell::SetValueInferType(cell, value);
-    // Please note we have to update the property details.
-    property_dictionary->DetailsAtPut(entry, details);
-  } else {
-    property_dictionary->SetEntry(entry, name, value, details);
+    PropertyCell::UpdateCell(property_dictionary, entry, value, details);
+    return;
   }
+
+  PropertyDetails original_details = property_dictionary->DetailsAt(entry);
+  int enumeration_index = original_details.dictionary_index();
+  DCHECK(enumeration_index > 0);
+  details = details.set_index(enumeration_index);
+  property_dictionary->SetEntry(entry, name, value, details);
 }
 
 
@@ -604,7 +600,7 @@ MaybeHandle<Object> JSObject::GetElementWithFailedAccessCheck(
     if (!result.is_null()) return result;
     where_to_start = PrototypeIterator::START_AT_PROTOTYPE;
   }
-  isolate->ReportFailedAccessCheck(object, v8::ACCESS_GET);
+  isolate->ReportFailedAccessCheck(object);
   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
   return isolate->factory()->undefined_value();
 }
@@ -621,14 +617,14 @@ Maybe<PropertyAttributes> JSObject::GetElementAttributesWithFailedAccessCheck(
         FindIndexedAllCanReadHolder(isolate, holder, where_to_start);
     if (!all_can_read_holder.ToHandle(&holder)) break;
     auto result =
-        JSObject::GetElementAttributeFromInterceptor(object, receiver, index);
+        JSObject::GetElementAttributeFromInterceptor(holder, receiver, index);
     if (isolate->has_scheduled_exception()) break;
-    if (result.has_value && result.value != ABSENT) return result;
+    if (result.IsJust() && result.FromJust() != 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);
+  isolate->ReportFailedAccessCheck(object);
+  RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
+  return Just(ABSENT);
 }
 
 
@@ -663,7 +659,7 @@ MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate,
 
     // Check access rights if needed.
     if (js_object->IsAccessCheckNeeded()) {
-      if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
+      if (!isolate->MayAccess(js_object)) {
         return JSObject::GetElementWithFailedAccessCheck(isolate, js_object,
                                                          receiver, index);
       }
@@ -710,8 +706,8 @@ MaybeHandle<Object> Object::SetElementWithReceiver(
 
     // 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);
+      if (!isolate->MayAccess(js_object)) {
+        isolate->ReportFailedAccessCheck(js_object);
         RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
         return isolate->factory()->undefined_value();
       }
@@ -721,12 +717,12 @@ MaybeHandle<Object> Object::SetElementWithReceiver(
       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) {
+      if (!from_interceptor.IsJust()) return MaybeHandle<Object>();
+      if ((from_interceptor.FromJust() & READ_ONLY) != 0) {
         return WriteToReadOnlyElement(isolate, receiver, index, value,
                                       language_mode);
       }
-      done = from_interceptor.value != ABSENT;
+      done = from_interceptor.FromJust() != ABSENT;
     }
 
     if (!done &&
@@ -798,10 +794,16 @@ Map* Object::GetRootMap(Isolate* isolate) {
 Object* Object::GetHash() {
   // The object is either a number, a name, an odd-ball,
   // a real JS object, or a Harmony proxy.
-  if (IsNumber()) {
-    uint32_t hash = std::isnan(Number())
-                        ? Smi::kMaxValue
-                        : ComputeLongHash(double_to_uint64(Number()));
+  if (IsSmi()) {
+    int num = Smi::cast(this)->value();
+    uint32_t hash = ComputeLongHash(double_to_uint64(static_cast<double>(num)));
+    return Smi::FromInt(hash & Smi::kMaxValue);
+  }
+  if (IsHeapNumber()) {
+    double num = HeapNumber::cast(this)->value();
+    if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
+    if (i::IsMinusZero(num)) num = 0;
+    uint32_t hash = ComputeLongHash(double_to_uint64(num));
     return Smi::FromInt(hash & Smi::kMaxValue);
   }
   if (IsName()) {
@@ -1202,7 +1204,7 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) {
     default: {
       Map* map_of_this = map();
       Heap* heap = GetHeap();
-      Object* constructor = map_of_this->constructor();
+      Object* constructor = map_of_this->GetConstructor();
       bool printed = false;
       if (constructor->IsHeapObject() &&
           !heap->Contains(HeapObject::cast(constructor))) {
@@ -1665,8 +1667,9 @@ String* JSReceiver::class_name() {
   if (IsJSFunction() || IsJSFunctionProxy()) {
     return GetHeap()->Function_string();
   }
-  if (map()->constructor()->IsJSFunction()) {
-    JSFunction* constructor = JSFunction::cast(map()->constructor());
+  Object* maybe_constructor = map()->GetConstructor();
+  if (maybe_constructor->IsJSFunction()) {
+    JSFunction* constructor = JSFunction::cast(maybe_constructor);
     return String::cast(constructor->shared()->instance_class_name());
   }
   // If the constructor is not present, return "Object".
@@ -1675,8 +1678,9 @@ String* JSReceiver::class_name() {
 
 
 String* Map::constructor_name() {
-  if (constructor()->IsJSFunction()) {
-    JSFunction* constructor = JSFunction::cast(this->constructor());
+  Object* maybe_constructor = GetConstructor();
+  if (maybe_constructor->IsJSFunction()) {
+    JSFunction* constructor = JSFunction::cast(maybe_constructor);
     String* name = String::cast(constructor->shared()->name());
     if (name->length() > 0) return name;
     String* inferred_name = constructor->shared()->inferred_name();
@@ -1695,6 +1699,12 @@ String* JSReceiver::constructor_name() {
 }
 
 
+static Handle<Object> WrapType(Handle<HeapType> type) {
+  if (type->IsClass()) return Map::WeakCellForMap(type->AsClass()->Map());
+  return type;
+}
+
+
 MaybeHandle<Map> Map::CopyWithField(Handle<Map> map,
                                     Handle<Name> name,
                                     Handle<HeapType> type,
@@ -1720,7 +1730,10 @@ MaybeHandle<Map> Map::CopyWithField(Handle<Map> map,
     type = HeapType::Any(isolate);
   }
 
-  DataDescriptor new_field_desc(name, index, type, attributes, representation);
+  Handle<Object> wrapped_type(WrapType(type));
+
+  DataDescriptor new_field_desc(name, index, wrapped_type, attributes,
+                                representation);
   Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
   int unused_property_fields = new_map->unused_property_fields() - 1;
   if (unused_property_fields < 0) {
@@ -1754,23 +1767,27 @@ void JSObject::AddSlowProperty(Handle<JSObject> object,
   DCHECK(!object->HasFastProperties());
   Isolate* isolate = object->GetIsolate();
   Handle<NameDictionary> dict(object->property_dictionary());
+  PropertyDetails details(attributes, DATA, 0, PropertyCellType::kInvalid);
   if (object->IsGlobalObject()) {
-    // In case name is an orphaned property reuse the cell.
     int entry = dict->FindEntry(name);
+    // If there's a cell there, just invalidate and set the property.
     if (entry != NameDictionary::kNotFound) {
-      Handle<PropertyCell> cell(PropertyCell::cast(dict->ValueAt(entry)));
-      PropertyCell::SetValueInferType(cell, value);
-      // Assign an enumeration index to the property and update
-      // SetNextEnumerationIndex.
+      PropertyCell::UpdateCell(dict, entry, value, details);
+      // TODO(dcarney): move this to UpdateCell.
+      // Need to adjust the details.
       int index = dict->NextEnumerationIndex();
-      PropertyDetails details(attributes, DATA, index);
       dict->SetNextEnumerationIndex(index + 1);
-      dict->SetEntry(entry, name, cell, details);
+      details = dict->DetailsAt(entry).set_index(index);
+      dict->DetailsAtPut(entry, details);
       return;
     }
-    value = isolate->factory()->NewPropertyCell(value);
+    auto cell = isolate->factory()->NewPropertyCell();
+    cell->set_value(*value);
+    auto cell_type = value->IsUndefined() ? PropertyCellType::kUndefined
+                                          : PropertyCellType::kConstant;
+    details = details.set_cell_type(cell_type);
+    value = cell;
   }
-  PropertyDetails details(attributes, DATA, 0);
   Handle<NameDictionary> result =
       NameDictionary::Add(dict, name, value, details);
   if (*dict != *result) object->set_properties(*result);
@@ -1778,7 +1795,7 @@ void JSObject::AddSlowProperty(Handle<JSObject> object,
 
 
 Context* JSObject::GetCreationContext() {
-  Object* constructor = this->map()->constructor();
+  Object* constructor = this->map()->GetConstructor();
   JSFunction* function;
   if (!constructor->IsJSFunction()) {
     // Functions have null as a constructor,
@@ -1881,7 +1898,8 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
             old_map->GetHeap()->empty_descriptor_array(),
             LayoutDescriptor::FastPointerLayout());
         // Ensure that no transition was inserted for prototype migrations.
-        DCHECK(!old_map->HasTransitionArray());
+        DCHECK_EQ(0, TransitionArray::NumberOfTransitions(
+                         old_map->raw_transitions()));
         DCHECK(new_map->GetBackPointer()->IsUndefined());
       }
     } else {
@@ -2167,11 +2185,10 @@ Handle<Map> Map::CopyGeneralizeAllRepresentations(
 
 void Map::DeprecateTransitionTree() {
   if (is_deprecated()) return;
-  if (HasTransitionArray()) {
-    TransitionArray* transitions = this->transitions();
-    for (int i = 0; i < transitions->number_of_transitions(); i++) {
-      transitions->GetTarget(i)->DeprecateTransitionTree();
-    }
+  Object* transitions = raw_transitions();
+  int num_transitions = TransitionArray::NumberOfTransitions(transitions);
+  for (int i = 0; i < num_transitions; ++i) {
+    TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree();
   }
   deprecate();
   dependent_code()->DeoptimizeDependentCodeGroup(
@@ -2196,13 +2213,11 @@ bool Map::DeprecateTarget(PropertyKind kind, Name* key,
                           DescriptorArray* new_descriptors,
                           LayoutDescriptor* new_layout_descriptor) {
   bool transition_target_deprecated = false;
-  if (HasTransitionArray()) {
-    TransitionArray* transitions = this->transitions();
-    int transition = transitions->Search(kind, key, attributes);
-    if (transition != TransitionArray::kNotFound) {
-      transitions->GetTarget(transition)->DeprecateTransitionTree();
-      transition_target_deprecated = true;
-    }
+  Map* maybe_transition =
+      TransitionArray::SearchTransition(this, kind, key, attributes);
+  if (maybe_transition != NULL) {
+    maybe_transition->DeprecateTransitionTree();
+    transition_target_deprecated = true;
   }
 
   // Don't overwrite the empty descriptor array.
@@ -2245,15 +2260,11 @@ Map* Map::FindLastMatchMap(int verbatim,
   Map* current = this;
 
   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(details.kind(), name, details.attributes());
-    if (transition == TransitionArray::kNotFound) break;
-
-    Map* next = transitions->GetTarget(transition);
+    Map* next = TransitionArray::SearchTransition(current, details.kind(), name,
+                                                  details.attributes());
+    if (next == NULL) break;
     DescriptorArray* next_descriptors = next->instance_descriptors();
 
     PropertyDetails next_details = next_descriptors->GetDetails(i);
@@ -2296,25 +2307,26 @@ Map* Map::FindFieldOwner(int descriptor) {
 
 void Map::UpdateFieldType(int descriptor, Handle<Name> name,
                           Representation new_representation,
-                          Handle<HeapType> new_type) {
+                          Handle<Object> new_wrapped_type) {
+  DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
   DisallowHeapAllocation no_allocation;
   PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
   if (details.type() != DATA) return;
-  if (HasTransitionArray()) {
-    TransitionArray* transitions = this->transitions();
-    for (int i = 0; i < transitions->number_of_transitions(); ++i) {
-      transitions->GetTarget(i)
-          ->UpdateFieldType(descriptor, name, new_representation, new_type);
-    }
+  Object* transitions = raw_transitions();
+  int num_transitions = TransitionArray::NumberOfTransitions(transitions);
+  for (int i = 0; i < num_transitions; ++i) {
+    Map* target = TransitionArray::GetTarget(transitions, i);
+    target->UpdateFieldType(descriptor, name, new_representation,
+                            new_wrapped_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;
+  if (instance_descriptors()->GetValue(descriptor) == *new_wrapped_type) return;
   DataDescriptor d(name, instance_descriptors()->GetFieldIndex(descriptor),
-                   new_type, details.attributes(), new_representation);
+                   new_wrapped_type, details.attributes(), new_representation);
   instance_descriptors()->Replace(descriptor, &d);
 }
 
@@ -2355,15 +2367,24 @@ void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
   Handle<DescriptorArray> descriptors(
       field_owner->instance_descriptors(), isolate);
   DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
-
-  // Determine the generalized new field type.
-  new_field_type = Map::GeneralizeFieldType(
-      old_field_type, new_field_type, isolate);
+  bool old_field_type_was_cleared =
+      old_field_type->Is(HeapType::None()) && old_representation.IsHeapObject();
+
+  // Determine the generalized new field type. Conservatively assume type Any
+  // for cleared field types because the cleared type could have been a
+  // deprecated map and there still could be live instances with a non-
+  // deprecated version of the map.
+  new_field_type =
+      old_field_type_was_cleared
+          ? HeapType::Any(isolate)
+          : Map::GeneralizeFieldType(old_field_type, new_field_type, isolate);
 
   PropertyDetails details = descriptors->GetDetails(modify_index);
   Handle<Name> name(descriptors->GetKey(modify_index));
+
+  Handle<Object> wrapped_type(WrapType(new_field_type));
   field_owner->UpdateFieldType(modify_index, name, new_representation,
-                               new_field_type);
+                               wrapped_type);
   field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
       isolate, DependentCode::kFieldTypeGroup);
 
@@ -2543,10 +2564,11 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
       next_attributes = old_details.attributes();
       next_representation = old_details.representation();
     }
-    int j = target_map->SearchTransition(next_kind, old_descriptors->GetKey(i),
-                                         next_attributes);
-    if (j == TransitionArray::kNotFound) break;
-    Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
+    Map* transition = TransitionArray::SearchTransition(
+        *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
+    if (transition == NULL) break;
+    Handle<Map> tmp_map(transition, isolate);
+
     Handle<DescriptorArray> tmp_descriptors = handle(
         tmp_map->instance_descriptors(), isolate);
 
@@ -2631,10 +2653,10 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
       next_kind = old_details.kind();
       next_attributes = old_details.attributes();
     }
-    int j = target_map->SearchTransition(next_kind, old_descriptors->GetKey(i),
-                                         next_attributes);
-    if (j == TransitionArray::kNotFound) break;
-    Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
+    Map* transition = TransitionArray::SearchTransition(
+        *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
+    if (transition == NULL) break;
+    Handle<Map> tmp_map(transition, isolate);
     Handle<DescriptorArray> tmp_descriptors(
         tmp_map->instance_descriptors(), isolate);
 
@@ -2755,7 +2777,8 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
           next_field_type =
               GeneralizeFieldType(target_field_type, old_field_type, isolate);
         }
-        DataDescriptor d(target_key, current_offset, next_field_type,
+        Handle<Object> wrapped_type(WrapType(next_field_type));
+        DataDescriptor d(target_key, current_offset, wrapped_type,
                          next_attributes, next_representation);
         current_offset += d.GetDetails().field_width_in_words();
         new_descriptors->Set(i, &d);
@@ -2823,8 +2846,10 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
           next_field_type = old_field_type;
         }
 
-        DataDescriptor d(old_key, current_offset, next_field_type,
-                         next_attributes, next_representation);
+        Handle<Object> wrapped_type(WrapType(next_field_type));
+
+        DataDescriptor d(old_key, current_offset, wrapped_type, next_attributes,
+                         next_representation);
         current_offset += d.GetDetails().field_width_in_words();
         new_descriptors->Set(i, &d);
       } else {
@@ -2869,7 +2894,8 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
   // 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()) {
+  if (!transition_target_deprecated &&
+      !TransitionArray::CanHaveMoreTransitions(split_map)) {
     return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
                                             new_kind, new_attributes,
                                             "GenAll_CantHaveMoreTransitions");
@@ -2925,30 +2951,7 @@ Handle<Map> Map::GeneralizeAllFieldRepresentations(
 
 
 // static
-MaybeHandle<Map> Map::TryUpdate(Handle<Map> map) {
-  Handle<Map> proto_map(map);
-  while (proto_map->prototype()->IsJSObject()) {
-    Handle<JSObject> holder(JSObject::cast(proto_map->prototype()));
-    proto_map = Handle<Map>(holder->map());
-    if (proto_map->is_deprecated() && JSObject::TryMigrateInstance(holder)) {
-      proto_map = Handle<Map>(holder->map());
-    }
-  }
-  return TryUpdateInternal(map);
-}
-
-
-// static
-Handle<Map> Map::Update(Handle<Map> map) {
-  if (!map->is_deprecated()) return map;
-  return ReconfigureProperty(map, -1, kData, NONE, Representation::None(),
-                             HeapType::None(map->GetIsolate()),
-                             ALLOW_IN_DESCRIPTOR);
-}
-
-
-// static
-MaybeHandle<Map> Map::TryUpdateInternal(Handle<Map> old_map) {
+MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
   DisallowHeapAllocation no_allocation;
   DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
 
@@ -2965,11 +2968,11 @@ MaybeHandle<Map> Map::TryUpdateInternal(Handle<Map> old_map) {
   Map* new_map = root_map;
   for (int i = root_nof; i < old_nof; ++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);
+    Map* transition = TransitionArray::SearchTransition(
+        new_map, old_details.kind(), old_descriptors->GetKey(i),
+        old_details.attributes());
+    if (transition == NULL) return MaybeHandle<Map>();
+    new_map = transition;
     DescriptorArray* new_descriptors = new_map->instance_descriptors();
 
     PropertyDetails new_details = new_descriptors->GetDetails(i);
@@ -2978,33 +2981,41 @@ MaybeHandle<Map> Map::TryUpdateInternal(Handle<Map> old_map) {
     if (!old_details.representation().fits_into(new_details.representation())) {
       return MaybeHandle<Map>();
     }
-    Object* new_value = new_descriptors->GetValue(i);
-    Object* old_value = old_descriptors->GetValue(i);
     switch (new_details.type()) {
       case DATA: {
-        PropertyType old_type = old_details.type();
-        if (old_type == DATA) {
-          if (!HeapType::cast(old_value)->NowIs(HeapType::cast(new_value))) {
+        HeapType* new_type = new_descriptors->GetFieldType(i);
+        PropertyType old_property_type = old_details.type();
+        if (old_property_type == DATA) {
+          HeapType* old_type = old_descriptors->GetFieldType(i);
+          if (!old_type->NowIs(new_type)) {
             return MaybeHandle<Map>();
           }
         } else {
-          DCHECK(old_type == DATA_CONSTANT);
-          if (!HeapType::cast(new_value)->NowContains(old_value)) {
+          DCHECK(old_property_type == DATA_CONSTANT);
+          Object* old_value = old_descriptors->GetValue(i);
+          if (!new_type->NowContains(old_value)) {
             return MaybeHandle<Map>();
           }
         }
         break;
       }
-      case ACCESSOR:
-        DCHECK(HeapType::Any()->Is(HeapType::cast(new_value)));
+      case ACCESSOR: {
+#ifdef DEBUG
+        HeapType* new_type = new_descriptors->GetFieldType(i);
+        DCHECK(HeapType::Any()->Is(new_type));
+#endif
         break;
+      }
 
       case DATA_CONSTANT:
-      case ACCESSOR_CONSTANT:
+      case ACCESSOR_CONSTANT: {
+        Object* old_value = old_descriptors->GetValue(i);
+        Object* new_value = new_descriptors->GetValue(i);
         if (old_details.location() == kField || old_value != new_value) {
           return MaybeHandle<Map>();
         }
         break;
+      }
     }
   }
   if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>();
@@ -3012,6 +3023,15 @@ MaybeHandle<Map> Map::TryUpdateInternal(Handle<Map> old_map) {
 }
 
 
+// static
+Handle<Map> Map::Update(Handle<Map> map) {
+  if (!map->is_deprecated()) return map;
+  return ReconfigureProperty(map, -1, kData, NONE, Representation::None(),
+                             HeapType::None(map->GetIsolate()),
+                             ALLOW_IN_DESCRIPTOR);
+}
+
+
 MaybeHandle<Object> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
                                                          Handle<Object> value) {
   Handle<Name> name = it->name();
@@ -3068,7 +3088,7 @@ MaybeHandle<Object> Object::SetPropertyInternal(LookupIterator* it,
         // TODO(verwaest): Remove the distinction. This is mostly bogus since we
         // don't know whether we'll want to fetch attributes or call a setter
         // until we find the property.
-        if (it->HasAccess(v8::ACCESS_SET)) break;
+        if (it->HasAccess()) break;
         return JSObject::SetPropertyWithFailedAccessCheck(it, value,
                                                           language_mode);
 
@@ -3099,9 +3119,9 @@ MaybeHandle<Object> Object::SetPropertyInternal(LookupIterator* it,
           Maybe<PropertyAttributes> maybe_attributes =
               JSObject::GetPropertyAttributesWithInterceptor(
                   it->GetHolder<JSObject>(), it->GetReceiver(), it->name());
-          if (!maybe_attributes.has_value) return MaybeHandle<Object>();
-          done = maybe_attributes.value != ABSENT;
-          if (done && (maybe_attributes.value & READ_ONLY) != 0) {
+          if (!maybe_attributes.IsJust()) return MaybeHandle<Object>();
+          done = maybe_attributes.FromJust() != ABSENT;
+          if (done && (maybe_attributes.FromJust() & READ_ONLY) != 0) {
             return WriteToReadOnlyProperty(it, value, language_mode);
           }
         }
@@ -3115,6 +3135,10 @@ MaybeHandle<Object> Object::SetPropertyInternal(LookupIterator* it,
                                        it->GetHolder<JSObject>(),
                                        it->GetAccessors(), language_mode);
 
+      case LookupIterator::INTEGER_INDEXED_EXOTIC:
+        done = true;
+        break;
+
       case LookupIterator::DATA:
         if (it->property_details().IsReadOnly()) {
           return WriteToReadOnlyProperty(it, value, language_mode);
@@ -3177,6 +3201,9 @@ MaybeHandle<Object> Object::SetSuperProperty(LookupIterator* it,
       return JSObject::AddDataProperty(&own_lookup, value, NONE, language_mode,
                                        store_mode);
 
+    case LookupIterator::INTEGER_INDEXED_EXOTIC:
+      return result;
+
     case LookupIterator::DATA: {
       PropertyDetails details = own_lookup.property_details();
       if (details.IsConfigurable() || !details.IsReadOnly()) {
@@ -3306,16 +3333,14 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
     return WriteToReadOnlyProperty(it, value, language_mode);
   }
 
+  if (it->state() == LookupIterator::INTEGER_INDEXED_EXOTIC) return value;
+
   Handle<JSObject> receiver = it->GetStoreTarget();
 
   // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
   // 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);
@@ -3370,9 +3395,9 @@ MaybeHandle<Object> JSObject::SetElementWithCallbackSetterInPrototypes(
         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
 
     if (js_proto->IsAccessCheckNeeded()) {
-      if (!isolate->MayIndexedAccess(js_proto, index, v8::ACCESS_SET)) {
+      if (!isolate->MayAccess(js_proto)) {
         *found = true;
-        isolate->ReportFailedAccessCheck(js_proto, v8::ACCESS_SET);
+        isolate->ReportFailedAccessCheck(js_proto);
         RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
         return MaybeHandle<Object>();
       }
@@ -3594,9 +3619,9 @@ static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
   // have the cached transition.
   if (IsExternalArrayElementsKind(to_kind) &&
       !IsFixedTypedArrayElementsKind(map->elements_kind())) {
-    if (map->HasElementsTransition()) {
-        Map* next_map = map->elements_transition_map();
-        if (next_map->elements_kind() == to_kind) return next_map;
+    Map* next_map = map->ElementsTransitionMap();
+    if (next_map != NULL && next_map->elements_kind() == to_kind) {
+      return next_map;
     }
     return map;
   }
@@ -3604,13 +3629,14 @@ static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
   ElementsKind kind = map->elements_kind();
   while (kind != target_kind) {
     kind = GetNextTransitionElementsKind(kind);
-    if (!current_map->HasElementsTransition()) return current_map;
-    current_map = current_map->elements_transition_map();
+    Map* next_map = current_map->ElementsTransitionMap();
+    if (next_map == NULL) return current_map;
+    current_map = next_map;
   }
 
-  if (to_kind != kind && current_map->HasElementsTransition()) {
+  Map* next_map = current_map->ElementsTransitionMap();
+  if (to_kind != kind && next_map != NULL) {
     DCHECK(to_kind == DICTIONARY_ELEMENTS);
-    Map* next_map = current_map->elements_transition_map();
     if (next_map->elements_kind() == to_kind) return next_map;
   }
 
@@ -3642,15 +3668,11 @@ bool Map::IsMapInArrayPrototypeChain() {
 
 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()));
+  if (map->weak_cell_cache()->IsWeakCell()) {
+    return Handle<WeakCell>(WeakCell::cast(map->weak_cell_cache()));
   }
   Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
-  code_cache->set_weak_cell_cache(*weak_cell);
+  map->set_weak_cell_cache(*weak_cell);
   return weak_cell;
 }
 
@@ -3760,16 +3782,16 @@ Maybe<bool> JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy,
   Isolate* isolate = proxy->GetIsolate();
 
   // TODO(rossberg): adjust once there is a story for symbols vs proxies.
-  if (name->IsSymbol()) return maybe(false);
+  if (name->IsSymbol()) return Just(false);
 
   Handle<Object> args[] = { name };
   Handle<Object> result;
   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
       isolate, result, CallTrap(proxy, "has", isolate->derived_has_trap(),
                                 arraysize(args), args),
-      Maybe<bool>());
+      Nothing<bool>());
 
-  return maybe(result->BooleanValue());
+  return Just(result->BooleanValue());
 }
 
 
@@ -3936,17 +3958,16 @@ Maybe<PropertyAttributes> JSProxy::GetPropertyAttributesWithHandler(
   HandleScope scope(isolate);
 
   // TODO(rossberg): adjust once there is a story for symbols vs proxies.
-  if (name->IsSymbol()) return maybe(ABSENT);
+  if (name->IsSymbol()) return Just(ABSENT);
 
   Handle<Object> args[] = { name };
   Handle<Object> result;
   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-      isolate, result,
-      proxy->CallTrap(proxy, "getPropertyDescriptor", Handle<Object>(),
-                      arraysize(args), args),
-      Maybe<PropertyAttributes>());
+      isolate, result, proxy->CallTrap(proxy, "getPropertyDescriptor",
+                                       Handle<Object>(), arraysize(args), args),
+      Nothing<PropertyAttributes>());
 
-  if (result->IsUndefined()) return maybe(ABSENT);
+  if (result->IsUndefined()) return Just(ABSENT);
 
   Handle<Object> argv[] = { result };
   Handle<Object> desc;
@@ -3954,7 +3975,7 @@ Maybe<PropertyAttributes> JSProxy::GetPropertyAttributesWithHandler(
       isolate, desc,
       Execution::Call(isolate, isolate->to_complete_property_descriptor(),
                       result, arraysize(argv), argv),
-      Maybe<PropertyAttributes>());
+      Nothing<PropertyAttributes>());
 
   // Convert result to PropertyAttributes.
   Handle<String> enum_n = isolate->factory()->InternalizeOneByteString(
@@ -3962,26 +3983,26 @@ Maybe<PropertyAttributes> JSProxy::GetPropertyAttributesWithHandler(
   Handle<Object> enumerable;
   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, enumerable,
                                    Object::GetProperty(desc, enum_n),
-                                   Maybe<PropertyAttributes>());
+                                   Nothing<PropertyAttributes>());
   Handle<String> conf_n = isolate->factory()->InternalizeOneByteString(
       STATIC_CHAR_VECTOR("configurable_"));
   Handle<Object> configurable;
   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, configurable,
                                    Object::GetProperty(desc, conf_n),
-                                   Maybe<PropertyAttributes>());
+                                   Nothing<PropertyAttributes>());
   Handle<String> writ_n = isolate->factory()->InternalizeOneByteString(
       STATIC_CHAR_VECTOR("writable_"));
   Handle<Object> writable;
   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, writable,
                                    Object::GetProperty(desc, writ_n),
-                                   Maybe<PropertyAttributes>());
+                                   Nothing<PropertyAttributes>());
   if (!writable->BooleanValue()) {
     Handle<String> set_n = isolate->factory()->InternalizeOneByteString(
         STATIC_CHAR_VECTOR("set_"));
     Handle<Object> setter;
     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, setter,
                                      Object::GetProperty(desc, set_n),
-                                     Maybe<PropertyAttributes>());
+                                     Nothing<PropertyAttributes>());
     writable = isolate->factory()->ToBoolean(!setter->IsUndefined());
   }
 
@@ -3990,18 +4011,17 @@ Maybe<PropertyAttributes> JSProxy::GetPropertyAttributesWithHandler(
     Handle<String> trap = isolate->factory()->InternalizeOneByteString(
         STATIC_CHAR_VECTOR("getPropertyDescriptor"));
     Handle<Object> args[] = { handler, trap, name };
-    Handle<Object> error;
-    MaybeHandle<Object> maybe_error = isolate->factory()->NewTypeError(
+    Handle<Object> error = isolate->factory()->NewTypeError(
         "proxy_prop_not_configurable", HandleVector(args, arraysize(args)));
-    if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
-    return maybe(NONE);
+    isolate->Throw(*error);
+    return Just(NONE);
   }
 
   int attributes = NONE;
   if (!enumerable->BooleanValue()) attributes |= DONT_ENUM;
   if (!configurable->BooleanValue()) attributes |= DONT_DELETE;
   if (!writable->BooleanValue()) attributes |= READ_ONLY;
-  return maybe(static_cast<PropertyAttributes>(attributes));
+  return Just(static_cast<PropertyAttributes>(attributes));
 }
 
 
@@ -4114,31 +4134,6 @@ bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
 }
 
 
-void JSObject::WriteToField(int descriptor, Object* value) {
-  DisallowHeapAllocation no_gc;
-
-  DescriptorArray* desc = map()->instance_descriptors();
-  PropertyDetails details = desc->GetDetails(descriptor);
-
-  DCHECK(details.type() == DATA);
-
-  FieldIndex index = FieldIndex::ForDescriptor(map(), descriptor);
-  if (details.representation().IsDouble()) {
-    // Nothing more to be done.
-    if (value->IsUninitialized()) return;
-    if (IsUnboxedDoubleField(index)) {
-      RawFastDoublePropertyAtPut(index, value->Number());
-    } else {
-      HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index));
-      DCHECK(box->IsMutableHeapNumber());
-      box->set_value(value->Number());
-    }
-  } else {
-    RawFastPropertyAtPut(index, value);
-  }
-}
-
-
 void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
                            Handle<Object> value,
                            PropertyAttributes attributes) {
@@ -4149,7 +4144,7 @@ void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
   DCHECK(!object->IsJSProxy());
   DCHECK(!name->AsArrayIndex(&index));
   Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
-  DCHECK(maybe.has_value);
+  DCHECK(maybe.IsJust());
   DCHECK(!it.IsFound());
   DCHECK(object->map()->is_extensible() ||
          it.isolate()->IsInternallyUsedPropertyName(name));
@@ -4173,6 +4168,9 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
                      !it.isolate()->IsInternallyUsedPropertyName(name);
   for (; it.IsFound(); it.Next()) {
     switch (it.state()) {
+      case LookupIterator::INTEGER_INDEXED_EXOTIC:
+        return value;
+
       case LookupIterator::INTERCEPTOR:
       case LookupIterator::JSPROXY:
       case LookupIterator::NOT_FOUND:
@@ -4180,7 +4178,7 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
         UNREACHABLE();
 
       case LookupIterator::ACCESS_CHECK:
-        if (!it.isolate()->MayNamedAccess(object, name, v8::ACCESS_SET)) {
+        if (!it.isolate()->MayAccess(object)) {
           return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY);
         }
         break;
@@ -4288,7 +4286,7 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
 
   Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
   if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
-    return maybe(ABSENT);
+    return Just(ABSENT);
   }
   PropertyCallbackArguments args(
       isolate, interceptor->data(), *receiver, *holder);
@@ -4301,7 +4299,7 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
     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()));
+      return Just(static_cast<PropertyAttributes>(result->Int32Value()));
     }
   } else if (!interceptor->getter()->IsUndefined()) {
     v8::GenericNamedPropertyGetterCallback getter =
@@ -4310,11 +4308,11 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
     LOG(isolate,
         ApiNamedPropertyAccess("interceptor-named-get-has", *holder, *name));
     v8::Handle<v8::Value> result = args.Call(getter, v8::Utils::ToLocal(name));
-    if (!result.IsEmpty()) return maybe(DONT_ENUM);
+    if (!result.IsEmpty()) return Just(DONT_ENUM);
   }
 
-  RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
-  return maybe(ABSENT);
+  RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
+  return Just(ABSENT);
 }
 
 
@@ -4344,19 +4342,21 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
         Maybe<PropertyAttributes> result =
             JSObject::GetPropertyAttributesWithInterceptor(
                 it->GetHolder<JSObject>(), it->GetReceiver(), it->name());
-        if (!result.has_value) return result;
-        if (result.value != ABSENT) return result;
+        if (!result.IsJust()) return result;
+        if (result.FromJust() != ABSENT) return result;
         break;
       }
       case LookupIterator::ACCESS_CHECK:
-        if (it->HasAccess(v8::ACCESS_HAS)) break;
+        if (it->HasAccess()) break;
         return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
+      case LookupIterator::INTEGER_INDEXED_EXOTIC:
+        return Just(ABSENT);
       case LookupIterator::ACCESSOR:
       case LookupIterator::DATA:
-        return maybe(it->property_details().attributes());
+        return Just(it->property_details().attributes());
     }
   }
-  return maybe(ABSENT);
+  return Just(ABSENT);
 }
 
 
@@ -4367,7 +4367,7 @@ Maybe<PropertyAttributes> JSObject::GetElementAttributeWithReceiver(
 
   // Check access rights if needed.
   if (object->IsAccessCheckNeeded()) {
-    if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_HAS)) {
+    if (!isolate->MayAccess(object)) {
       return GetElementAttributesWithFailedAccessCheck(isolate, object,
                                                        receiver, index);
     }
@@ -4375,7 +4375,7 @@ Maybe<PropertyAttributes> JSObject::GetElementAttributeWithReceiver(
 
   if (object->IsJSGlobalProxy()) {
     PrototypeIterator iter(isolate, object);
-    if (iter.IsAtEnd()) return maybe(ABSENT);
+    if (iter.IsAtEnd()) return Just(ABSENT);
     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
     return JSObject::GetElementAttributeWithReceiver(
         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
@@ -4405,8 +4405,9 @@ Maybe<PropertyAttributes> JSObject::GetElementAttributeWithInterceptor(
 
   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);
+  if (!from_interceptor.IsJust()) return Nothing<PropertyAttributes>();
+  if (from_interceptor.FromJust() != ABSENT)
+    return Just(from_interceptor.FromJust());
 
   return GetElementAttributeWithoutInterceptor(object, receiver, index,
                                                check_prototype);
@@ -4428,7 +4429,7 @@ Maybe<PropertyAttributes> JSObject::GetElementAttributeFromInterceptor(
         ApiIndexedPropertyAccess("interceptor-indexed-has", *object, index));
     v8::Handle<v8::Integer> result = args.Call(query, index);
     if (!result.IsEmpty())
-      return maybe(static_cast<PropertyAttributes>(result->Int32Value()));
+      return Just(static_cast<PropertyAttributes>(result->Int32Value()));
   } else if (!interceptor->getter()->IsUndefined()) {
     v8::IndexedPropertyGetterCallback getter =
         v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
@@ -4436,10 +4437,10 @@ Maybe<PropertyAttributes> JSObject::GetElementAttributeFromInterceptor(
         ApiIndexedPropertyAccess(
             "interceptor-indexed-get-has", *object, index));
     v8::Handle<v8::Value> result = args.Call(getter, index);
-    if (!result.IsEmpty()) return maybe(NONE);
+    if (!result.IsEmpty()) return Just(NONE);
   }
-  RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
-  return maybe(ABSENT);
+  RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
+  return Just(ABSENT);
 }
 
 
@@ -4448,14 +4449,14 @@ Maybe<PropertyAttributes> JSObject::GetElementAttributeWithoutInterceptor(
     bool check_prototype) {
   PropertyAttributes attr =
       object->GetElementsAccessor()->GetAttributes(object, index);
-  if (attr != ABSENT) return maybe(attr);
+  if (attr != ABSENT) return Just(attr);
 
   // Handle [] on String objects.
   if (object->IsStringObjectWithCharacterAt(index)) {
-    return maybe(static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE));
+    return Just(static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE));
   }
 
-  if (!check_prototype) return maybe(ABSENT);
+  if (!check_prototype) return Just(ABSENT);
 
   PrototypeIterator iter(object->GetIsolate(), object);
   if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
@@ -4464,7 +4465,7 @@ Maybe<PropertyAttributes> JSObject::GetElementAttributeWithoutInterceptor(
         Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
         index);
   }
-  if (iter.IsAtEnd()) return maybe(ABSENT);
+  if (iter.IsAtEnd()) return Just(ABSENT);
   return GetElementAttributeWithReceiver(
       Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
       index, true);
@@ -4557,7 +4558,8 @@ void JSObject::MigrateFastToSlow(Handle<JSObject> object,
     switch (details.type()) {
       case DATA_CONSTANT: {
         Handle<Object> value(descs->GetConstant(i), isolate);
-        PropertyDetails d(details.attributes(), DATA, i + 1);
+        PropertyDetails d(details.attributes(), DATA, i + 1,
+                          PropertyCellType::kInvalid);
         dictionary = NameDictionary::Add(dictionary, key, value, d);
         break;
       }
@@ -4575,20 +4577,23 @@ void JSObject::MigrateFastToSlow(Handle<JSObject> object,
             value = isolate->factory()->NewHeapNumber(old->value());
           }
         }
-        PropertyDetails d(details.attributes(), DATA, i + 1);
+        PropertyDetails d(details.attributes(), DATA, i + 1,
+                          PropertyCellType::kInvalid);
         dictionary = NameDictionary::Add(dictionary, key, value, d);
         break;
       }
       case ACCESSOR: {
         FieldIndex index = FieldIndex::ForDescriptor(*map, i);
         Handle<Object> value(object->RawFastPropertyAt(index), isolate);
-        PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1);
+        PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
+                          PropertyCellType::kInvalid);
         dictionary = NameDictionary::Add(dictionary, key, value, d);
         break;
       }
       case ACCESSOR_CONSTANT: {
         Handle<Object> value(descs->GetCallbacksObject(i), isolate);
-        PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1);
+        PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
+                          PropertyCellType::kInvalid);
         dictionary = NameDictionary::Add(dictionary, key, value, d);
         break;
       }
@@ -4821,7 +4826,7 @@ static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
       value = handle(Handle<FixedArray>::cast(array)->get(i), isolate);
     }
     if (!value->IsTheHole()) {
-      PropertyDetails details(NONE, DATA, 0);
+      PropertyDetails details = PropertyDetails::Empty();
       dictionary =
           SeededNumberDictionary::AddNumberEntry(dictionary, i, value, details);
     }
@@ -5073,8 +5078,8 @@ bool JSObject::HasHiddenProperties(Handle<JSObject> object) {
   LookupIterator it(object, hidden, LookupIterator::OWN_SKIP_INTERCEPTOR);
   Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
   // Cannot get an exception since the hidden_string isn't accessible to JS.
-  DCHECK(maybe.has_value);
-  return maybe.value != ABSENT;
+  DCHECK(maybe.IsJust());
+  return maybe.FromJust() != ABSENT;
 }
 
 
@@ -5217,9 +5222,8 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
   Factory* factory = isolate->factory();
 
   // Check access rights if needed.
-  if (object->IsAccessCheckNeeded() &&
-      !isolate->MayIndexedAccess(object, index, v8::ACCESS_DELETE)) {
-    isolate->ReportFailedAccessCheck(object, v8::ACCESS_DELETE);
+  if (object->IsAccessCheckNeeded() && !isolate->MayAccess(object)) {
+    isolate->ReportFailedAccessCheck(object);
     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
     return factory->false_value();
   }
@@ -5250,8 +5254,8 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
   bool should_enqueue_change_record = false;
   if (object->map()->is_observed()) {
     Maybe<bool> maybe = HasOwnElement(object, index);
-    if (!maybe.has_value) return MaybeHandle<Object>();
-    should_enqueue_change_record = maybe.value;
+    if (!maybe.IsJust()) return MaybeHandle<Object>();
+    should_enqueue_change_record = maybe.FromJust();
     if (should_enqueue_change_record) {
       if (!GetOwnElementAccessorPair(object, index).is_null()) {
         old_value = Handle<Object>::cast(factory->the_hole_value());
@@ -5275,8 +5279,8 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
 
   if (should_enqueue_change_record) {
     Maybe<bool> maybe = HasOwnElement(object, index);
-    if (!maybe.has_value) return MaybeHandle<Object>();
-    if (!maybe.value) {
+    if (!maybe.IsJust()) return MaybeHandle<Object>();
+    if (!maybe.FromJust()) {
       Handle<String> name = factory->Uint32ToString(index);
       RETURN_ON_EXCEPTION(
           isolate, EnqueueChangeRecord(object, "delete", name, old_value),
@@ -5296,14 +5300,13 @@ void JSObject::DeleteNormalizedProperty(Handle<JSObject> object,
   int entry = dictionary->FindEntry(name);
   DCHECK_NE(NameDictionary::kNotFound, entry);
 
-  // If we have a global object set the cell to the hole.
+  // If we have a global object, invalidate the cell and swap in a new one.
   if (object->IsGlobalObject()) {
-    PropertyDetails details = dictionary->DetailsAt(entry);
-    DCHECK(details.IsConfigurable());
-    Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
-    Handle<Object> value = isolate->factory()->the_hole_value();
-    PropertyCell::SetValueInferType(cell, value);
-    dictionary->DetailsAtPut(entry, details.AsDeleted());
+    auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
+    cell->set_value(isolate->heap()->the_hole_value());
+    // TODO(dcarney): InvalidateForDelete
+    dictionary->DetailsAtPut(entry, dictionary->DetailsAt(entry).set_cell_type(
+                                        PropertyCellType::kDeleted));
     return;
   }
 
@@ -5338,9 +5341,8 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
       case LookupIterator::TRANSITION:
         UNREACHABLE();
       case LookupIterator::ACCESS_CHECK:
-        if (it.HasAccess(v8::ACCESS_DELETE)) break;
-        it.isolate()->ReportFailedAccessCheck(it.GetHolder<JSObject>(),
-                                              v8::ACCESS_DELETE);
+        if (it.HasAccess()) break;
+        it.isolate()->ReportFailedAccessCheck(it.GetHolder<JSObject>());
         RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it.isolate(), Object);
         return it.isolate()->factory()->false_value();
       case LookupIterator::INTERCEPTOR: {
@@ -5353,6 +5355,8 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
         if (it.isolate()->has_pending_exception()) return maybe_result;
         break;
       }
+      case LookupIterator::INTEGER_INDEXED_EXOTIC:
+        return it.isolate()->factory()->true_value();
       case LookupIterator::DATA:
         if (is_observed) {
           old_value = it.GetDataValue();
@@ -5454,7 +5458,7 @@ bool JSObject::ReferencesObject(Object* obj) {
   DisallowHeapAllocation no_allocation;
 
   // Is the object the constructor for this object?
-  if (map_of_this->constructor() == obj) {
+  if (map_of_this->GetConstructor() == obj) {
     return true;
   }
 
@@ -5518,7 +5522,7 @@ bool JSObject::ReferencesObject(Object* obj) {
     Map* arguments_map =
         heap->isolate()->context()->native_context()->sloppy_arguments_map();
     JSFunction* arguments_function =
-        JSFunction::cast(arguments_map->constructor());
+        JSFunction::cast(arguments_map->GetConstructor());
 
     // Get the context and don't check if it is the native context.
     JSFunction* f = JSFunction::cast(this);
@@ -5533,7 +5537,7 @@ bool JSObject::ReferencesObject(Object* obj) {
       if (context->get(i)->IsJSObject()) {
         JSObject* ctxobj = JSObject::cast(context->get(i));
         // If it is an arguments array check the content.
-        if (ctxobj->map()->constructor() == arguments_function) {
+        if (ctxobj->map()->GetConstructor() == arguments_function) {
           if (ctxobj->ReferencesObject(obj)) {
             return true;
           }
@@ -5547,7 +5551,7 @@ bool JSObject::ReferencesObject(Object* obj) {
     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->IsScriptContext()) {
+      if (context->IsScriptContext()) {
         return false;
       }
 
@@ -5569,10 +5573,8 @@ MaybeHandle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
 
   Isolate* isolate = object->GetIsolate();
 
-  if (object->IsAccessCheckNeeded() &&
-      !isolate->MayNamedAccess(
-          object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
-    isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
+  if (object->IsAccessCheckNeeded() && !isolate->MayAccess(object)) {
+    isolate->ReportFailedAccessCheck(object);
     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
     return isolate->factory()->false_value();
   }
@@ -5680,10 +5682,8 @@ MaybeHandle<Object> JSObject::PreventExtensionsWithTransition(
   DCHECK(!object->map()->is_observed());
 
   Isolate* isolate = object->GetIsolate();
-  if (object->IsAccessCheckNeeded() &&
-      !isolate->MayNamedAccess(
-          object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
-    isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
+  if (object->IsAccessCheckNeeded() && !isolate->MayAccess(object)) {
+    isolate->ReportFailedAccessCheck(object);
     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
     return isolate->factory()->false_value();
   }
@@ -5721,13 +5721,15 @@ MaybeHandle<Object> JSObject::PreventExtensionsWithTransition(
   }
 
   Handle<Map> old_map(object->map(), isolate);
-  int transition_index = old_map->SearchSpecialTransition(*transition_marker);
-  if (transition_index != TransitionArray::kNotFound) {
-    Handle<Map> transition_map(old_map->GetTransition(transition_index));
+  Map* transition =
+      TransitionArray::SearchSpecial(*old_map, *transition_marker);
+  if (transition != NULL) {
+    Handle<Map> transition_map(transition, isolate);
     DCHECK(transition_map->has_dictionary_elements());
     DCHECK(!transition_map->is_extensible());
     JSObject::MigrateToMap(object, transition_map);
-  } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
+  } else if (object->HasFastProperties() &&
+             TransitionArray::CanHaveMoreTransitions(old_map)) {
     // Create a new descriptor array with the appropriate property attributes
     Handle<Map> new_map = Map::CopyForPreventExtensions(
         old_map, attrs, transition_marker, "CopyForPreventExtensions");
@@ -5786,12 +5788,13 @@ void JSObject::SetObserved(Handle<JSObject> object) {
   Handle<Map> new_map;
   Handle<Map> old_map(object->map(), isolate);
   DCHECK(!old_map->is_observed());
-  int transition_index =
-      old_map->SearchSpecialTransition(isolate->heap()->observed_symbol());
-  if (transition_index != TransitionArray::kNotFound) {
-    new_map = handle(old_map->GetTransition(transition_index), isolate);
+  Map* transition = TransitionArray::SearchSpecial(
+      *old_map, isolate->heap()->observed_symbol());
+  if (transition != NULL) {
+    new_map = handle(transition, isolate);
     DCHECK(new_map->is_observed());
-  } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
+  } else if (object->HasFastProperties() &&
+             TransitionArray::CanHaveMoreTransitions(old_map)) {
     new_map = Map::CopyForObserved(old_map);
   } else {
     new_map = Map::Copy(old_map, "SlowObserved");
@@ -5932,8 +5935,8 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
         Handle<String> key_string(String::cast(names->get(i)));
         Maybe<PropertyAttributes> maybe =
             JSReceiver::GetOwnPropertyAttributes(copy, key_string);
-        DCHECK(maybe.has_value);
-        PropertyAttributes attributes = maybe.value;
+        DCHECK(maybe.IsJust());
+        PropertyAttributes attributes = maybe.FromJust();
         // Only deep copy fields from the object literal expression.
         // In particular, don't try to copy the length attribute of
         // an array.
@@ -6240,12 +6243,12 @@ static Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
     return storage;
   } else {
     Handle<NameDictionary> dictionary(object->property_dictionary());
-    int length = dictionary->NumberOfEnumElements();
+    int length = dictionary->NumberOfEnumElements(*object);
     if (length == 0) {
       return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
     }
     Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
-    dictionary->CopyEnumKeysTo(*storage);
+    dictionary->CopyEnumKeysTo(*object, *storage);
     return storage;
   }
 }
@@ -6257,7 +6260,7 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
   Isolate* isolate = object->GetIsolate();
   Handle<FixedArray> content = isolate->factory()->empty_fixed_array();
   Handle<JSFunction> arguments_function(
-      JSFunction::cast(isolate->sloppy_arguments_map()->constructor()));
+      JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor()));
 
   // Only collect keys if access is permitted.
   for (PrototypeIterator iter(isolate, object,
@@ -6288,10 +6291,8 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
 
     // Check access rights if required.
-    if (current->IsAccessCheckNeeded() &&
-        !isolate->MayNamedAccess(
-            current, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
-      isolate->ReportFailedAccessCheck(current, v8::ACCESS_KEYS);
+    if (current->IsAccessCheckNeeded() && !isolate->MayAccess(current)) {
+      isolate->ReportFailedAccessCheck(current);
       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray);
       break;
     }
@@ -6330,11 +6331,9 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
     // array or dictionary.  So the fast inline test for whether to
     // use the cache says yes, so we should not create a cache.
     bool cache_enum_keys =
-        ((current->map()->constructor() != *arguments_function) &&
-         !current->IsJSValue() &&
-         !current->IsAccessCheckNeeded() &&
-         !current->HasNamedInterceptor() &&
-         !current->HasIndexedInterceptor());
+        ((current->map()->GetConstructor() != *arguments_function) &&
+         !current->IsJSValue() && !current->IsAccessCheckNeeded() &&
+         !current->HasNamedInterceptor() && !current->HasIndexedInterceptor());
     // Compute the property keys and cache them if possible.
     ASSIGN_RETURN_ON_EXCEPTION(
         isolate, content,
@@ -6380,7 +6379,8 @@ static bool UpdateGetterSetterInDictionary(
       DCHECK(details.IsConfigurable());
       if (details.attributes() != attributes) {
         dictionary->DetailsAtPut(
-            entry, PropertyDetails(attributes, ACCESSOR_CONSTANT, index));
+            entry, PropertyDetails(attributes, ACCESSOR_CONSTANT, index,
+                                   PropertyCellType::kInvalid));
       }
       AccessorPair::cast(result)->SetComponents(getter, setter);
       return true;
@@ -6482,7 +6482,8 @@ void JSObject::SetElementCallback(Handle<JSObject> object,
                                   Handle<Object> structure,
                                   PropertyAttributes attributes) {
   Heap* heap = object->GetHeap();
-  PropertyDetails details = PropertyDetails(attributes, ACCESSOR_CONSTANT, 0);
+  PropertyDetails details = PropertyDetails(attributes, ACCESSOR_CONSTANT, 0,
+                                            PropertyCellType::kInvalid);
 
   // Normalize elements to make this operation simple.
   bool had_dictionary_elements = object->HasDictionaryElements();
@@ -6527,28 +6528,10 @@ void JSObject::SetPropertyCallback(Handle<JSObject> object,
   // Normalize object to make this operation simple.
   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
-    // need to deoptimize all functions that rely on this global
-    // object.
-    Deoptimizer::DeoptimizeGlobalObject(*object);
-  }
 
   // Update the dictionary with the new ACCESSOR_CONSTANT property.
-  PropertyDetails details = PropertyDetails(attributes, ACCESSOR_CONSTANT, 0);
+  PropertyDetails details = PropertyDetails(attributes, ACCESSOR_CONSTANT, 0,
+                                            PropertyCellType::kMutable);
   SetNormalizedProperty(object, name, structure, details);
 
   ReoptimizeIfPrototype(object);
@@ -6562,9 +6545,8 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
                                              PropertyAttributes attributes) {
   Isolate* isolate = object->GetIsolate();
   // Check access rights if needed.
-  if (object->IsAccessCheckNeeded() &&
-      !isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
-    isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
+  if (object->IsAccessCheckNeeded() && !isolate->MayAccess(object)) {
+    isolate->ReportFailedAccessCheck(object);
     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
     return isolate->factory()->undefined_value();
   }
@@ -6597,18 +6579,18 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
       Maybe<bool> maybe = HasOwnElement(object, index);
       // Workaround for a GCC 4.4.3 bug which leads to "‘preexists’ may be used
       // uninitialized in this function".
-      if (!maybe.has_value) {
+      if (!maybe.IsJust()) {
         DCHECK(false);
         return isolate->factory()->undefined_value();
       }
-      preexists = maybe.value;
+      preexists = maybe.FromJust();
       if (preexists && GetOwnElementAccessorPair(object, index).is_null()) {
         old_value =
             Object::GetElement(isolate, object, index).ToHandleChecked();
       }
     } else {
       LookupIterator it(object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
-      CHECK(GetPropertyAttributes(&it).has_value);
+      CHECK(GetPropertyAttributes(&it).IsJust());
       preexists = it.IsFound();
       if (preexists && (it.state() == LookupIterator::DATA ||
                         it.GetAccessors()->IsAccessorInfo())) {
@@ -6656,9 +6638,8 @@ MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
   Handle<Name> name(Name::cast(info->name()));
 
   // Check access rights if needed.
-  if (object->IsAccessCheckNeeded() &&
-      !isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
-    isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
+  if (object->IsAccessCheckNeeded() && !isolate->MayAccess(object)) {
+    isolate->ReportFailedAccessCheck(object);
     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
     return factory->undefined_value();
   }
@@ -6715,7 +6696,7 @@ MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
   } else {
     // Lookup the name.
     LookupIterator it(object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
-    CHECK(GetPropertyAttributes(&it).has_value);
+    CHECK(GetPropertyAttributes(&it).IsJust());
     // ES5 forbids turning a property into an accessor if it's not
     // configurable. See 8.6.1 (Table 5).
     if (it.IsFound() && (it.IsReadOnly() || !it.IsConfigurable())) {
@@ -6747,10 +6728,8 @@ MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
       Handle<Object> current = PrototypeIterator::GetCurrent(iter);
       // Check access rights if needed.
       if (current->IsAccessCheckNeeded() &&
-          !isolate->MayNamedAccess(Handle<JSObject>::cast(current), name,
-                                   v8::ACCESS_HAS)) {
-        isolate->ReportFailedAccessCheck(Handle<JSObject>::cast(current),
-                                         v8::ACCESS_HAS);
+          !isolate->MayAccess(Handle<JSObject>::cast(current))) {
+        isolate->ReportFailedAccessCheck(Handle<JSObject>::cast(current));
         RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
         return isolate->factory()->undefined_value();
       }
@@ -6781,15 +6760,16 @@ MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
           UNREACHABLE();
 
         case LookupIterator::ACCESS_CHECK:
-          if (it.HasAccess(v8::ACCESS_HAS)) continue;
-          isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>(),
-                                           v8::ACCESS_HAS);
+          if (it.HasAccess()) continue;
+          isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
           RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
           return isolate->factory()->undefined_value();
 
         case LookupIterator::JSPROXY:
           return isolate->factory()->undefined_value();
 
+        case LookupIterator::INTEGER_INDEXED_EXOTIC:
+          return isolate->factory()->undefined_value();
         case LookupIterator::DATA:
           continue;
         case LookupIterator::ACCESSOR: {
@@ -6850,7 +6830,7 @@ Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
   Handle<Map> result = map->GetIsolate()->factory()->NewMap(
       map->instance_type(), instance_size);
   result->SetPrototype(handle(map->prototype(), map->GetIsolate()));
-  result->set_constructor(map->constructor());
+  result->set_constructor_or_backpointer(map->GetConstructor());
   result->set_bit_field(map->bit_field());
   result->set_bit_field2(map->bit_field2());
   int new_bit_field3 = map->bit_field3();
@@ -6888,7 +6868,7 @@ Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
     if (FLAG_enable_slow_asserts) {
       // The cached map should match newly created normalized map bit-by-bit,
       // except for the code cache, which can contain some ics which can be
-      // applied to the shared map.
+      // applied to the shared map, dependent code and weak cell cache.
       Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
 
       DCHECK(memcmp(fresh->address(),
@@ -6896,7 +6876,9 @@ Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
                     Map::kCodeCacheOffset) == 0);
       STATIC_ASSERT(Map::kDependentCodeOffset ==
                     Map::kCodeCacheOffset + kPointerSize);
-      int offset = Map::kDependentCodeOffset + kPointerSize;
+      STATIC_ASSERT(Map::kWeakCellCacheOffset ==
+                    Map::kDependentCodeOffset + kPointerSize);
+      int offset = Map::kWeakCellCacheOffset + kPointerSize;
       DCHECK(memcmp(fresh->address() + offset,
                     new_map->address() + offset,
                     Map::kSize - offset) == 0);
@@ -7017,11 +6999,12 @@ void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
 
 // 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));
+  Object* transitions = map->raw_transitions();
+  int num_transitions = TransitionArray::NumberOfTransitions(transitions);
+  for (int i = -0; i < num_transitions; ++i) {
+    Map* target = TransitionArray::GetTarget(transitions, i);
+    Name* key = TransitionArray::GetKey(transitions, i);
+    Map::TraceTransition("Transition", map, target, key);
     Map::TraceAllTransitions(target);
   }
 }
@@ -7038,13 +7021,7 @@ void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
     Map::TraceTransition("NoTransition", *parent, *child, *name);
 #endif
   } else {
-    Handle<TransitionArray> transitions =
-        TransitionArray::Insert(parent, name, child, flag);
-    if (!parent->HasTransitionArray() ||
-        *transitions != parent->transitions()) {
-      parent->set_transitions(*transitions);
-    }
-    child->SetBackPointer(*parent);
+    TransitionArray::Insert(parent, name, child, flag);
     if (child->prototype()->IsJSObject()) {
       Handle<JSObject> proto(JSObject::cast(child->prototype()));
       if (!child->ShouldRegisterAsPrototypeUser(proto)) {
@@ -7068,7 +7045,8 @@ Handle<Map> Map::CopyReplaceDescriptors(
   Handle<Map> result = CopyDropDescriptors(map);
 
   if (!map->is_prototype_map()) {
-    if (flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()) {
+    if (flag == INSERT_TRANSITION &&
+        TransitionArray::CanHaveMoreTransitions(map)) {
       result->InitializeDescriptors(*descriptors, *layout_descriptor);
 
       Handle<Name> name;
@@ -7092,7 +7070,8 @@ Handle<Map> Map::CopyReplaceDescriptors(
   if (FLAG_trace_maps &&
       // Mirror conditions above that did not call ConnectTransition().
       (map->is_prototype_map() ||
-       !(flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()))) {
+       !(flag == INSERT_TRANSITION &&
+         TransitionArray::CanHaveMoreTransitions(map)))) {
     PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
            reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
            reason);
@@ -7150,22 +7129,24 @@ Handle<Map> Map::CopyInstallDescriptors(
 
 Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
                                     TransitionFlag flag) {
+  Map* maybe_elements_transition_map = NULL;
   if (flag == INSERT_TRANSITION) {
-    DCHECK(!map->HasElementsTransition() ||
-        ((map->elements_transition_map()->elements_kind() ==
-          DICTIONARY_ELEMENTS ||
+    maybe_elements_transition_map = map->ElementsTransitionMap();
+    DCHECK(
+        maybe_elements_transition_map == NULL ||
+        ((maybe_elements_transition_map->elements_kind() ==
+              DICTIONARY_ELEMENTS ||
           IsExternalArrayElementsKind(
-              map->elements_transition_map()->elements_kind())) &&
-         (kind == DICTIONARY_ELEMENTS ||
-          IsExternalArrayElementsKind(kind))));
+              maybe_elements_transition_map->elements_kind())) &&
+         (kind == DICTIONARY_ELEMENTS || IsExternalArrayElementsKind(kind))));
     DCHECK(!IsFastElementsKind(kind) ||
            IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
     DCHECK(kind != map->elements_kind());
   }
 
   bool insert_transition = flag == INSERT_TRANSITION &&
-                           map->CanHaveMoreTransitions() &&
-                           !map->HasElementsTransition();
+                           TransitionArray::CanHaveMoreTransitions(map) &&
+                           maybe_elements_transition_map == NULL;
 
   if (insert_transition) {
     Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
@@ -7189,7 +7170,7 @@ Handle<Map> Map::CopyForObserved(Handle<Map> map) {
   Isolate* isolate = map->GetIsolate();
 
   bool insert_transition =
-      map->CanHaveMoreTransitions() && !map->is_prototype_map();
+      TransitionArray::CanHaveMoreTransitions(map) && !map->is_prototype_map();
 
   if (insert_transition) {
     Handle<Map> new_map = CopyForTransition(map, "CopyForObserved");
@@ -7355,9 +7336,10 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
   // Migrate to the newest map before storing the property.
   map = Update(map);
 
-  int index = map->SearchTransition(kData, *name, attributes);
-  if (index != TransitionArray::kNotFound) {
-    Handle<Map> transition(map->GetTransition(index));
+  Map* maybe_transition =
+      TransitionArray::SearchTransition(*map, kData, *name, attributes);
+  if (maybe_transition != NULL) {
+    Handle<Map> transition(maybe_transition);
     int descriptor = transition->LastAdded();
 
     DCHECK_EQ(attributes, transition->instance_descriptors()
@@ -7446,9 +7428,10 @@ Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
                                        ? KEEP_INOBJECT_PROPERTIES
                                        : CLEAR_INOBJECT_PROPERTIES;
 
-  int index = map->SearchTransition(kAccessor, *name, attributes);
-  if (index != TransitionArray::kNotFound) {
-    Handle<Map> transition(map->GetTransition(index));
+  Map* maybe_transition =
+      TransitionArray::SearchTransition(*map, kAccessor, *name, attributes);
+  if (maybe_transition != NULL) {
+    Handle<Map> transition(maybe_transition, isolate);
     DescriptorArray* descriptors = transition->instance_descriptors();
     int descriptor = transition->LastAdded();
     DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
@@ -7520,9 +7503,8 @@ Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
   // Ensure the key is unique.
   descriptor->KeyToUniqueName();
 
-  if (flag == INSERT_TRANSITION &&
-      map->owns_descriptors() &&
-      map->CanHaveMoreTransitions()) {
+  if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
+      TransitionArray::CanHaveMoreTransitions(map)) {
     return ShareDescriptor(map, descriptors, descriptor);
   }
 
@@ -7686,207 +7668,6 @@ void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
 }
 
 
-// An iterator over all map transitions in an descriptor array, reusing the
-// constructor field of the map while it is running. Negative values in
-// the constructor field indicate an active map transition iteration. The
-// original constructor is restored after iterating over all entries.
-class IntrusiveMapTransitionIterator {
- public:
-  IntrusiveMapTransitionIterator(
-      Map* map, TransitionArray* transition_array, Object* constructor)
-      : map_(map),
-        transition_array_(transition_array),
-        constructor_(constructor) { }
-
-  void StartIfNotStarted() {
-    DCHECK(!(*IteratorField())->IsSmi() || IsIterating());
-    if (!(*IteratorField())->IsSmi()) {
-      DCHECK(*IteratorField() == constructor_);
-      *IteratorField() = Smi::FromInt(-1);
-    }
-  }
-
-  bool IsIterating() {
-    return (*IteratorField())->IsSmi() &&
-           Smi::cast(*IteratorField())->value() < 0;
-  }
-
-  Map* Next() {
-    DCHECK(IsIterating());
-    int value = Smi::cast(*IteratorField())->value();
-    int index = -value - 1;
-    int number_of_transitions = transition_array_->number_of_transitions();
-    if (index < number_of_transitions) {
-      *IteratorField() = Smi::FromInt(value - 1);
-      return transition_array_->GetTarget(index);
-    }
-
-    *IteratorField() = constructor_;
-    return NULL;
-  }
-
- private:
-  Object** IteratorField() {
-    return HeapObject::RawField(map_, Map::kConstructorOffset);
-  }
-
-  Map* map_;
-  TransitionArray* transition_array_;
-  Object* constructor_;
-};
-
-
-// An iterator over all prototype transitions, reusing the constructor field
-// of the map while it is running.  Positive values in the constructor field
-// indicate an active prototype transition iteration. The original constructor
-// is restored after iterating over all entries.
-class IntrusivePrototypeTransitionIterator {
- public:
-  IntrusivePrototypeTransitionIterator(
-      Map* map, HeapObject* proto_trans, Object* constructor)
-      : map_(map), proto_trans_(proto_trans), constructor_(constructor) { }
-
-  void StartIfNotStarted() {
-    if (!(*IteratorField())->IsSmi()) {
-      DCHECK(*IteratorField() == constructor_);
-      *IteratorField() = Smi::FromInt(0);
-    }
-  }
-
-  bool IsIterating() {
-    return (*IteratorField())->IsSmi() &&
-           Smi::cast(*IteratorField())->value() >= 0;
-  }
-
-  Map* Next() {
-    DCHECK(IsIterating());
-    int transitionNumber = Smi::cast(*IteratorField())->value();
-    if (transitionNumber < NumberOfTransitions()) {
-      *IteratorField() = Smi::FromInt(transitionNumber + 1);
-      return GetTransition(transitionNumber);
-    }
-    *IteratorField() = constructor_;
-    return NULL;
-  }
-
- private:
-  Object** IteratorField() {
-    return HeapObject::RawField(map_, Map::kConstructorOffset);
-  }
-
-  int NumberOfTransitions() {
-    FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
-    Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
-    return Smi::cast(num)->value();
-  }
-
-  Map* GetTransition(int transitionNumber) {
-    FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
-    int index = Map::kProtoTransitionHeaderSize + transitionNumber;
-    return Map::cast(proto_trans->get(index));
-  }
-
-  Map* map_;
-  HeapObject* proto_trans_;
-  Object* constructor_;
-};
-
-
-// To traverse the transition tree iteratively, we have to store two kinds of
-// information in a map: The parent map in the traversal and which children of a
-// node have already been visited. To do this without additional memory, we
-// temporarily reuse two fields with known values:
-//
-//  (1) The map of the map temporarily holds the parent, and is restored to the
-//      meta map afterwards.
-//
-//  (2) The info which children have already been visited depends on which part
-//      of the map we currently iterate. We use the constructor field of the
-//      map to store the current index. We can do that because the constructor
-//      is the same for all involved maps.
-//
-//    (a) If we currently follow normal map transitions, we temporarily store
-//        the current index in the constructor field, and restore it to the
-//        original constructor afterwards. Note that a single descriptor can
-//        have 0, 1, or 2 transitions.
-//
-//    (b) If we currently follow prototype transitions, we temporarily store
-//        the current index in the constructor field, and restore it to the
-//        original constructor afterwards.
-//
-// Note that the child iterator is just a concatenation of two iterators: One
-// iterating over map transitions and one iterating over prototype transisitons.
-class TraversableMap : public Map {
- public:
-  // Record the parent in the traversal within this map. Note that this destroys
-  // this map's map!
-  void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
-
-  // Reset the current map's map, returning the parent previously stored in it.
-  TraversableMap* GetAndResetParent() {
-    TraversableMap* old_parent = static_cast<TraversableMap*>(map());
-    set_map_no_write_barrier(GetHeap()->meta_map());
-    return old_parent;
-  }
-
-  // If we have an unvisited child map, return that one and advance. If we have
-  // none, return NULL and restore the overwritten constructor field.
-  TraversableMap* ChildIteratorNext(Object* constructor) {
-    if (!HasTransitionArray()) return NULL;
-
-    TransitionArray* transition_array = transitions();
-    if (transition_array->HasPrototypeTransitions()) {
-      HeapObject* proto_transitions =
-          transition_array->GetPrototypeTransitions();
-      IntrusivePrototypeTransitionIterator proto_iterator(this,
-                                                          proto_transitions,
-                                                          constructor);
-      proto_iterator.StartIfNotStarted();
-      if (proto_iterator.IsIterating()) {
-        Map* next = proto_iterator.Next();
-        if (next != NULL) return static_cast<TraversableMap*>(next);
-      }
-    }
-
-    IntrusiveMapTransitionIterator transition_iterator(this,
-                                                       transition_array,
-                                                       constructor);
-    transition_iterator.StartIfNotStarted();
-    if (transition_iterator.IsIterating()) {
-      Map* next = transition_iterator.Next();
-      if (next != NULL) return static_cast<TraversableMap*>(next);
-    }
-
-    return NULL;
-  }
-};
-
-
-// Traverse the transition tree in postorder without using the C++ stack by
-// doing pointer reversal.
-void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
-  // Make sure that we do not allocate in the callback.
-  DisallowHeapAllocation no_allocation;
-
-  TraversableMap* current = static_cast<TraversableMap*>(this);
-  // Get the root constructor here to restore it later when finished iterating
-  // over maps.
-  Object* root_constructor = constructor();
-  while (true) {
-    TraversableMap* child = current->ChildIteratorNext(root_constructor);
-    if (child != NULL) {
-      child->SetParent(current);
-      current = child;
-    } else {
-      TraversableMap* parent = current->GetAndResetParent();
-      callback(current, data);
-      if (current == this) break;
-      current = parent;
-    }
-  }
-}
-
-
 void CodeCache::Update(
     Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
   // The number of monomorphic stubs for normal load/store/call IC's can grow to
@@ -8505,6 +8286,47 @@ Handle<WeakFixedArray> WeakFixedArray::Allocate(
 }
 
 
+Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj,
+                                 AddMode mode) {
+  int length = array->Length();
+  array = EnsureSpace(array, length + 1);
+  if (mode == kReloadLengthAfterAllocation) {
+    DCHECK(array->Length() <= length);
+    length = array->Length();
+  }
+  array->Set(length, *obj);
+  array->SetLength(length + 1);
+  return array;
+}
+
+
+Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
+                                 Handle<Object> obj2, AddMode mode) {
+  int length = array->Length();
+  array = EnsureSpace(array, length + 2);
+  if (mode == kReloadLengthAfterAllocation) {
+    length = array->Length();
+  }
+  array->Set(length, *obj1);
+  array->Set(length + 1, *obj2);
+  array->SetLength(length + 2);
+  return array;
+}
+
+
+Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
+  int capacity = array->length();
+  bool empty = (capacity == 0);
+  if (capacity < kFirstIndex + length) {
+    capacity = kFirstIndex + length;
+    capacity = capacity + Max(capacity / 2, 2);
+    array = Handle<ArrayList>::cast(FixedArray::CopySize(array, capacity));
+    if (empty) array->SetLength(0);
+  }
+  return array;
+}
+
+
 Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
                                                   int number_of_descriptors,
                                                   int slack) {
@@ -8655,6 +8477,36 @@ Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
 }
 
 
+int HandlerTable::LookupRange(int pc_offset, int* stack_depth_out) {
+  int innermost_handler = -1, innermost_start = -1;
+  for (int i = 0; i < length(); i += kRangeEntrySize) {
+    int start_offset = Smi::cast(get(i + kRangeStartIndex))->value();
+    int end_offset = Smi::cast(get(i + kRangeEndIndex))->value();
+    int handler_offset = Smi::cast(get(i + kRangeHandlerIndex))->value();
+    int stack_depth = Smi::cast(get(i + kRangeDepthIndex))->value();
+    if (pc_offset > start_offset && pc_offset <= end_offset) {
+      DCHECK_NE(start_offset, innermost_start);
+      if (start_offset < innermost_start) continue;
+      innermost_handler = handler_offset;
+      innermost_start = start_offset;
+      *stack_depth_out = stack_depth;
+    }
+  }
+  return innermost_handler;
+}
+
+
+// TODO(turbofan): Make sure table is sorted and use binary search.
+int HandlerTable::LookupReturn(int pc_offset) {
+  for (int i = 0; i < length(); i += kReturnEntrySize) {
+    int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
+    int handler_offset = Smi::cast(get(i + kReturnHandlerIndex))->value();
+    if (pc_offset == return_offset) return handler_offset;
+  }
+  return -1;
+}
+
+
 #ifdef DEBUG
 bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
   if (IsEmpty()) return other->IsEmpty();
@@ -9733,7 +9585,7 @@ int Map::Hash() {
   // addresses.
 
   // Shift away the tag.
-  int hash = ObjectAddressForHashing(constructor()) >> 2;
+  int hash = ObjectAddressForHashing(GetConstructor()) >> 2;
 
   // XOR-ing the prototype and constructor directly yields too many zero bits
   // when the two pointers are close (which is fairly common).
@@ -9745,7 +9597,7 @@ int Map::Hash() {
 
 
 static bool CheckEquivalent(Map* first, Map* second) {
-  return first->constructor() == second->constructor() &&
+  return first->GetConstructor() == second->GetConstructor() &&
          first->prototype() == second->prototype() &&
          first->instance_type() == second->instance_type() &&
          first->bit_field() == second->bit_field() &&
@@ -9823,7 +9675,6 @@ void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
 
 void JSFunction::MarkForOptimization() {
   Isolate* isolate = GetIsolate();
-  DCHECK(isolate->use_crankshaft());
   DCHECK(!IsOptimized());
   DCHECK(shared()->allows_lazy_compilation() || code()->optimizable());
   set_code_no_write_barrier(
@@ -9847,9 +9698,7 @@ void JSFunction::AttemptConcurrentOptimization() {
     // recompilation race.  This goes away as soon as OSR becomes one-shot.
     return;
   }
-  DCHECK(isolate->use_crankshaft());
   DCHECK(!IsInOptimizationQueue());
-  DCHECK(is_compiled() || isolate->debug()->has_break_points());
   DCHECK(!IsOptimized());
   DCHECK(shared()->allows_lazy_compilation() || code()->optimizable());
   DCHECK(isolate->concurrent_recompilation_enabled());
@@ -10033,11 +9882,65 @@ void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
 }
 
 
+static void GetMinInobjectSlack(Map* map, void* data) {
+  int slack = map->unused_property_fields();
+  if (*reinterpret_cast<int*>(data) > slack) {
+    *reinterpret_cast<int*>(data) = slack;
+  }
+}
+
+
+static void ShrinkInstanceSize(Map* map, void* data) {
+  int slack = *reinterpret_cast<int*>(data);
+  map->set_inobject_properties(map->inobject_properties() - slack);
+  map->set_unused_property_fields(map->unused_property_fields() - slack);
+  map->set_instance_size(map->instance_size() - slack * kPointerSize);
+
+  // Visitor id might depend on the instance size, recalculate it.
+  map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
+}
+
+
+void JSFunction::CompleteInobjectSlackTracking() {
+  DCHECK(has_initial_map());
+  Map* map = initial_map();
+
+  DCHECK(map->counter() >= Map::kSlackTrackingCounterEnd - 1);
+  map->set_counter(Map::kRetainingCounterStart);
+
+  int slack = map->unused_property_fields();
+  TransitionArray::TraverseTransitionTree(map, &GetMinInobjectSlack, &slack);
+  if (slack != 0) {
+    // Resize the initial map and all maps in its transition tree.
+    TransitionArray::TraverseTransitionTree(map, &ShrinkInstanceSize, &slack);
+  }
+}
+
+
+static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
+  DisallowHeapAllocation no_gc;
+  if (!object->HasFastProperties()) return false;
+  Map* map = object->map();
+  if (map->is_prototype_map()) return false;
+  DescriptorArray* descriptors = map->instance_descriptors();
+  for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
+    PropertyDetails details = descriptors->GetDetails(i);
+    if (details.location() == kDescriptor) continue;
+    if (details.representation().IsHeapObject() ||
+        details.representation().IsTagged()) {
+      FieldIndex index = FieldIndex::ForDescriptor(map, i);
+      if (object->RawFastPropertyAt(index)->IsJSFunction()) return true;
+    }
+  }
+  return false;
+}
+
+
 void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
                                    PrototypeOptimizationMode mode) {
   if (object->IsGlobalObject()) return;
   if (object->IsJSGlobalProxy()) return;
-  if (mode == FAST_PROTOTYPE && !object->map()->is_prototype_map()) {
+  if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) {
     // First normalize to ensure all JSFunctions are DATA_CONSTANT.
     JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
                                   "NormalizeAsPrototype");
@@ -10053,8 +9956,9 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
       Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
       JSObject::MigrateToMap(object, new_map);
     }
-    if (object->map()->constructor()->IsJSFunction()) {
-      JSFunction* constructor = JSFunction::cast(object->map()->constructor());
+    Object* maybe_constructor = object->map()->GetConstructor();
+    if (maybe_constructor->IsJSFunction()) {
+      JSFunction* constructor = JSFunction::cast(maybe_constructor);
       // Replace the pointer to the exact constructor with the Object function
       // from the same context if undetectable from JS. This is to avoid keeping
       // memory alive unnecessarily.
@@ -10063,7 +9967,7 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
               object->GetIsolate()->heap()->Object_string()) {
         Context* context = constructor->context()->native_context();
         JSFunction* object_function = context->object_function();
-        object->map()->set_constructor(object_function);
+        object->map()->SetConstructor(object_function);
       }
     }
     object->map()->set_is_prototype_map(true);
@@ -10161,8 +10065,9 @@ Handle<Object> CacheInitialJSArrayMaps(
        i < kFastElementsKindCount; ++i) {
     Handle<Map> new_map;
     ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
-    if (current_map->HasElementsTransition()) {
-      new_map = handle(current_map->elements_transition_map());
+    Map* maybe_elements_transition = current_map->ElementsTransitionMap();
+    if (maybe_elements_transition != NULL) {
+      new_map = handle(maybe_elements_transition);
       DCHECK(new_map->elements_kind() == next_kind);
     } else {
       new_map = Map::CopyAsElementsKind(
@@ -10224,6 +10129,11 @@ void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
     // needed.  At that point, a new initial map is created and the
     // prototype is put into the initial map where it belongs.
     function->set_prototype_or_initial_map(*value);
+    if (value->IsJSObject()) {
+      // Optimize as prototype to detach it from its transition tree.
+      JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value),
+                                    FAST_PROTOTYPE);
+    }
   }
   isolate->heap()->ClearInstanceofCache();
 }
@@ -10245,7 +10155,7 @@ void JSFunction::SetPrototype(Handle<JSFunction> function,
     Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype");
 
     JSObject::MigrateToMap(function, new_map);
-    new_map->set_constructor(*value);
+    new_map->SetConstructor(*value);
     new_map->set_non_instance_prototype(true);
     Isolate* isolate = new_map->GetIsolate();
     construct_prototype = handle(
@@ -10288,7 +10198,7 @@ void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
     map->SetPrototype(prototype, FAST_PROTOTYPE);
   }
   function->set_prototype_or_initial_map(*map);
-  map->set_constructor(*function);
+  map->SetConstructor(*function);
 #if TRACE_MAPS
   if (FLAG_trace_maps) {
     PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n",
@@ -10350,11 +10260,6 @@ void JSFunction::PrintName(FILE* out) {
 }
 
 
-Context* JSFunction::NativeContextFromLiterals(FixedArray* literals) {
-  return Context::cast(literals->get(JSFunction::kLiteralNativeContextIndex));
-}
-
-
 // The filter is a pattern that matches function names in this way:
 //   "*"      all; the default
 //   "-"      all but the top-level function
@@ -10392,6 +10297,15 @@ bool JSFunction::PassesFilter(const char* raw_filter) {
 }
 
 
+Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
+  Isolate* isolate = function->GetIsolate();
+  Handle<Object> name =
+      JSObject::GetDataProperty(function, isolate->factory()->name_string());
+  if (name->IsString()) return Handle<String>::cast(name);
+  return handle(function->shared()->DebugName(), isolate);
+}
+
+
 void Oddball::Initialize(Isolate* isolate,
                          Handle<Oddball> oddball,
                          const char* to_string,
@@ -10520,6 +10434,7 @@ Handle<Object> Script::GetNameOrSourceURL(Handle<Script> script) {
 Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
   Isolate* isolate = script->GetIsolate();
   if (!script->wrapper()->IsUndefined()) {
+    DCHECK(script->wrapper()->IsWeakCell());
     Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
     if (!cell->cleared()) {
       // Return a handle for the existing script wrapper from the cache.
@@ -10766,41 +10681,6 @@ void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
 }
 
 
-static void GetMinInobjectSlack(Map* map, void* data) {
-  int slack = map->unused_property_fields();
-  if (*reinterpret_cast<int*>(data) > slack) {
-    *reinterpret_cast<int*>(data) = slack;
-  }
-}
-
-
-static void ShrinkInstanceSize(Map* map, void* data) {
-  int slack = *reinterpret_cast<int*>(data);
-  map->set_inobject_properties(map->inobject_properties() - slack);
-  map->set_unused_property_fields(map->unused_property_fields() - slack);
-  map->set_instance_size(map->instance_size() - slack * kPointerSize);
-
-  // Visitor id might depend on the instance size, recalculate it.
-  map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
-}
-
-
-void JSFunction::CompleteInobjectSlackTracking() {
-  DCHECK(has_initial_map());
-  Map* map = initial_map();
-
-  DCHECK(map->counter() >= Map::kSlackTrackingCounterEnd - 1);
-  map->set_counter(Map::kRetainingCounterStart);
-
-  int slack = map->unused_property_fields();
-  map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
-  if (slack != 0) {
-    // Resize the initial map and all maps in its transition tree.
-    map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
-  }
-}
-
-
 int SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context,
                                                BailoutId osr_ast_id) {
   DisallowHeapAllocation no_gc;
@@ -10902,7 +10782,7 @@ void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
 
 
 void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
-  Address p = rinfo->target_reference();
+  Address p = rinfo->target_external_reference();
   VisitExternalReference(&p);
 }
 
@@ -11411,11 +11291,18 @@ Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
 }
 
 
-void Code::PrintDeoptLocation(FILE* out, int bailout_id) {
-  Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, bailout_id);
-  if (info.deopt_reason != Deoptimizer::kNoReason || info.raw_position != 0) {
-    PrintF(out, "            ;;; deoptimize at %d: %s\n", info.raw_position,
-           Deoptimizer::GetDeoptReason(info.deopt_reason));
+void Code::PrintDeoptLocation(FILE* out, Address pc) {
+  Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
+  class SourcePosition pos = info.position;
+  if (info.deopt_reason != Deoptimizer::kNoReason || !pos.IsUnknown()) {
+    if (FLAG_hydrogen_track_positions) {
+      PrintF(out, "            ;;; deoptimize at %d_%d: %s\n",
+             pos.inlining_id(), pos.position(),
+             Deoptimizer::GetDeoptReason(info.deopt_reason));
+    } else {
+      PrintF(out, "            ;;; deoptimize at %d: %s\n", pos.raw(),
+             Deoptimizer::GetDeoptReason(info.deopt_reason));
+    }
   }
 }
 
@@ -11482,11 +11369,9 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(
     os << "\n";
   }
   for (int i = 0; i < deopt_count; i++) {
-    // TODO(svenpanne) Add some basic formatting to our streams.
-    Vector<char> buf1 = Vector<char>::New(128);
-    SNPrintF(buf1, "%6d  %6d  %6d %6d", i, AstId(i).ToInt(),
-             ArgumentsStackHeight(i)->value(), Pc(i)->value());
-    os << buf1.start();
+    os << std::setw(6) << i << "  " << std::setw(6) << AstId(i).ToInt() << "  "
+       << std::setw(6) << ArgumentsStackHeight(i)->value() << " "
+       << std::setw(6) << Pc(i)->value();
 
     if (!FLAG_print_code_verbose) {
       os << "\n";
@@ -11507,9 +11392,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(
     while (iterator.HasNext() &&
            Translation::BEGIN !=
            (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
-      Vector<char> buf2 = Vector<char>::New(128);
-      SNPrintF(buf2, "%27s    %s ", "", Translation::StringFor(opcode));
-      os << buf2.start();
+      os << std::setw(31) << "    " << Translation::StringFor(opcode) << " ";
 
       switch (opcode) {
         case Translation::BEGIN:
@@ -11641,13 +11524,34 @@ void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
   os << "ast id        pc  state\n";
   for (int i = 0; i < this->DeoptPoints(); i++) {
     int pc_and_state = this->PcAndState(i)->value();
-    // TODO(svenpanne) Add some basic formatting to our streams.
-    Vector<char> buf = Vector<char>::New(100);
-    SNPrintF(buf, "%6d  %8d  %s\n", this->AstId(i).ToInt(),
-             FullCodeGenerator::PcField::decode(pc_and_state),
-             FullCodeGenerator::State2String(
-                 FullCodeGenerator::StateField::decode(pc_and_state)));
-    os << buf.start();
+    os << std::setw(6) << this->AstId(i).ToInt() << "  " << std::setw(8)
+       << FullCodeGenerator::PcField::decode(pc_and_state) << "  "
+       << FullCodeGenerator::State2String(
+              FullCodeGenerator::StateField::decode(pc_and_state)) << "\n";
+  }
+}
+
+
+void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
+  os << "   from   to       hdlr\n";
+  for (int i = 0; i < length(); i += kRangeEntrySize) {
+    int pc_start = Smi::cast(get(i + kRangeStartIndex))->value();
+    int pc_end = Smi::cast(get(i + kRangeEndIndex))->value();
+    int handler = Smi::cast(get(i + kRangeHandlerIndex))->value();
+    int depth = Smi::cast(get(i + kRangeDepthIndex))->value();
+    os << "  (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
+       << ")  ->  " << std::setw(4) << handler << " (depth=" << depth << ")\n";
+  }
+}
+
+
+void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
+  os << "   off      hdlr\n";
+  for (int i = 0; i < length(); i += kReturnEntrySize) {
+    int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
+    int handler = Smi::cast(get(i + kReturnHandlerIndex))->value();
+    os << "  " << std::setw(4) << pc_offset << "  ->  " << std::setw(4)
+       << handler << "\n";
   }
 }
 
@@ -11755,17 +11659,12 @@ void Code::Disassemble(const char* name, std::ostream& os) {  // NOLINT
     for (unsigned i = 0; i < table.length(); i++) {
       unsigned pc_offset = table.GetPcOffset(i);
       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);
-      os << buf1.start() << "  ";
+      os << std::setw(4) << pc_offset << "  ";
       table.PrintEntry(i, os);
       os << " (sp -> fp)  ";
       SafepointEntry entry = table.GetEntry(i);
       if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
-        Vector<char> buf2 = Vector<char>::New(30);
-        SNPrintF(buf2, "%6d", entry.deoptimization_index());
-        os << buf2.start();
+        os << std::setw(6) << entry.deoptimization_index();
       } else {
         os << "<none>";
       }
@@ -11787,10 +11686,9 @@ void Code::Disassemble(const char* name, std::ostream& os) {  // NOLINT
       os << "ast_id  pc_offset  loop_depth\n";
 
       for (uint32_t i = 0; i < back_edges.length(); i++) {
-        Vector<char> buf = Vector<char>::New(100);
-        SNPrintF(buf, "%6d  %9u  %10u\n", back_edges.ast_id(i).ToInt(),
-                 back_edges.pc_offset(i), back_edges.loop_depth(i));
-        os << buf.start();
+        os << std::setw(6) << back_edges.ast_id(i).ToInt() << "  "
+           << std::setw(9) << back_edges.pc_offset(i) << "  " << std::setw(10)
+           << back_edges.loop_depth(i) << "\n";
       }
 
       os << "\n";
@@ -11804,6 +11702,16 @@ void Code::Disassemble(const char* name, std::ostream& os) {  // NOLINT
 #endif
   }
 
+  if (handler_table()->length() > 0) {
+    os << "Handler Table (size = " << handler_table()->Size() << ")\n";
+    if (kind() == FUNCTION) {
+      HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
+    } else if (kind() == OPTIMIZED_FUNCTION) {
+      HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os);
+    }
+    os << "\n";
+  }
+
   os << "RelocInfo (size = " << relocation_size() << ")\n";
   for (RelocIterator it(this); !it.done(); it.next()) {
     it.rinfo()->Print(GetIsolate(), os);
@@ -11948,9 +11856,9 @@ static bool GetOldValue(Isolate* isolate,
                         List<uint32_t>* indices) {
   Maybe<PropertyAttributes> maybe =
       JSReceiver::GetOwnElementAttribute(object, index);
-  DCHECK(maybe.has_value);
-  DCHECK(maybe.value != ABSENT);
-  if (maybe.value == DONT_DELETE) return false;
+  DCHECK(maybe.IsJust());
+  DCHECK(maybe.FromJust() != ABSENT);
+  if (maybe.FromJust() == DONT_DELETE) return false;
   Handle<Object> value;
   if (!JSObject::GetOwnElementAccessorPair(object, index).is_null()) {
     value = Handle<Object>::cast(isolate->factory()->the_hole_value());
@@ -12113,77 +12021,6 @@ MaybeHandle<Object> JSArray::SetElementsLength(
 }
 
 
-Handle<Map> Map::GetPrototypeTransition(Handle<Map> map,
-                                        Handle<Object> prototype) {
-  DisallowHeapAllocation no_gc;
-  FixedArray* cache = map->GetPrototypeTransitions();
-  int number_of_transitions = map->NumberOfProtoTransitions();
-  for (int i = 0; i < number_of_transitions; i++) {
-    Map* map = Map::cast(cache->get(kProtoTransitionHeaderSize + i));
-    if (map->prototype() == *prototype) return handle(map);
-  }
-  return Handle<Map>();
-}
-
-
-Handle<Map> Map::PutPrototypeTransition(Handle<Map> map,
-                                        Handle<Object> prototype,
-                                        Handle<Map> target_map) {
-  DCHECK(target_map->IsMap());
-  DCHECK(HeapObject::cast(*prototype)->map()->IsMap());
-  // Don't cache prototype transition if this map is either shared, or a map of
-  // a prototype.
-  if (map->is_prototype_map()) return map;
-  if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return map;
-
-  const int header = kProtoTransitionHeaderSize;
-
-  Handle<FixedArray> cache(map->GetPrototypeTransitions());
-  int capacity = cache->length() - header;
-  int transitions = map->NumberOfProtoTransitions() + 1;
-
-  if (transitions > capacity) {
-    // Grow array by factor 2 up to MaxCachedPrototypeTransitions.
-    int new_capacity = Min(kMaxCachedPrototypeTransitions, transitions * 2);
-    if (new_capacity == capacity) return map;
-
-    cache = FixedArray::CopySize(cache, header + new_capacity);
-
-    SetPrototypeTransitions(map, cache);
-  }
-
-  // Reload number of transitions as GC might shrink them.
-  int last = map->NumberOfProtoTransitions();
-  int entry = header + last;
-
-  cache->set(entry, *target_map);
-  map->SetNumberOfProtoTransitions(last + 1);
-
-  return map;
-}
-
-
-void Map::ZapTransitions() {
-  TransitionArray* transition_array = transitions();
-  // TODO(mstarzinger): Temporarily use a slower version instead of the faster
-  // MemsetPointer to investigate a crasher. Switch back to MemsetPointer.
-  Object** data = transition_array->data_start();
-  Object* the_hole = GetHeap()->the_hole_value();
-  int length = transition_array->length();
-  for (int i = 0; i < length; i++) {
-    data[i] = the_hole;
-  }
-}
-
-
-void Map::ZapPrototypeTransitions() {
-  FixedArray* proto_transitions = GetPrototypeTransitions();
-  MemsetPointer(proto_transitions->data_start(),
-                GetHeap()->the_hole_value(),
-                proto_transitions->length());
-}
-
-
 // static
 void Map::AddDependentCompilationInfo(Handle<Map> map,
                                       DependentCode::DependencyGroup group,
@@ -12489,10 +12326,10 @@ const char* DependentCode::DependencyGroupName(DependencyGroup group) {
 Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
                                        Handle<Object> prototype,
                                        PrototypeOptimizationMode mode) {
-  Handle<Map> new_map = GetPrototypeTransition(map, prototype);
+  Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype);
   if (new_map.is_null()) {
     new_map = Copy(map, "TransitionToPrototype");
-    PutPrototypeTransition(map, prototype, new_map);
+    TransitionArray::PutPrototypeTransition(map, prototype, new_map);
     new_map->SetPrototype(prototype, mode);
   }
   return new_map;
@@ -12948,7 +12785,8 @@ MaybeHandle<Object> JSObject::SetDictionaryElement(
              element->IsTheHole());
       dictionary->UpdateMaxNumberKey(index);
       if (set_mode == DEFINE_PROPERTY) {
-        details = PropertyDetails(attributes, DATA, details.dictionary_index());
+        details = PropertyDetails(attributes, DATA, details.dictionary_index(),
+                                  PropertyCellType::kInvalid);
         dictionary->DetailsAtPut(entry, details);
       }
 
@@ -12991,7 +12829,7 @@ MaybeHandle<Object> JSObject::SetDictionaryElement(
       }
     }
 
-    PropertyDetails details(attributes, DATA, 0);
+    PropertyDetails details(attributes, DATA, 0, PropertyCellType::kInvalid);
     Handle<SeededNumberDictionary> new_dictionary =
         SeededNumberDictionary::AddNumberEntry(dictionary, index, value,
                                                details);
@@ -13184,8 +13022,8 @@ MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object,
 
   // Check access rights if needed.
   if (object->IsAccessCheckNeeded()) {
-    if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_SET)) {
-      isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
+    if (!isolate->MayAccess(object)) {
+      isolate->ReportFailedAccessCheck(object);
       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
       return value;
     }
@@ -13230,8 +13068,8 @@ MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object,
 
   Maybe<PropertyAttributes> maybe =
       JSReceiver::GetOwnElementAttribute(object, index);
-  if (!maybe.has_value) return MaybeHandle<Object>();
-  PropertyAttributes old_attributes = maybe.value;
+  if (!maybe.IsJust()) return MaybeHandle<Object>();
+  PropertyAttributes old_attributes = maybe.FromJust();
 
   Handle<Object> old_value = isolate->factory()->the_hole_value();
   Handle<Object> old_length_handle;
@@ -13261,8 +13099,8 @@ MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object,
 
   Handle<String> name = isolate->factory()->Uint32ToString(index);
   maybe = GetOwnElementAttribute(object, index);
-  if (!maybe.has_value) return MaybeHandle<Object>();
-  PropertyAttributes new_attributes = maybe.value;
+  if (!maybe.IsJust()) return MaybeHandle<Object>();
+  PropertyAttributes new_attributes = maybe.FromJust();
 
   if (old_attributes == ABSENT) {
     if (object->IsJSArray() &&
@@ -13960,7 +13798,7 @@ void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) {
 
 InterceptorInfo* JSObject::GetNamedInterceptor() {
   DCHECK(map()->has_named_interceptor());
-  JSFunction* constructor = JSFunction::cast(map()->constructor());
+  JSFunction* constructor = JSFunction::cast(map()->GetConstructor());
   DCHECK(constructor->shared()->IsApiFunction());
   Object* result =
       constructor->shared()->get_api_func_data()->named_property_handler();
@@ -13970,7 +13808,7 @@ InterceptorInfo* JSObject::GetNamedInterceptor() {
 
 InterceptorInfo* JSObject::GetIndexedInterceptor() {
   DCHECK(map()->has_indexed_interceptor());
-  JSFunction* constructor = JSFunction::cast(map()->constructor());
+  JSFunction* constructor = JSFunction::cast(map()->GetConstructor());
   DCHECK(constructor->shared()->IsApiFunction());
   Object* result =
       constructor->shared()->get_api_func_data()->indexed_property_handler();
@@ -14059,8 +13897,8 @@ Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
                                            Handle<Name> key) {
   LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
   Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
-  if (!maybe_result.has_value) return Maybe<bool>();
-  return maybe(it.IsFound());
+  if (!maybe_result.IsJust()) return Nothing<bool>();
+  return Just(it.IsFound());
 }
 
 
@@ -14070,17 +13908,17 @@ Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
   HandleScope scope(isolate);
   // 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<bool>());
-      return maybe(false);
+    if (!isolate->MayAccess(object)) {
+      isolate->ReportFailedAccessCheck(object);
+      RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
+      return Just(false);
     }
   }
 
   if (object->IsJSGlobalProxy()) {
     HandleScope scope(isolate);
     PrototypeIterator iter(isolate, object);
-    if (iter.IsAtEnd()) return maybe(false);
+    if (iter.IsAtEnd()) return Just(false);
     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
     return HasRealElementProperty(
         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index);
@@ -14088,8 +13926,7 @@ Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
 
   Maybe<PropertyAttributes> result =
       GetElementAttributeWithoutInterceptor(object, object, index, false);
-  if (!result.has_value) return Maybe<bool>();
-  return maybe(result.value != ABSENT);
+  return result.IsJust() ? Just(result.FromJust() != ABSENT) : Nothing<bool>();
 }
 
 
@@ -14097,8 +13934,8 @@ Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
                                                    Handle<Name> key) {
   LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
   Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
-  if (!maybe_result.has_value) return Maybe<bool>();
-  return maybe(it.state() == LookupIterator::ACCESSOR);
+  return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
+                               : Nothing<bool>();
 }
 
 
@@ -14112,7 +13949,7 @@ int JSObject::NumberOfOwnProperties(PropertyAttributes filter) {
     }
     return map->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter);
   }
-  return property_dictionary()->NumberOfElementsFilterAttributes(filter);
+  return property_dictionary()->NumberOfElementsFilterAttributes(this, filter);
 }
 
 
@@ -14245,9 +14082,7 @@ void JSObject::GetOwnPropertyNames(
       }
     }
   } else {
-    property_dictionary()->CopyKeysTo(storage,
-                                      index,
-                                      filter,
+    property_dictionary()->CopyKeysTo(this, storage, index, filter,
                                       NameDictionary::UNSORTED);
   }
 }
@@ -14331,11 +14166,13 @@ int JSObject::GetOwnElementKeys(FixedArray* storage,
 
     case DICTIONARY_ELEMENTS: {
       if (storage != NULL) {
-        element_dictionary()->CopyKeysTo(storage,
-                                         filter,
-                                         SeededNumberDictionary::SORTED);
+        element_dictionary()->CopyKeysTo<DictionaryEntryType::kObjects>(
+            storage, filter, SeededNumberDictionary::SORTED);
       }
-      counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
+      counter +=
+          element_dictionary()
+              ->NumberOfElementsFilterAttributes<DictionaryEntryType::kObjects>(
+                  filter);
       break;
     }
     case SLOPPY_ARGUMENTS_ELEMENTS: {
@@ -14348,10 +14185,11 @@ int JSObject::GetOwnElementKeys(FixedArray* storage,
         SeededNumberDictionary* dictionary =
             SeededNumberDictionary::cast(arguments);
         if (storage != NULL) {
-          dictionary->CopyKeysTo(
+          dictionary->CopyKeysTo<DictionaryEntryType::kObjects>(
               storage, filter, SeededNumberDictionary::UNSORTED);
         }
-        counter += dictionary->NumberOfElementsFilterAttributes(filter);
+        counter += dictionary->NumberOfElementsFilterAttributes<
+            DictionaryEntryType::kObjects>(filter);
         for (int i = 0; i < mapped_length; ++i) {
           if (!parameter_map->get(i + 2)->IsTheHole()) {
             if (storage != NULL) storage->set(counter, Smi::FromInt(i));
@@ -14942,15 +14780,6 @@ template Object*
 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
     SlowReverseLookup(Object* value);
 
-template void
-Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
-    CopyKeysTo(
-        FixedArray*,
-        PropertyAttributes,
-        Dictionary<SeededNumberDictionary,
-                   SeededNumberDictionaryShape,
-                   uint32_t>::SortMode);
-
 template Handle<Object>
 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
     Handle<NameDictionary>, int);
@@ -14971,18 +14800,6 @@ template Handle<SeededNumberDictionary>
 HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
     Shrink(Handle<SeededNumberDictionary>, uint32_t);
 
-template void Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
-    CopyKeysTo(
-        FixedArray*,
-        int,
-        PropertyAttributes,
-        Dictionary<
-            NameDictionary, NameDictionaryShape, Handle<Name> >::SortMode);
-
-template int
-Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
-    NumberOfElementsFilterAttributes(PropertyAttributes);
-
 template Handle<NameDictionary>
 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::Add(
     Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails);
@@ -14995,10 +14812,6 @@ template Handle<FixedArray> Dictionary<
     NameDictionary, NameDictionaryShape,
     Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>);
 
-template int
-Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
-    NumberOfElementsFilterAttributes(PropertyAttributes);
-
 template Handle<SeededNumberDictionary>
 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
     Add(Handle<SeededNumberDictionary>,
@@ -15025,16 +14838,13 @@ template Handle<NameDictionary>
 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
     EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
 
-template
-int Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
-    NumberOfEnumElements();
-
-template
-int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
-    NumberOfEnumElements();
+template bool
+Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
+           uint32_t>::HasComplexElements<DictionaryEntryType::kCells>();
 
-template bool Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
-                         uint32_t>::HasComplexElements();
+template bool
+Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
+           uint32_t>::HasComplexElements<DictionaryEntryType::kObjects>();
 
 template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape,
                        uint32_t>::FindEntry(uint32_t);
@@ -15104,7 +14914,7 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
   }
 
   uint32_t result = pos;
-  PropertyDetails no_details(NONE, DATA, 0);
+  PropertyDetails no_details = PropertyDetails::Empty();
   while (undefs > 0) {
     if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
       // Adding an entry with the key beyond smi-range requires
@@ -15465,40 +15275,37 @@ Handle<Object> ExternalFloat64Array::SetValue(
 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);
-  }
+  auto dictionary = handle(global->property_dictionary());
+  int entry = dictionary->FindEntry(name);
+  if (entry == NameDictionary::kNotFound) return;
+  PropertyCell::InvalidateEntry(dictionary, entry);
 }
 
 
+// TODO(dcarney): rename to EnsureEmptyPropertyCell or something.
 Handle<PropertyCell> GlobalObject::EnsurePropertyCell(
     Handle<GlobalObject> global, Handle<Name> name) {
   DCHECK(!global->HasFastProperties());
-  int entry = global->property_dictionary()->FindEntry(name);
-  if (entry == NameDictionary::kNotFound) {
-    Isolate* isolate = global->GetIsolate();
-    Handle<PropertyCell> cell = isolate->factory()->NewPropertyCellWithHole();
-    PropertyDetails details(NONE, DATA, 0);
-    details = details.AsDeleted();
-    Handle<NameDictionary> dictionary = NameDictionary::Add(
-        handle(global->property_dictionary()), name, cell, details);
-    global->set_properties(*dictionary);
+  auto dictionary = handle(global->property_dictionary());
+  int entry = dictionary->FindEntry(name);
+  Handle<PropertyCell> cell;
+  if (entry != NameDictionary::kNotFound) {
+    // This call should be idempotent.
+    DCHECK(dictionary->DetailsAt(entry).cell_type() ==
+               PropertyCellType::kUninitialized ||
+           dictionary->DetailsAt(entry).cell_type() ==
+               PropertyCellType::kDeleted);
+    DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
+    cell = handle(PropertyCell::cast(dictionary->ValueAt(entry)));
+    DCHECK(cell->value()->IsTheHole());
     return cell;
-  } else {
-    Object* value = global->property_dictionary()->ValueAt(entry);
-    DCHECK(value->IsPropertyCell());
-    return handle(PropertyCell::cast(value));
   }
+  Isolate* isolate = global->GetIsolate();
+  cell = isolate->factory()->NewPropertyCell();
+  PropertyDetails details(NONE, DATA, 0, PropertyCellType::kUninitialized);
+  dictionary = NameDictionary::Add(dictionary, name, cell, details);
+  global->set_properties(*dictionary);
+  return cell;
 }
 
 
@@ -15908,8 +15715,7 @@ Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
     int enum_index = PropertyDetails::kInitialIndex + i;
 
     PropertyDetails details = dictionary->DetailsAt(index);
-    PropertyDetails new_details =
-        PropertyDetails(details.attributes(), details.type(), enum_index);
+    PropertyDetails new_details = details.set_index(enum_index);
     dictionary->DetailsAtPut(index, new_details);
   }
 
@@ -15962,7 +15768,7 @@ Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
 #ifdef DEBUG
   USE(Shape::AsHandle(dictionary->GetIsolate(), key));
 #endif
-  PropertyDetails details(NONE, DATA, 0);
+  PropertyDetails details = PropertyDetails::Empty();
 
   AddEntry(dictionary, key, value, details, dictionary->Hash(key));
   return dictionary;
@@ -15998,13 +15804,11 @@ void Dictionary<Derived, Shape, Key>::AddEntry(
 
   uint32_t entry = dictionary->FindInsertionEntry(hash);
   // Insert element at empty or deleted entry
-  if (!details.IsDeleted() &&
-      details.dictionary_index() == 0 &&
-      Shape::kIsEnumerable) {
+  if (details.dictionary_index() == 0 && Shape::kIsEnumerable) {
     // Assign an enumeration index to the property and update
     // SetNextEnumerationIndex.
     int index = dictionary->NextEnumerationIndex();
-    details = PropertyDetails(details.attributes(), details.type(), index);
+    details = details.set_index(index);
     dictionary->SetNextEnumerationIndex(index + 1);
   }
   dictionary->SetEntry(entry, k, value, details);
@@ -16050,7 +15854,7 @@ Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
     uint32_t key,
     Handle<Object> value) {
   SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
-  return Add(dictionary, key, value, PropertyDetails(NONE, DATA, 0));
+  return Add(dictionary, key, value, PropertyDetails::Empty());
 }
 
 
@@ -16081,9 +15885,7 @@ Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
     return AddNumberEntry(dictionary, key, value, details);
   }
   // Preserve enumeration index.
-  details = PropertyDetails(details.attributes(),
-                            details.type(),
-                            dictionary->DetailsAt(entry).dictionary_index());
+  details = details.set_index(dictionary->DetailsAt(entry).dictionary_index());
   Handle<Object> object_key =
       SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
   dictionary->SetEntry(entry, object_key, value, details);
@@ -16104,8 +15906,22 @@ Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
 }
 
 
+template <DictionaryEntryType type, typename D>
+static inline bool IsDeleted(D d, int i) {
+  switch (type) {
+    case DictionaryEntryType::kObjects:
+      return false;
+    case DictionaryEntryType::kCells:
+      DCHECK(d->ValueAt(i)->IsPropertyCell());
+      return PropertyCell::cast(d->ValueAt(i))->value()->IsTheHole();
+  }
+  UNREACHABLE();
+  return false;
+}
 
-template<typename Derived, typename Shape, typename Key>
+
+template <typename Derived, typename Shape, typename Key>
+template <DictionaryEntryType type>
 int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
     PropertyAttributes filter) {
   int capacity = DerivedHashTable::Capacity();
@@ -16113,8 +15929,8 @@ int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
   for (int i = 0; i < capacity; i++) {
     Object* k = DerivedHashTable::KeyAt(i);
     if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
+      if (IsDeleted<type>(this, i)) continue;
       PropertyDetails details = DetailsAt(i);
-      if (details.IsDeleted()) continue;
       PropertyAttributes attr = details.attributes();
       if ((attr & filter) == 0) result++;
     }
@@ -16123,21 +15939,15 @@ int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
 }
 
 
-template<typename Derived, typename Shape, typename Key>
-int Dictionary<Derived, Shape, Key>::NumberOfEnumElements() {
-  return NumberOfElementsFilterAttributes(
-      static_cast<PropertyAttributes>(DONT_ENUM | SYMBOLIC));
-}
-
-
 template <typename Derived, typename Shape, typename Key>
+template <DictionaryEntryType type>
 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)) {
+      if (IsDeleted<type>(this, i)) continue;
       PropertyDetails details = DetailsAt(i);
-      if (details.IsDeleted()) continue;
       if (details.type() == ACCESSOR_CONSTANT) return true;
       PropertyAttributes attr = details.attributes();
       if (attr & (READ_ONLY | DONT_DELETE | DONT_ENUM)) return true;
@@ -16148,17 +15958,18 @@ bool Dictionary<Derived, Shape, Key>::HasComplexElements() {
 
 
 template <typename Derived, typename Shape, typename Key>
+template <DictionaryEntryType type>
 void Dictionary<Derived, Shape, Key>::CopyKeysTo(
     FixedArray* storage, PropertyAttributes filter,
     typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
-  DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
+  DCHECK(storage->length() >= NumberOfElementsFilterAttributes<type>(filter));
   int capacity = DerivedHashTable::Capacity();
   int index = 0;
   for (int i = 0; i < capacity; i++) {
      Object* k = DerivedHashTable::KeyAt(i);
      if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
+       if (IsDeleted<type>(this, i)) continue;
        PropertyDetails details = DetailsAt(i);
-       if (details.IsDeleted()) continue;
        PropertyAttributes attr = details.attributes();
        if ((attr & filter) == 0) storage->set(index++, k);
      }
@@ -16181,6 +15992,7 @@ struct EnumIndexComparator {
 };
 
 
+template <DictionaryEntryType type>
 void NameDictionary::CopyEnumKeysTo(FixedArray* storage) {
   int length = storage->length();
   int capacity = Capacity();
@@ -16189,7 +16001,7 @@ void NameDictionary::CopyEnumKeysTo(FixedArray* storage) {
      Object* k = KeyAt(i);
      if (IsKey(k) && !k->IsSymbol()) {
        PropertyDetails details = DetailsAt(i);
-       if (details.IsDeleted() || details.IsDontEnum()) continue;
+       if (details.IsDontEnum() || IsDeleted<type>(this, i)) continue;
        storage->set(properties, Smi::FromInt(i));
        properties++;
        if (properties == length) break;
@@ -16206,19 +16018,18 @@ void NameDictionary::CopyEnumKeysTo(FixedArray* storage) {
 }
 
 
-template<typename Derived, typename Shape, typename Key>
+template <typename Derived, typename Shape, typename Key>
+template <DictionaryEntryType type>
 void Dictionary<Derived, Shape, Key>::CopyKeysTo(
-    FixedArray* storage,
-    int index,
-    PropertyAttributes filter,
+    FixedArray* storage, int index, PropertyAttributes filter,
     typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
-  DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
+  DCHECK(storage->length() >= NumberOfElementsFilterAttributes<type>(filter));
   int capacity = DerivedHashTable::Capacity();
   for (int i = 0; i < capacity; i++) {
     Object* k = DerivedHashTable::KeyAt(i);
     if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
+      if (IsDeleted<type>(this, i)) continue;
       PropertyDetails details = DetailsAt(i);
-      if (details.IsDeleted()) continue;
       PropertyAttributes attr = details.attributes();
       if ((attr & filter) == 0) storage->set(index++, k);
     }
@@ -16238,6 +16049,7 @@ Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
     Object* k =  DerivedHashTable::KeyAt(i);
     if (Dictionary::IsKey(k)) {
       Object* e = ValueAt(i);
+      // TODO(dcarney): this should be templatized.
       if (e->IsPropertyCell()) {
         e = PropertyCell::cast(e)->value();
       }
@@ -16863,12 +16675,14 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
 
 
 // Get the break point objects for a code position.
-Object* DebugInfo::GetBreakPointObjects(int code_position) {
+Handle<Object> DebugInfo::GetBreakPointObjects(int code_position) {
   Object* break_point_info = GetBreakPointInfo(code_position);
   if (break_point_info->IsUndefined()) {
-    return GetHeap()->undefined_value();
+    return GetIsolate()->factory()->undefined_value();
   }
-  return BreakPointInfo::cast(break_point_info)->break_point_objects();
+  return Handle<Object>(
+      BreakPointInfo::cast(break_point_info)->break_point_objects(),
+      GetIsolate());
 }
 
 
@@ -16887,22 +16701,22 @@ int DebugInfo::GetBreakPointCount() {
 }
 
 
-Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
-                                      Handle<Object> break_point_object) {
-  Heap* heap = debug_info->GetHeap();
-  if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
-  for (int i = 0; i < debug_info->break_points()->length(); i++) {
-    if (!debug_info->break_points()->get(i)->IsUndefined()) {
-      Handle<BreakPointInfo> break_point_info =
-          Handle<BreakPointInfo>(BreakPointInfo::cast(
-              debug_info->break_points()->get(i)));
-      if (BreakPointInfo::HasBreakPointObject(break_point_info,
-                                              break_point_object)) {
-        return *break_point_info;
+Handle<Object> DebugInfo::FindBreakPointInfo(
+    Handle<DebugInfo> debug_info, Handle<Object> break_point_object) {
+  Isolate* isolate = debug_info->GetIsolate();
+  if (!debug_info->break_points()->IsUndefined()) {
+    for (int i = 0; i < debug_info->break_points()->length(); i++) {
+      if (!debug_info->break_points()->get(i)->IsUndefined()) {
+        Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
+            BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
+        if (BreakPointInfo::HasBreakPointObject(break_point_info,
+                                                break_point_object)) {
+          return break_point_info;
+        }
       }
     }
   }
-  return heap->undefined_value();
+  return isolate->factory()->undefined_value();
 }
 
 
@@ -17223,8 +17037,15 @@ Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
           fixed_typed_array->length(), typed_array->type(),
           static_cast<uint8_t*>(buffer->backing_store()));
 
-  buffer->set_weak_first_view(*typed_array);
-  DCHECK(typed_array->weak_next() == isolate->heap()->undefined_value());
+  Heap* heap = isolate->heap();
+  if (heap->InNewSpace(*typed_array)) {
+    DCHECK(typed_array->weak_next() == isolate->heap()->undefined_value());
+    typed_array->set_weak_next(heap->new_array_buffer_views_list());
+    heap->set_new_array_buffer_views_list(*typed_array);
+  } else {
+    buffer->set_weak_first_view(*typed_array);
+    DCHECK(typed_array->weak_next() == isolate->heap()->undefined_value());
+  }
   typed_array->set_buffer(*buffer);
   JSObject::SetMapAndElements(typed_array, new_map, new_elements);
 
@@ -17243,54 +17064,109 @@ Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
 }
 
 
-HeapType* PropertyCell::type() {
-  return static_cast<HeapType*>(type_raw());
+Handle<PropertyCell> PropertyCell::InvalidateEntry(
+    Handle<NameDictionary> dictionary, int entry) {
+  Isolate* isolate = dictionary->GetIsolate();
+  // Swap with a copy.
+  DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
+  Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
+  auto new_cell = isolate->factory()->NewPropertyCell();
+  new_cell->set_value(cell->value());
+  dictionary->ValueAtPut(entry, *new_cell);
+  bool is_the_hole = cell->value()->IsTheHole();
+  // Cell is officially mutable henceforth.
+  auto details = dictionary->DetailsAt(entry);
+  details = details.set_cell_type(is_the_hole ? PropertyCellType::kDeleted
+                                              : PropertyCellType::kMutable);
+  dictionary->DetailsAtPut(entry, details);
+  // Old cell is ready for invalidation.
+  if (is_the_hole) {
+    cell->set_value(isolate->heap()->undefined_value());
+  } else {
+    cell->set_value(isolate->heap()->the_hole_value());
+  }
+  cell->dependent_code()->DeoptimizeDependentCodeGroup(
+      isolate, DependentCode::kPropertyCellChangedGroup);
+  return new_cell;
 }
 
 
-void PropertyCell::set_type(HeapType* type, WriteBarrierMode ignored) {
-  DCHECK(IsPropertyCell());
-  set_type_raw(type, ignored);
+PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
+                                           Handle<Object> value,
+                                           PropertyDetails details) {
+  PropertyCellType type = details.cell_type();
+  DCHECK(!value->IsTheHole());
+  DCHECK_IMPLIES(cell->value()->IsTheHole(),
+                 type == PropertyCellType::kUninitialized ||
+                     type == PropertyCellType::kDeleted);
+  switch (type) {
+    // Only allow a cell to transition once into constant state.
+    case PropertyCellType::kUninitialized:
+      if (value->IsUndefined()) return PropertyCellType::kUndefined;
+      return PropertyCellType::kConstant;
+    case PropertyCellType::kUndefined:
+      return PropertyCellType::kConstant;
+    case PropertyCellType::kConstant:
+      // No transition.
+      if (*value == cell->value()) return PropertyCellType::kConstant;
+    // Fall through.
+    case PropertyCellType::kMutable:
+      return PropertyCellType::kMutable;
+  }
+  UNREACHABLE();
+  return PropertyCellType::kMutable;
 }
 
 
-Handle<HeapType> PropertyCell::UpdatedType(Handle<PropertyCell> cell,
-                                           Handle<Object> value) {
-  Isolate* isolate = cell->GetIsolate();
-  Handle<HeapType> old_type(cell->type(), isolate);
-  Handle<HeapType> new_type = HeapType::Constant(value, isolate);
-
-  if (new_type->Is(old_type)) return old_type;
-
-  cell->dependent_code()->DeoptimizeDependentCodeGroup(
-      isolate, DependentCode::kPropertyCellChangedGroup);
-
-  if (old_type->Is(HeapType::None()) || old_type->Is(HeapType::Undefined())) {
-    return new_type;
+Handle<Object> PropertyCell::UpdateCell(Handle<NameDictionary> dictionary,
+                                        int entry, Handle<Object> value,
+                                        PropertyDetails details) {
+  DCHECK(!value->IsTheHole());
+  DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
+  Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
+  const PropertyDetails original_details = dictionary->DetailsAt(entry);
+  // Data accesses could be cached in ics or optimized code.
+  bool invalidate =
+      original_details.kind() == kData && details.kind() == kAccessor;
+  int index = original_details.dictionary_index();
+  auto old_type = original_details.cell_type();
+  // Preserve the enumeration index unless the property was deleted or never
+  // initialized.
+  if (cell->value()->IsTheHole()) {
+    index = dictionary->NextEnumerationIndex();
+    dictionary->SetNextEnumerationIndex(index + 1);
+    // Negative lookup cells must be invalidated.
+    invalidate = true;
   }
+  DCHECK(index > 0);
+  details = details.set_index(index);
 
-  return HeapType::Any(isolate);
-}
-
-
-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())) &&
+  if ((old_type == PropertyCellType::kUninitialized ||
+       old_type == PropertyCellType::kUndefined) &&
       value->IsString()) {
     auto string = Handle<String>::cast(value);
-    if (string->length() <= kMaxLengthForInternalization &&
-        !string->map()->is_undetectable()) {
+    if (string->length() <= kMaxLengthForInternalization) {
       value = cell->GetIsolate()->factory()->InternalizeString(string);
     }
   }
+
+  auto new_type = UpdatedType(cell, value, original_details);
+  if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry);
+
+  // Install new property details and cell value.
+  details = details.set_cell_type(new_type);
+  dictionary->DetailsAtPut(entry, details);
   cell->set_value(*value);
-  if (!HeapType::Any()->Is(cell->type())) {
-    Handle<HeapType> new_type = UpdatedType(cell, value);
-    cell->set_type(*new_type);
+
+  // Deopt when transitioning from a constant type.
+  if (!invalidate && old_type == PropertyCellType::kConstant &&
+      new_type != PropertyCellType::kConstant) {
+    auto isolate = dictionary->GetIsolate();
+    cell->dependent_code()->DeoptimizeDependentCodeGroup(
+        isolate, DependentCode::kPropertyCellChangedGroup);
   }
   return value;
 }
index d4af4a6..5faf62b 100644 (file)
 //       - Symbol
 //     - HeapNumber
 //     - Cell
-//       - PropertyCell
+//     - PropertyCell
 //     - Code
 //     - Map
 //     - Oddball
@@ -662,7 +662,6 @@ enum InstanceType {
   CODE_TYPE,
   ODDBALL_TYPE,
   CELL_TYPE,
-  PROPERTY_CELL_TYPE,
 
   // "Data", objects that cannot contain non-map-word pointers to heap
   // objects.
@@ -718,6 +717,7 @@ enum InstanceType {
   CONSTANT_POOL_ARRAY_TYPE,
   SHARED_FUNCTION_INFO_TYPE,
   WEAK_CELL_TYPE,
+  PROPERTY_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
@@ -938,9 +938,11 @@ template <class C> inline bool Is(Object* obj);
   V(DeoptimizationInputData)       \
   V(DeoptimizationOutputData)      \
   V(DependentCode)                 \
+  V(HandlerTable)                  \
   V(FixedArray)                    \
   V(FixedDoubleArray)              \
   V(WeakFixedArray)                \
+  V(ArrayList)                     \
   V(ConstantPoolArray)             \
   V(Context)                       \
   V(ScriptContextTable)            \
@@ -2080,7 +2082,7 @@ class JSObject: public JSReceiver {
   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);
+  inline void WriteToField(int descriptor, Object* value);
 
   // Access to in object properties.
   inline int GetInObjectPropertyOffset(int index);
@@ -2627,6 +2629,34 @@ class WeakFixedArray : public FixedArray {
 };
 
 
+// Generic array grows dynamically with O(1) amortized insertion.
+class ArrayList : public FixedArray {
+ public:
+  enum AddMode {
+    kNone,
+    // Use this if GC can delete elements from the array.
+    kReloadLengthAfterAllocation,
+  };
+  static Handle<ArrayList> Add(Handle<ArrayList> array, Handle<Object> obj,
+                               AddMode mode = kNone);
+  static Handle<ArrayList> Add(Handle<ArrayList> array, Handle<Object> obj1,
+                               Handle<Object> obj2, AddMode = kNone);
+  inline int Length();
+  inline void SetLength(int length);
+  inline Object* Get(int index);
+  inline Object** Slot(int index);
+  inline void Set(int index, Object* obj);
+  inline void Clear(int index, Object* undefined);
+  DECLARE_CAST(ArrayList)
+
+ private:
+  static Handle<ArrayList> EnsureSpace(Handle<ArrayList> array, int length);
+  static const int kLengthIndex = 0;
+  static const int kFirstIndex = 1;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ArrayList);
+};
+
+
 // ConstantPoolArray describes a fixed-sized array containing constant pool
 // entries.
 //
@@ -3504,6 +3534,9 @@ class StringTable: public HashTable<StringTable,
 };
 
 
+enum class DictionaryEntryType { kObjects, kCells };
+
+
 template <typename Derived, typename Shape, typename Key>
 class Dictionary: public HashTable<Derived, Shape, Key> {
  protected:
@@ -3532,9 +3565,6 @@ class Dictionary: public HashTable<Derived, Shape, Key> {
     this->set(DerivedHashTable::EntryToIndex(entry) + 2, value.AsSmi());
   }
 
-  // Sorting support
-  void CopyValuesTo(FixedArray* elements);
-
   // Delete a property from the dictionary.
   static Handle<Object> DeleteProperty(Handle<Derived> dictionary, int entry);
 
@@ -3545,27 +3575,82 @@ class Dictionary: public HashTable<Derived, Shape, Key> {
     return DerivedHashTable::Shrink(dictionary, key);
   }
 
+  // Sorting support
+  // TODO(dcarney): templatize or move to SeededNumberDictionary
+  void CopyValuesTo(FixedArray* elements);
+
   // Returns the number of elements in the dictionary filtering out properties
   // with the specified attributes.
+  template <DictionaryEntryType type>
   int NumberOfElementsFilterAttributes(PropertyAttributes filter);
+  int NumberOfElementsFilterAttributes(Object* holder,
+                                       PropertyAttributes filter) {
+    if (holder->IsGlobalObject()) {
+      return NumberOfElementsFilterAttributes<DictionaryEntryType::kCells>(
+          filter);
+    } else {
+      return NumberOfElementsFilterAttributes<DictionaryEntryType::kObjects>(
+          filter);
+    }
+  }
 
   // Returns the number of enumerable elements in the dictionary.
-  int NumberOfEnumElements();
+  template <DictionaryEntryType type>
+  int NumberOfEnumElements() {
+    return NumberOfElementsFilterAttributes<type>(
+        static_cast<PropertyAttributes>(DONT_ENUM | SYMBOLIC));
+  }
+  int NumberOfEnumElements(Object* holder) {
+    if (holder->IsGlobalObject()) {
+      return NumberOfEnumElements<DictionaryEntryType::kCells>();
+    } else {
+      return NumberOfEnumElements<DictionaryEntryType::kObjects>();
+    }
+  }
 
   // Returns true if the dictionary contains any elements that are non-writable,
   // non-configurable, non-enumerable, or have getters/setters.
+  template <DictionaryEntryType type>
   bool HasComplexElements();
+  bool HasComplexElements(Object* holder) {
+    if (holder->IsGlobalObject()) {
+      return HasComplexElements<DictionaryEntryType::kCells>();
+    } else {
+      return HasComplexElements<DictionaryEntryType::kObjects>();
+    }
+  }
 
   enum SortMode { UNSORTED, SORTED };
+
   // Copies keys to preallocated fixed array.
-  void CopyKeysTo(FixedArray* storage,
-                  PropertyAttributes filter,
+  template <DictionaryEntryType type>
+  void CopyKeysTo(FixedArray* storage, PropertyAttributes filter,
                   SortMode sort_mode);
+  void CopyKeysTo(Object* holder, FixedArray* storage,
+                  PropertyAttributes filter, SortMode sort_mode) {
+    if (holder->IsGlobalObject()) {
+      return CopyKeysTo<DictionaryEntryType::kCells>(storage, filter,
+                                                     sort_mode);
+    } else {
+      return CopyKeysTo<DictionaryEntryType::kObjects>(storage, filter,
+                                                       sort_mode);
+    }
+  }
+
   // Fill in details for properties into storage.
-  void CopyKeysTo(FixedArray* storage,
-                  int index,
-                  PropertyAttributes filter,
+  template <DictionaryEntryType type>
+  void CopyKeysTo(FixedArray* storage, int index, PropertyAttributes filter,
                   SortMode sort_mode);
+  void CopyKeysTo(Object* holder, FixedArray* storage, int index,
+                  PropertyAttributes filter, SortMode sort_mode) {
+    if (holder->IsGlobalObject()) {
+      return CopyKeysTo<DictionaryEntryType::kCells>(storage, index, filter,
+                                                     sort_mode);
+    } else {
+      return CopyKeysTo<DictionaryEntryType::kObjects>(storage, index, filter,
+                                                       sort_mode);
+    }
+  }
 
   // Accessors for next enumeration index.
   void SetNextEnumerationIndex(int index) {
@@ -3658,7 +3743,16 @@ class NameDictionary: public Dictionary<NameDictionary,
   DECLARE_CAST(NameDictionary)
 
   // Copies enumerable keys to preallocated fixed array.
+  template <DictionaryEntryType type>
   void CopyEnumKeysTo(FixedArray* storage);
+  void CopyEnumKeysTo(Object* holder, FixedArray* storage) {
+    if (holder->IsGlobalObject()) {
+      return CopyEnumKeysTo<DictionaryEntryType::kCells>(storage);
+    } else {
+      return CopyEnumKeysTo<DictionaryEntryType::kObjects>(storage);
+    }
+  }
+
   inline static Handle<FixedArray> DoGenerateNewEnumerationIndices(
       Handle<NameDictionary> dictionary);
 
@@ -4219,6 +4313,10 @@ class ScopeInfo : public FixedArray {
   // exposed to the user in a debugger.
   bool LocalIsSynthetic(int var);
 
+  String* StrongModeFreeVariableName(int var);
+  int StrongModeFreeVariableStartPosition(int var);
+  int StrongModeFreeVariableEndPosition(int var);
+
   // Lookup support for serialized scope info. Returns the
   // the stack slot index for a given slot name if the slot is
   // present; otherwise returns a value < 0. The name must be an internalized
@@ -4245,6 +4343,8 @@ class ScopeInfo : public FixedArray {
   // must be an internalized string.
   int FunctionContextSlotIndex(String* name, VariableMode* mode);
 
+  bool block_scope_is_class_scope();
+  FunctionKind function_kind();
 
   // Copies all the context locals into an object used to materialize a scope.
   static bool CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
@@ -4269,11 +4369,12 @@ class ScopeInfo : public FixedArray {
   // 3. The number of non-parameter variables allocated on the stack.
   // 4. The number of non-parameter and parameter variables allocated in the
   //    context.
-#define FOR_EACH_NUMERIC_FIELD(V)          \
-  V(Flags)                                 \
-  V(ParameterCount)                        \
-  V(StackLocalCount)                       \
-  V(ContextLocalCount)
+#define FOR_EACH_NUMERIC_FIELD(V) \
+  V(Flags)                        \
+  V(ParameterCount)               \
+  V(StackLocalCount)              \
+  V(ContextLocalCount)            \
+  V(StrongModeFreeVariableCount)
 
 #define FIELD_ACCESSORS(name)                            \
   void Set##name(int value) {                            \
@@ -4320,7 +4421,12 @@ class ScopeInfo : public FixedArray {
   //    the context locals in ContextLocalNameEntries. One slot is used per
   //    context local, so in total this part occupies ContextLocalCount()
   //    slots in the array.
-  // 5. FunctionNameEntryIndex:
+  // 5. StrongModeFreeVariableNameEntries:
+  //    Stores the names of strong mode free variables.
+  // 6. StrongModeFreeVariablePositionEntries:
+  //    Stores the locations (start and end position) of strong mode free
+  //    variables.
+  // 7. FunctionNameEntryIndex:
   //    If the scope belongs to a named function expression this part contains
   //    information about the function variable. It always occupies two array
   //    slots:  a. The name of the function variable.
@@ -4329,6 +4435,8 @@ class ScopeInfo : public FixedArray {
   int StackLocalEntriesIndex();
   int ContextLocalNameEntriesIndex();
   int ContextLocalInfoEntriesIndex();
+  int StrongModeFreeVariableNameEntriesIndex();
+  int StrongModeFreeVariablePositionEntriesIndex();
   int FunctionNameEntryIndex();
 
   // Location of the function variable for named function expressions.
@@ -4350,6 +4458,10 @@ class ScopeInfo : public FixedArray {
   class AsmFunctionField : public BitField<bool, 13, 1> {};
   class IsSimpleParameterListField
       : public BitField<bool, AsmFunctionField::kNext, 1> {};
+  class BlockScopeIsClassScopeField
+      : public BitField<bool, IsSimpleParameterListField::kNext, 1> {};
+  class FunctionKindField
+      : public BitField<FunctionKind, BlockScopeIsClassScopeField::kNext, 8> {};
 
   // BitFields representing the encoded information for context locals in the
   // ContextLocalInfoEntries part.
@@ -4768,6 +4880,7 @@ class FixedTypedArrayBase: public FixedArrayBase {
 
   inline int size();
 
+  static inline int TypedArraySize(InstanceType type, int length);
   inline int TypedArraySize(InstanceType type);
 
   // Use with care: returns raw pointer into heap.
@@ -4776,6 +4889,8 @@ class FixedTypedArrayBase: public FixedArrayBase {
   inline int DataSize();
 
  private:
+  static inline int ElementSize(InstanceType type);
+
   inline int DataSize(InstanceType type);
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(FixedTypedArrayBase);
@@ -4969,6 +5084,71 @@ class DeoptimizationOutputData: public FixedArray {
 };
 
 
+// HandlerTable is a fixed array containing entries for exception handlers in
+// the code object it is associated with. The tables comes in two flavors:
+// 1) Based on ranges: Used for unoptimized code. Contains one entry per
+//    exception handler and a range representing the try-block covered by that
+//    handler. Layout looks as follows:
+//      [ range-start , range-end , handler-offset , stack-depth ]
+// 2) Based on return addresses: Used for turbofanned code. Contains one entry
+//    per call-site that could throw an exception. Layout looks as follows:
+//      [ return-address-offset , handler-offset ]
+class HandlerTable : public FixedArray {
+ public:
+  // Accessors for handler table based on ranges.
+  void SetRangeStart(int index, int value) {
+    set(index * kRangeEntrySize + kRangeStartIndex, Smi::FromInt(value));
+  }
+  void SetRangeEnd(int index, int value) {
+    set(index * kRangeEntrySize + kRangeEndIndex, Smi::FromInt(value));
+  }
+  void SetRangeHandler(int index, int value) {
+    set(index * kRangeEntrySize + kRangeHandlerIndex, Smi::FromInt(value));
+  }
+  void SetRangeDepth(int index, int value) {
+    set(index * kRangeEntrySize + kRangeDepthIndex, Smi::FromInt(value));
+  }
+
+  // Accessors for handler table based on return addresses.
+  void SetReturnOffset(int index, int value) {
+    set(index * kReturnEntrySize + kReturnOffsetIndex, Smi::FromInt(value));
+  }
+  void SetReturnHandler(int index, int value) {
+    set(index * kReturnEntrySize + kReturnHandlerIndex, Smi::FromInt(value));
+  }
+
+  // Lookup handler in a table based on ranges.
+  int LookupRange(int pc_offset, int* stack_depth);
+
+  // Lookup handler in a table based on return addresses.
+  int LookupReturn(int pc_offset);
+
+  // Returns the required length of the underlying fixed array.
+  static int LengthForRange(int entries) { return entries * kRangeEntrySize; }
+  static int LengthForReturn(int entries) { return entries * kReturnEntrySize; }
+
+  DECLARE_CAST(HandlerTable)
+
+#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
+  void HandlerTableRangePrint(std::ostream& os);   // NOLINT
+  void HandlerTableReturnPrint(std::ostream& os);  // NOLINT
+#endif
+
+ private:
+  // Layout description for handler table based on ranges.
+  static const int kRangeStartIndex = 0;
+  static const int kRangeEndIndex = 1;
+  static const int kRangeHandlerIndex = 2;
+  static const int kRangeDepthIndex = 3;
+  static const int kRangeEntrySize = 4;
+
+  // Layout description for handler table based on return addresses.
+  static const int kReturnOffsetIndex = 0;
+  static const int kReturnHandlerIndex = 1;
+  static const int kReturnEntrySize = 2;
+};
+
+
 // Forward declaration.
 class Cell;
 class PropertyCell;
@@ -5388,7 +5568,7 @@ class Code: public HeapObject {
     return GetCodeAgeStub(isolate, kNotExecutedCodeAge, NO_MARKING_PARITY);
   }
 
-  void PrintDeoptLocation(FILE* out, int bailout_id);
+  void PrintDeoptLocation(FILE* out, Address pc);
   bool CanDeoptAt(Address pc);
 
 #ifdef VERIFY_HEAP
@@ -5869,25 +6049,14 @@ class Map: public HeapObject {
   // map with DICTIONARY_ELEMENTS was found in the prototype chain.
   bool DictionaryElementsInPrototypeChainOnly();
 
-  inline bool HasTransitionArray() const;
-  inline bool HasElementsTransition();
-  inline Map* elements_transition_map();
+  inline Map* ElementsTransitionMap();
 
-  inline Map* GetTransition(int transition_index);
-  inline int SearchSpecialTransition(Symbol* name);
-  inline int SearchTransition(PropertyKind kind, Name* name,
-                              PropertyAttributes attributes);
   inline FixedArrayBase* GetInitialElements();
 
-  DECL_ACCESSORS(transitions, TransitionArray)
-
-  static inline Handle<String> ExpectedTransitionKey(Handle<Map> map);
-  static inline Handle<Map> ExpectedTransitionTarget(Handle<Map> map);
-
-  // Try to follow an existing transition to a field with attributes NONE. The
-  // return value indicates whether the transition was successful.
-  static inline Handle<Map> FindTransitionToField(Handle<Map> map,
-                                                  Handle<Name> key);
+  // [raw_transitions]: Provides access to the transitions storage field.
+  // Don't call set_raw_transitions() directly to overwrite transitions, use
+  // the TransitionArray::ReplaceTransitions() wrapper instead!
+  DECL_ACCESSORS(raw_transitions, Object)
 
   Map* FindRootMap();
   Map* FindFieldOwner(int descriptor);
@@ -5954,7 +6123,18 @@ class Map: public HeapObject {
   bool CanUseOptimizationsBasedOnPrototypeRegistry();
 
   // [constructor]: points back to the function responsible for this map.
-  DECL_ACCESSORS(constructor, Object)
+  // The field overlaps with the back pointer. All maps in a transition tree
+  // have the same constructor, so maps with back pointers can walk the
+  // back pointer chain until they find the map holding their constructor.
+  DECL_ACCESSORS(constructor_or_backpointer, Object)
+  inline Object* GetConstructor() const;
+  inline void SetConstructor(Object* constructor,
+                             WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+  // [back pointer]: points back to the parent map from which a transition
+  // leads to this map. The field overlaps with the constructor (see above).
+  inline Object* GetBackPointer();
+  inline void SetBackPointer(Object* value,
+                             WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
 
   // [instance descriptors]: describes the object.
   DECL_ACCESSORS(instance_descriptors, DescriptorArray)
@@ -5981,47 +6161,11 @@ class Map: public HeapObject {
   // [dependent code]: list of optimized codes that weakly embed this map.
   DECL_ACCESSORS(dependent_code, DependentCode)
 
-  // [back pointer]: points back to the parent map from which a transition
-  // leads to this map. The field overlaps with prototype transitions and the
-  // back pointer will be moved into the prototype transitions array if
-  // required.
-  inline Object* GetBackPointer();
-  inline void SetBackPointer(Object* value,
-                             WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
-  inline void init_back_pointer(Object* undefined);
-
-  // [prototype transitions]: cache of prototype transitions.
-  // Prototype transition is a transition that happens
-  // when we change object's prototype to a new one.
-  // Cache format:
-  //    0: finger - index of the first free cell in the cache
-  //    1 + i: target map
-  inline FixedArray* GetPrototypeTransitions();
-  inline bool HasPrototypeTransitions();
-
-  static const int kProtoTransitionNumberOfEntriesOffset = 0;
-  static const int kProtoTransitionHeaderSize = 1;
-
-  inline int NumberOfProtoTransitions() {
-    FixedArray* cache = GetPrototypeTransitions();
-    if (cache->length() == 0) return 0;
-    return
-        Smi::cast(cache->get(kProtoTransitionNumberOfEntriesOffset))->value();
-  }
-
-  inline void SetNumberOfProtoTransitions(int value) {
-    FixedArray* cache = GetPrototypeTransitions();
-    DCHECK(cache->length() != 0);
-    cache->set(kProtoTransitionNumberOfEntriesOffset, Smi::FromInt(value));
-  }
+  // [weak cell cache]: cache that stores a weak cell pointing to this map.
+  DECL_ACCESSORS(weak_cell_cache, Object)
 
   inline PropertyDetails GetLastDescriptorDetails();
 
-  // The size of transition arrays are limited so they do not end up in large
-  // object space. Otherwise ClearNonLiveTransitions would leak memory while
-  // applying in-place right trimming.
-  inline bool CanHaveMoreTransitions();
-
   int LastAdded() {
     int number_of_own_descriptors = NumberOfOwnDescriptors();
     DCHECK(number_of_own_descriptors > 0);
@@ -6068,12 +6212,9 @@ class Map: public HeapObject {
   // Returns a non-deprecated version of the input. If the input was not
   // deprecated, it is directly returned. Otherwise, the non-deprecated version
   // is found by re-transitioning from the root of the transition tree using the
-  // descriptor array of the map. Returns NULL if no updated map is found.
-  // This method also applies any pending migrations along the prototype chain.
+  // descriptor array of the map. Returns MaybeHandle<Map>() if no updated map
+  // is found.
   static MaybeHandle<Map> TryUpdate(Handle<Map> map) WARN_UNUSED_RESULT;
-  // Same as above, but does not touch the prototype chain.
-  static MaybeHandle<Map> TryUpdateInternal(Handle<Map> map)
-      WARN_UNUSED_RESULT;
 
   // Returns a non-deprecated version of the input. This method may deprecate
   // existing maps along the way if encodings conflict. Not for use while
@@ -6192,11 +6333,6 @@ class Map: public HeapObject {
   // Removes a code object from the code cache at the given index.
   void RemoveFromCodeCache(Name* name, Code* code, int index);
 
-  // Set all map transitions from this map to dead maps to null.  Also clear
-  // back pointers in transition targets so that we do not process this map
-  // again while following back pointers.
-  void ClearNonLiveTransitions(Heap* heap);
-
   // Computes a hash value for this map, to be used in HashTables and such.
   int Hash();
 
@@ -6262,18 +6398,6 @@ class Map: public HeapObject {
   inline int visitor_id();
   inline void set_visitor_id(int visitor_id);
 
-  typedef void (*TraverseCallback)(Map* map, void* data);
-
-  void TraverseTransitionTree(TraverseCallback callback, void* data);
-
-  // When you set the prototype of an object using the __proto__ accessor you
-  // need a new map for the object (the prototype is stored in the map).  In
-  // order not to multiply maps unnecessarily we store these as transitions in
-  // 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 they transition to.
-  static const int kMaxCachedPrototypeTransitions = 256;
   static Handle<Map> TransitionToPrototype(Handle<Map> map,
                                            Handle<Object> prototype,
                                            PrototypeOptimizationMode mode);
@@ -6285,15 +6409,15 @@ class Map: public HeapObject {
   static const int kInstanceAttributesOffset = kInstanceSizesOffset + kIntSize;
   static const int kBitField3Offset = kInstanceAttributesOffset + kIntSize;
   static const int kPrototypeOffset = kBitField3Offset + kPointerSize;
-  static const int kConstructorOffset = kPrototypeOffset + kPointerSize;
-  // Storage for the transition array is overloaded to directly contain a back
-  // pointer if unused. When the map has transitions, the back pointer is
-  // transferred to the transition array and accessed through an extra
-  // indirection.
-  static const int kTransitionsOrBackPointerOffset =
-      kConstructorOffset + kPointerSize;
-  static const int kDescriptorsOffset =
-      kTransitionsOrBackPointerOffset + kPointerSize;
+  static const int kConstructorOrBackPointerOffset =
+      kPrototypeOffset + kPointerSize;
+  // When there is only one transition, it is stored directly in this field;
+  // otherwise a transition array is used.
+  // For prototype maps, this slot is used to store a pointer to the prototype
+  // object using this map.
+  static const int kTransitionsOffset =
+      kConstructorOrBackPointerOffset + kPointerSize;
+  static const int kDescriptorsOffset = kTransitionsOffset + kPointerSize;
 #if V8_DOUBLE_FIELDS_UNBOXING
   static const int kLayoutDecriptorOffset = kDescriptorsOffset + kPointerSize;
   static const int kCodeCacheOffset = kLayoutDecriptorOffset + kPointerSize;
@@ -6302,7 +6426,8 @@ class Map: public HeapObject {
   static const int kCodeCacheOffset = kDescriptorsOffset + kPointerSize;
 #endif
   static const int kDependentCodeOffset = kCodeCacheOffset + kPointerSize;
-  static const int kSize = kDependentCodeOffset + kPointerSize;
+  static const int kWeakCellCacheOffset = kDependentCodeOffset + kPointerSize;
+  static const int kSize = kWeakCellCacheOffset + kPointerSize;
 
   // Layout of pointer fields. Heap iteration code relies on them
   // being continuously allocated.
@@ -6432,15 +6557,6 @@ class Map: public HeapObject {
   static Handle<Map> TransitionElementsToSlow(Handle<Map> object,
                                               ElementsKind to_kind);
 
-  // Zaps the contents of backing data structures. Note that the
-  // heap verifier (i.e. VerifyMarkingVisitor) relies on zapping of objects
-  // holding weak references when incremental marking is used, because it also
-  // iterates over objects that are otherwise unreachable.
-  // In general we only want to call these functions in release mode when
-  // heap verification is turned on.
-  void ZapPrototypeTransitions();
-  void ZapTransitions();
-
   void DeprecateTransitionTree();
   bool DeprecateTarget(PropertyKind kind, Name* key,
                        PropertyAttributes attributes,
@@ -6449,9 +6565,12 @@ class Map: public HeapObject {
 
   Map* FindLastMatchMap(int verbatim, int length, DescriptorArray* descriptors);
 
+  // Update field type of the given descriptor to new representation and new
+  // type. The type must be prepared for storing in descriptor array:
+  // it must be either a simple type or a map wrapped in a weak cell.
   void UpdateFieldType(int descriptor_number, Handle<Name> name,
                        Representation new_representation,
-                       Handle<HeapType> new_type);
+                       Handle<Object> new_wrapped_type);
 
   void PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
                             PropertyAttributes attributes);
@@ -6466,16 +6585,6 @@ class Map: public HeapObject {
                            HeapType* old_field_type,
                            HeapType* new_field_type);
 
-  static inline void SetPrototypeTransitions(
-      Handle<Map> map,
-      Handle<FixedArray> prototype_transitions);
-
-  static Handle<Map> GetPrototypeTransition(Handle<Map> map,
-                                            Handle<Object> prototype);
-  static Handle<Map> PutPrototypeTransition(Handle<Map> map,
-                                            Handle<Object> prototype,
-                                            Handle<Map> target_map);
-
   static const int kFastPropertiesSoftLimit = 12;
   static const int kMaxFastProperties = 128;
 
@@ -7221,8 +7330,9 @@ class SharedFunctionInfo: public HeapObject {
     kIsConciseMethod,
     kIsAccessorFunction,
     kIsDefaultConstructor,
-    kIsBaseConstructor,
     kIsSubclassConstructor,
+    kIsBaseConstructor,
+    kInClassLiteral,
     kIsAsmFunction,
     kDeserialized,
     kCompilerHintsCount  // Pseudo entry
@@ -7230,7 +7340,7 @@ class SharedFunctionInfo: public HeapObject {
   // Add hints for other modes when they're added.
   STATIC_ASSERT(LANGUAGE_END == 3);
 
-  class FunctionKindBits : public BitField<FunctionKind, kIsArrow, 7> {};
+  class FunctionKindBits : public BitField<FunctionKind, kIsArrow, 8> {};
 
   class DeoptCountBits : public BitField<int, 0, 4> {};
   class OptReenableTriesBits : public BitField<int, 4, 18> {};
@@ -7321,11 +7431,6 @@ class JSGeneratorObject: public JSObject {
   // [operand_stack]: Saved operand stack.
   DECL_ACCESSORS(operand_stack, FixedArray)
 
-  // [stack_handler_index]: Index of first stack handler in operand_stack, or -1
-  // if the captured activation had no stack handler.
-  inline int stack_handler_index() const;
-  inline void set_stack_handler_index(int stack_handler_index);
-
   DECLARE_CAST(JSGeneratorObject)
 
   // Dispatched behavior.
@@ -7342,9 +7447,7 @@ class JSGeneratorObject: public JSObject {
   static const int kReceiverOffset = kContextOffset + kPointerSize;
   static const int kContinuationOffset = kReceiverOffset + kPointerSize;
   static const int kOperandStackOffset = kContinuationOffset + kPointerSize;
-  static const int kStackHandlerIndexOffset =
-      kOperandStackOffset + kPointerSize;
-  static const int kSize = kStackHandlerIndexOffset + kPointerSize;
+  static const int kSize = kOperandStackOffset + kPointerSize;
 
   // Resume mode, for use by runtime functions.
   enum ResumeMode { NEXT, THROW };
@@ -7579,12 +7682,13 @@ class JSFunction: public JSObject {
   // Returns the number of allocated literals.
   inline int NumberOfLiterals();
 
-  // Retrieve the native context from a function's literal array.
-  static Context* NativeContextFromLiterals(FixedArray* literals);
-
   // Used for flags such as --hydrogen-filter.
   bool PassesFilter(const char* raw_filter);
 
+  // The function's name if it is configured, otherwise shared function info
+  // debug name.
+  static Handle<String> GetDebugName(Handle<JSFunction> function);
+
   // Layout descriptors. The last property (from kNonWeakFieldsEndOffset to
   // kSize) is weak and has special handling during garbage collection.
   static const int kCodeEntryOffset = JSObject::kHeaderSize;
@@ -7598,10 +7702,6 @@ class JSFunction: public JSObject {
   static const int kNextFunctionLinkOffset = kNonWeakFieldsEndOffset;
   static const int kSize = kNextFunctionLinkOffset + kPointerSize;
 
-  // Layout of the literals array.
-  static const int kLiteralsPrefixSize = 1;
-  static const int kLiteralNativeContextIndex = 0;
-
   // Layout of the bound-function binding array.
   static const int kBoundFunctionIndex = 0;
   static const int kBoundThisIndex = 1;
@@ -7709,10 +7809,6 @@ class JSBuiltinsObject: public GlobalObject {
   inline Object* javascript_builtin(Builtins::JavaScript id);
   inline void set_javascript_builtin(Builtins::JavaScript id, Object* value);
 
-  // Accessors for code of the runtime routines written in JavaScript.
-  inline Code* javascript_builtin_code(Builtins::JavaScript id);
-  inline void set_javascript_builtin_code(Builtins::JavaScript id, Code* value);
-
   DECLARE_CAST(JSBuiltinsObject)
 
   // Dispatched behavior.
@@ -7724,19 +7820,13 @@ class JSBuiltinsObject: public GlobalObject {
   // (function and code object).
   static const int kJSBuiltinsCount = Builtins::id_count;
   static const int kJSBuiltinsOffset = GlobalObject::kHeaderSize;
-  static const int kJSBuiltinsCodeOffset =
-      GlobalObject::kHeaderSize + (kJSBuiltinsCount * kPointerSize);
   static const int kSize =
-      kJSBuiltinsCodeOffset + (kJSBuiltinsCount * kPointerSize);
+      GlobalObject::kHeaderSize + (kJSBuiltinsCount * kPointerSize);
 
   static int OffsetOfFunctionWithId(Builtins::JavaScript id) {
     return kJSBuiltinsOffset + id * kPointerSize;
   }
 
-  static int OffsetOfCodeWithId(Builtins::JavaScript id) {
-    return kJSBuiltinsCodeOffset + id * kPointerSize;
-  }
-
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(JSBuiltinsObject);
 };
@@ -8121,7 +8211,6 @@ class CodeCache: public Struct {
  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(
@@ -8149,8 +8238,7 @@ class CodeCache: public Struct {
   static const int kDefaultCacheOffset = HeapObject::kHeaderSize;
   static const int kNormalTypeCacheOffset =
       kDefaultCacheOffset + kPointerSize;
-  static const int kWeakCellCacheOffset = kNormalTypeCacheOffset + kPointerSize;
-  static const int kSize = kWeakCellCacheOffset + kPointerSize;
+  static const int kSize = kNormalTypeCacheOffset + kPointerSize;
 
  private:
   static void UpdateDefaultCache(
@@ -9684,14 +9772,14 @@ class Oddball: public HeapObject {
 
 class Cell: public HeapObject {
  public:
-  // [value]: value of the global property.
+  // [value]: value of the cell.
   DECL_ACCESSORS(value, Object)
 
   DECLARE_CAST(Cell)
 
   static inline Cell* FromValueAddress(Address value) {
     Object* result = FromAddress(value - kValueOffset);
-    DCHECK(result->IsCell() || result->IsPropertyCell());
+    DCHECK(result->IsCell());
     return static_cast<Cell*>(result);
   }
 
@@ -9716,46 +9804,38 @@ class Cell: public HeapObject {
 };
 
 
-class PropertyCell: public Cell {
+class PropertyCell : public HeapObject {
  public:
-  // [type]: type of the global property.
-  HeapType* type();
-  void set_type(HeapType* value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
-
+  // [value]: value of the global property.
+  DECL_ACCESSORS(value, Object)
   // [dependent_code]: dependent code that depends on the type of the global
   // property.
   DECL_ACCESSORS(dependent_code, DependentCode)
 
-  // Sets the value of the cell and updates the type field to be the union
-  // 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.
-  // 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.
-  static Handle<HeapType> UpdatedType(Handle<PropertyCell> cell,
-                                      Handle<Object> value);
+  // without actually modifying the details.
+  static PropertyCellType UpdatedType(Handle<PropertyCell> cell,
+                                      Handle<Object> value,
+                                      PropertyDetails details);
+  static Handle<Object> UpdateCell(Handle<NameDictionary> dictionary, int entry,
+                                   Handle<Object> value,
+                                   PropertyDetails details);
+
+  static Handle<PropertyCell> InvalidateEntry(Handle<NameDictionary> dictionary,
+                                              int entry);
 
   static void AddDependentCompilationInfo(Handle<PropertyCell> cell,
                                           CompilationInfo* info);
 
   DECLARE_CAST(PropertyCell)
 
-  inline Address TypeAddress() {
-    return address() + kTypeOffset;
-  }
-
   // Dispatched behavior.
   DECLARE_PRINTER(PropertyCell)
   DECLARE_VERIFIER(PropertyCell)
 
   // Layout description.
-  static const int kTypeOffset = kValueOffset + kPointerSize;
-  static const int kDependentCodeOffset = kTypeOffset + kPointerSize;
+  static const int kValueOffset = HeapObject::kHeaderSize;
+  static const int kDependentCodeOffset = kValueOffset + kPointerSize;
   static const int kSize = kDependentCodeOffset + kPointerSize;
 
   static const int kPointerFieldsBeginOffset = kValueOffset;
@@ -9766,7 +9846,6 @@ class PropertyCell: public Cell {
                               kSize> BodyDescriptor;
 
  private:
-  DECL_ACCESSORS(type_raw, Object)
   DISALLOW_IMPLICIT_CONSTRUCTORS(PropertyCell);
 };
 
@@ -10577,6 +10656,7 @@ class InterceptorInfo: public Struct {
   DECL_ACCESSORS(data, Object)
   DECL_BOOLEAN_ACCESSORS(can_intercept_symbols)
   DECL_BOOLEAN_ACCESSORS(all_can_read)
+  DECL_BOOLEAN_ACCESSORS(non_masking)
 
   inline int flags() const;
   inline void set_flags(int flags);
@@ -10598,6 +10678,7 @@ class InterceptorInfo: public Struct {
 
   static const int kCanInterceptSymbolsBit = 0;
   static const int kAllCanReadBit = 1;
+  static const int kNonMasking = 2;
 
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptorInfo);
@@ -10671,6 +10752,7 @@ class FunctionTemplateInfo: public TemplateInfo {
   DECL_BOOLEAN_ACCESSORS(remove_prototype)
   DECL_BOOLEAN_ACCESSORS(do_not_cache)
   DECL_BOOLEAN_ACCESSORS(instantiated)
+  DECL_BOOLEAN_ACCESSORS(accept_any_receiver)
 
   DECLARE_CAST(FunctionTemplateInfo)
 
@@ -10716,6 +10798,7 @@ class FunctionTemplateInfo: public TemplateInfo {
   static const int kRemovePrototypeBit   = 4;
   static const int kDoNotCacheBit        = 5;
   static const int kInstantiatedBit      = 6;
+  static const int kAcceptAnyReceiver = 7;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(FunctionTemplateInfo);
 };
@@ -10781,10 +10864,10 @@ class DebugInfo: public Struct {
                             int source_position, int statement_position,
                             Handle<Object> break_point_object);
   // Get the break point objects for a code position.
-  Object* GetBreakPointObjects(int code_position);
+  Handle<Object> GetBreakPointObjects(int code_position);
   // Find the break point info holding this break point object.
-  static Object* FindBreakPointInfo(Handle<DebugInfo> debug_info,
-                                    Handle<Object> break_point_object);
+  static Handle<Object> FindBreakPointInfo(Handle<DebugInfo> debug_info,
+                                           Handle<Object> break_point_object);
   // Get the number of break points for this function.
   int GetBreakPointCount();
 
@@ -10947,9 +11030,12 @@ class ObjectVisitor BASE_EMBEDDED {
   // Visits an external reference embedded into a code object.
   virtual void VisitExternalReference(RelocInfo* rinfo);
 
-  // Visits an external reference. The value may be modified on return.
+  // Visits an external reference.
   virtual void VisitExternalReference(Address* p) {}
 
+  // Visits an (encoded) internal reference.
+  virtual void VisitInternalReference(RelocInfo* rinfo) {}
+
   // Visits a handle that has an embedder-assigned class ID.
   virtual void VisitEmbedderReference(Object** p, uint16_t class_id) {}
 
index 5999df9..eda4f5c 100644 (file)
@@ -42,7 +42,11 @@ void DisposeOptimizedCompileJob(OptimizedCompileJob* job,
 
 class OptimizingCompilerThread::CompileTask : public v8::Task {
  public:
-  explicit CompileTask(Isolate* isolate) : isolate_(isolate) {}
+  explicit CompileTask(Isolate* isolate) : isolate_(isolate) {
+    OptimizingCompilerThread* thread = isolate_->optimizing_compiler_thread();
+    base::LockGuard<base::Mutex> lock_guard(&thread->ref_count_mutex_);
+    ++thread->ref_count_;
+  }
 
   virtual ~CompileTask() {}
 
@@ -54,7 +58,6 @@ class OptimizingCompilerThread::CompileTask : public v8::Task {
     DisallowHandleDereference no_deref;
 
     OptimizingCompilerThread* thread = isolate_->optimizing_compiler_thread();
-
     {
       TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_);
 
@@ -62,32 +65,14 @@ class OptimizingCompilerThread::CompileTask : public v8::Task {
         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);
-        }
-      }
+      thread->CompileNext(thread->NextInput(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;
-        }
+      base::LockGuard<base::Mutex> lock_guard(&thread->ref_count_mutex_);
+      if (--thread->ref_count_ == 0) {
+        thread->ref_count_zero_.NotifyOne();
       }
     }
-    if (signal) thread->stop_semaphore_.Signal();
   }
 
   Isolate* isolate_;
@@ -97,6 +82,12 @@ class OptimizingCompilerThread::CompileTask : public v8::Task {
 
 
 OptimizingCompilerThread::~OptimizingCompilerThread() {
+#ifdef DEBUG
+  {
+    base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
+    DCHECK_EQ(0, ref_count_);
+  }
+#endif
   DCHECK_EQ(0, input_queue_length_);
   DeleteArray(input_queue_);
   if (FLAG_concurrent_osr) {
@@ -168,28 +159,29 @@ void OptimizingCompilerThread::Run() {
 }
 
 
-OptimizedCompileJob* OptimizingCompilerThread::NextInput(StopFlag* flag) {
+OptimizedCompileJob* OptimizingCompilerThread::NextInput(
+    bool check_if_flushing) {
   base::LockGuard<base::Mutex> access_input_queue_(&input_queue_mutex_);
-  if (input_queue_length_ == 0) {
-    if (flag) {
-      UNREACHABLE();
-      *flag = CONTINUE;
-    }
-    return NULL;
-  }
+  if (input_queue_length_ == 0) return NULL;
   OptimizedCompileJob* job = input_queue_[InputQueueIndex(0)];
   DCHECK_NOT_NULL(job);
   input_queue_shift_ = InputQueueIndex(1);
   input_queue_length_--;
-  if (flag) {
-    *flag = static_cast<StopFlag>(base::Acquire_Load(&stop_thread_));
+  if (check_if_flushing) {
+    if (static_cast<StopFlag>(base::Acquire_Load(&stop_thread_)) != CONTINUE) {
+      if (!job->info()->is_osr()) {
+        AllowHandleDereference allow_handle_dereference;
+        DisposeOptimizedCompileJob(job, true);
+      }
+      return NULL;
+    }
   }
   return job;
 }
 
 
 void OptimizingCompilerThread::CompileNext(OptimizedCompileJob* job) {
-  DCHECK_NOT_NULL(job);
+  if (!job) return;
 
   // The function may have already been optimized by OSR.  Simply continue.
   OptimizedCompileJob::Status status = job->OptimizeGraph();
@@ -222,7 +214,6 @@ void OptimizingCompilerThread::FlushInputQueue(bool restore_function_code) {
 
 
 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.
@@ -245,20 +236,16 @@ void OptimizingCompilerThread::FlushOsrBuffer(bool restore_function_code) {
 
 void OptimizingCompilerThread::Flush() {
   DCHECK(!IsOptimizerThread());
-  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();
+  base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(FLUSH));
+  if (FLAG_block_concurrent_recompilation) Unblock();
+  if (!job_based_recompilation_) {
+    input_queue_semaphore_.Signal();
+    stop_semaphore_.Wait();
   } else {
-    base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(FLUSH));
-    if (FLAG_block_concurrent_recompilation) Unblock();
+    base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
+    while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_);
+    base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(CONTINUE));
   }
-  if (!job_based_recompilation_) input_queue_semaphore_.Signal();
-  if (block) stop_semaphore_.Wait();
   FlushOutputQueue(true);
   if (FLAG_concurrent_osr) FlushOsrBuffer(true);
   if (tracing_enabled_) {
@@ -269,20 +256,16 @@ void OptimizingCompilerThread::Flush() {
 
 void OptimizingCompilerThread::Stop() {
   DCHECK(!IsOptimizerThread());
-  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();
+  base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(STOP));
+  if (FLAG_block_concurrent_recompilation) Unblock();
+  if (!job_based_recompilation_) {
+    input_queue_semaphore_.Signal();
+    stop_semaphore_.Wait();
   } else {
-    base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(STOP));
-    if (FLAG_block_concurrent_recompilation) Unblock();
+    base::LockGuard<base::Mutex> lock_guard(&ref_count_mutex_);
+    while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_);
+    base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(CONTINUE));
   }
-  if (!job_based_recompilation_) input_queue_semaphore_.Signal();
-  if (block) stop_semaphore_.Wait();
 
   if (recompilation_delay_ != 0) {
     // At this point the optimizing compiler thread's event loop has stopped.
@@ -372,8 +355,6 @@ void OptimizingCompilerThread::QueueForOptimization(OptimizedCompileJob* job) {
   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 {
@@ -384,10 +365,6 @@ void OptimizingCompilerThread::QueueForOptimization(OptimizedCompileJob* job) {
 
 void OptimizingCompilerThread::Unblock() {
   DCHECK(!IsOptimizerThread());
-  {
-    base::LockGuard<base::RecursiveMutex> lock(&task_count_mutex_);
-    task_count_ += blocked_jobs_;
-  }
   while (blocked_jobs_ > 0) {
     if (job_based_recompilation_) {
       V8::GetCurrentPlatform()->CallOnBackgroundThread(
index 3088843..7d60d9b 100644 (file)
@@ -6,6 +6,7 @@
 #define V8_OPTIMIZING_COMPILER_THREAD_H_
 
 #include "src/base/atomicops.h"
+#include "src/base/platform/condition-variable.h"
 #include "src/base/platform/mutex.h"
 #include "src/base/platform/platform.h"
 #include "src/base/platform/time.h"
@@ -35,10 +36,10 @@ class OptimizingCompilerThread : public base::Thread {
         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),
+        ref_count_(0),
         tracing_enabled_(FLAG_trace_concurrent_recompilation),
         job_based_recompilation_(FLAG_job_based_recompilation),
         recompilation_delay_(FLAG_concurrent_recompilation_delay) {
@@ -96,7 +97,7 @@ class OptimizingCompilerThread : public base::Thread {
   void FlushOutputQueue(bool restore_function_code);
   void FlushOsrBuffer(bool restore_function_code);
   void CompileNext(OptimizedCompileJob* job);
-  OptimizedCompileJob* NextInput(StopFlag* flag = NULL);
+  OptimizedCompileJob* NextInput(bool check_if_flushing = false);
 
   // Add a recompilation task for OSR to the cyclic buffer, awaiting OSR entry.
   // Tasks evicted from the cyclic buffer are discarded.
@@ -140,18 +141,15 @@ class OptimizingCompilerThread : public base::Thread {
   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_;
 
+  int ref_count_;
+  base::Mutex ref_count_mutex_;
+  base::ConditionVariable ref_count_zero_;
+
   // Copies of FLAG_trace_concurrent_recompilation,
   // FLAG_concurrent_recompilation_delay and
   // FLAG_job_based_recompilation that will be used from the background thread.
index 985a90f..8ed20ee 100644 (file)
 namespace v8 {
 namespace internal {
 
+ScriptData::ScriptData(const byte* data, int 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));
+    CopyBytes(copy, data, length);
+    data_ = copy;
+    AcquireDataOwnership();
+  }
+}
+
+
+ParseInfo::ParseInfo(Zone* zone)
+    : zone_(zone),
+      flags_(0),
+      source_stream_(nullptr),
+      source_stream_encoding_(ScriptCompiler::StreamedSource::ONE_BYTE),
+      extension_(nullptr),
+      compile_options_(ScriptCompiler::kNoCompileOptions),
+      script_scope_(nullptr),
+      unicode_cache_(nullptr),
+      stack_limit_(0),
+      hash_seed_(0),
+      cached_data_(nullptr),
+      ast_value_factory_(nullptr),
+      literal_(nullptr),
+      scope_(nullptr) {}
+
+
+ParseInfo::ParseInfo(Zone* zone, Handle<JSFunction> function)
+    : ParseInfo(zone, Handle<SharedFunctionInfo>(function->shared())) {
+  set_closure(function);
+  set_context(Handle<Context>(function->context()));
+}
+
+
+ParseInfo::ParseInfo(Zone* zone, Handle<SharedFunctionInfo> shared)
+    : ParseInfo(zone) {
+  isolate_ = shared->GetIsolate();
+
+  set_lazy();
+  set_hash_seed(isolate_->heap()->HashSeed());
+  set_stack_limit(isolate_->stack_guard()->real_climit());
+  set_unicode_cache(isolate_->unicode_cache());
+  set_language_mode(shared->language_mode());
+  set_shared_info(shared);
+
+  Handle<Script> script(Script::cast(shared->script()));
+  set_script(script);
+  if (!script.is_null() && script->type()->value() == Script::TYPE_NATIVE) {
+    set_native();
+  }
+}
+
+
+ParseInfo::ParseInfo(Zone* zone, Handle<Script> script) : ParseInfo(zone) {
+  isolate_ = script->GetIsolate();
+
+  set_hash_seed(isolate_->heap()->HashSeed());
+  set_stack_limit(isolate_->stack_guard()->real_climit());
+  set_unicode_cache(isolate_->unicode_cache());
+  set_script(script);
+
+  if (script->type()->value() == Script::TYPE_NATIVE) {
+    set_native();
+  }
+}
+
+
 RegExpBuilder::RegExpBuilder(Zone* zone)
     : zone_(zone),
       pending_empty_(false),
@@ -251,7 +320,7 @@ int ParseData::FunctionsSize() {
 }
 
 
-void Parser::SetCachedData(CompilationInfo* info) {
+void Parser::SetCachedData(ParseInfo* info) {
   if (compile_options_ == ScriptCompiler::kNoCompileOptions) {
     cached_parse_data_ = NULL;
   } else {
@@ -600,56 +669,46 @@ Expression* ParserTraits::NewThrowError(
 
 
 void ParserTraits::ReportMessageAt(Scanner::Location source_location,
-                                   const char* message,
-                                   const char* arg,
-                                   bool is_reference_error) {
+                                   const char* message, const char* arg,
+                                   ParseErrorType error_type) {
   if (parser_->stack_overflow()) {
     // Suppress the error message (syntax error or such) in the presence of a
     // stack overflow. The isolate allows only one pending exception at at time
     // and we want to report the stack overflow later.
     return;
   }
-  parser_->has_pending_error_ = true;
-  parser_->pending_error_location_ = source_location;
-  parser_->pending_error_message_ = message;
-  parser_->pending_error_char_arg_ = arg;
-  parser_->pending_error_arg_ = NULL;
-  parser_->pending_error_is_reference_error_ = is_reference_error;
+  parser_->pending_error_handler_.ReportMessageAt(source_location.beg_pos,
+                                                  source_location.end_pos,
+                                                  message, arg, error_type);
 }
 
 
-void ParserTraits::ReportMessage(const char* message,
-                                 const char* arg,
-                                 bool is_reference_error) {
+void ParserTraits::ReportMessage(const char* message, const char* arg,
+                                 ParseErrorType error_type) {
   Scanner::Location source_location = parser_->scanner()->location();
-  ReportMessageAt(source_location, message, arg, is_reference_error);
+  ReportMessageAt(source_location, message, arg, error_type);
 }
 
 
-void ParserTraits::ReportMessage(const char* message,
-                                 const AstRawString* arg,
-                                 bool is_reference_error) {
+void ParserTraits::ReportMessage(const char* message, const AstRawString* arg,
+                                 ParseErrorType error_type) {
   Scanner::Location source_location = parser_->scanner()->location();
-  ReportMessageAt(source_location, message, arg, is_reference_error);
+  ReportMessageAt(source_location, message, arg, error_type);
 }
 
 
 void ParserTraits::ReportMessageAt(Scanner::Location source_location,
-                                   const char* message,
-                                   const AstRawString* arg,
-                                   bool is_reference_error) {
+                                   const char* message, const AstRawString* arg,
+                                   ParseErrorType error_type) {
   if (parser_->stack_overflow()) {
     // Suppress the error message (syntax error or such) in the presence of a
     // stack overflow. The isolate allows only one pending exception at at time
     // and we want to report the stack overflow later.
     return;
   }
-  parser_->has_pending_error_ = true;
-  parser_->pending_error_location_ = source_location;
-  parser_->pending_error_message_ = message;
-  parser_->pending_error_char_arg_ = NULL;
-  parser_->pending_error_arg_ = arg;
-  parser_->pending_error_is_reference_error_ = is_reference_error;
+  parser_->pending_error_handler_.ReportMessageAt(source_location.beg_pos,
+                                                  source_location.end_pos,
+                                                  message, arg, error_type);
 }
 
 
@@ -704,6 +763,10 @@ Literal* ParserTraits::ExpressionFromLiteral(Token::Value token, int pos,
       return factory->NewBooleanLiteral(true, pos);
     case Token::FALSE_LITERAL:
       return factory->NewBooleanLiteral(false, pos);
+    case Token::SMI: {
+      int value = scanner->smi_value();
+      return factory->NewSmiLiteral(value, pos);
+    }
     case Token::NUMBER: {
       double value = scanner->DoubleValue();
       return factory->NewNumberLiteral(value, pos);
@@ -716,7 +779,9 @@ Literal* ParserTraits::ExpressionFromLiteral(Token::Value token, int pos,
 
 
 Expression* ParserTraits::ExpressionFromIdentifier(const AstRawString* name,
-                                                   int pos, Scope* scope,
+                                                   int start_position,
+                                                   int end_position,
+                                                   Scope* scope,
                                                    AstNodeFactory* factory) {
   if (parser_->fni_ != NULL) parser_->fni_->PushVariableName(name);
 
@@ -725,8 +790,10 @@ Expression* ParserTraits::ExpressionFromIdentifier(const AstRawString* name,
   // for Traits::DeclareArrowParametersFromExpression() to be able to
   // pick the names of the parameters.
   return parser_->parsing_lazy_arrow_parameters_
-             ? factory->NewVariableProxy(name, false, pos)
-             : scope->NewUnresolved(factory, name, pos);
+             ? factory->NewVariableProxy(name, Variable::NORMAL, start_position,
+                                         end_position)
+             : scope->NewUnresolved(factory, name, start_position,
+                                    end_position);
 }
 
 
@@ -781,38 +848,31 @@ ClassLiteral* ParserTraits::ParseClassLiteral(
 }
 
 
-Parser::Parser(CompilationInfo* info, uintptr_t stack_limit, uint32_t hash_seed,
-               UnicodeCache* unicode_cache)
-    : ParserBase<ParserTraits>(info->zone(), &scanner_, stack_limit,
+Parser::Parser(ParseInfo* info)
+    : ParserBase<ParserTraits>(info->zone(), &scanner_, info->stack_limit(),
                                info->extension(), info->ast_value_factory(),
                                NULL, this),
-      scanner_(unicode_cache),
+      scanner_(info->unicode_cache()),
       reusable_preparser_(NULL),
       original_scope_(NULL),
       target_stack_(NULL),
       compile_options_(info->compile_options()),
       cached_parse_data_(NULL),
       parsing_lazy_arrow_parameters_(false),
-      has_pending_error_(false),
-      pending_error_message_(NULL),
-      pending_error_arg_(NULL),
-      pending_error_char_arg_(NULL),
       total_preparse_skipped_(0),
       pre_parse_timer_(NULL),
       parsing_on_main_thread_(true) {
-  // Even though we were passed CompilationInfo, we should not store it in
+  // Even though we were passed ParseInfo, we should not store it in
   // Parser - this makes sure that Isolate is not accidentally accessed via
-  // CompilationInfo during background parsing.
+  // ParseInfo during background parsing.
   DCHECK(!info->script().is_null() || info->source_stream() != NULL);
-  set_allow_lazy(false);  // Must be explicitly enabled.
+  set_allow_lazy(info->allow_lazy_parsing());
   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_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);
   set_allow_harmony_computed_property_names(
@@ -825,13 +885,14 @@ Parser::Parser(CompilationInfo* info, uintptr_t stack_limit, uint32_t hash_seed,
   }
   if (info->ast_value_factory() == NULL) {
     // info takes ownership of AstValueFactory.
-    info->SetAstValueFactory(new AstValueFactory(zone(), hash_seed));
+    info->set_ast_value_factory(new AstValueFactory(zone(), info->hash_seed()));
+    info->set_ast_value_factory_owned();
     ast_value_factory_ = info->ast_value_factory();
   }
 }
 
 
-FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) {
+FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
   // TODO(bmeurer): We temporarily need to pass allow_nesting = true here,
   // see comment for HistogramTimerScope class.
 
@@ -839,7 +900,6 @@ FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) {
   // called in the main thread.
   DCHECK(parsing_on_main_thread_);
 
-  Isolate* isolate = info->isolate();
   HistogramTimerScope timer_scope(isolate->counters()->parse(), true);
   Handle<String> source(String::cast(info->script()->source()));
   isolate->counters()->total_parse_size()->Increment(source->length());
@@ -880,7 +940,7 @@ FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) {
   if (eval_scope != NULL) {
     eval_scope->set_end_position(source->length());
   }
-  HandleSourceURLComments(info);
+  HandleSourceURLComments(isolate, info->script());
 
   if (FLAG_trace_parse && result != NULL) {
     double ms = timer.Elapsed().InMillisecondsF();
@@ -903,18 +963,18 @@ FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) {
 }
 
 
-FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope,
+FunctionLiteral* Parser::DoParseProgram(ParseInfo* info, Scope** scope,
                                         Scope** eval_scope) {
   // Note that this function can be called from the main thread or from a
   // background thread. We should not access anything Isolate / heap dependent
-  // via CompilationInfo, and also not pass it forward.
+  // via ParseInfo, and also not pass it forward.
   DCHECK(scope_ == NULL);
   DCHECK(target_stack_ == NULL);
 
   FunctionLiteral* result = NULL;
   {
     *scope = NewScope(scope_, SCRIPT_SCOPE);
-    info->SetScriptScope(*scope);
+    info->set_script_scope(*scope);
     if (!info->context().is_null() && !info->context()->IsNativeContext()) {
       *scope = Scope::DeserializeScopeChain(info->isolate(), zone(),
                                             *info->context(), *scope);
@@ -930,8 +990,8 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope,
       if (!(*scope)->is_script_scope() || is_strict(info->language_mode())) {
         *scope = NewScope(*scope, EVAL_SCOPE);
       }
-    } else if (info->is_global()) {
-      *scope = NewScope(*scope, SCRIPT_SCOPE);
+    } else if (info->is_module()) {
+      *scope = NewScope(*scope, MODULE_SCOPE);
     }
     (*scope)->set_start_position(0);
     // End position will be set by the caller.
@@ -955,19 +1015,13 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope,
     int beg_pos = scanner()->location().beg_pos;
     if (info->is_module()) {
       DCHECK(allow_harmony_modules());
-      Statement* stmt = ParseModule(&ok);
-      if (ok) {
-        body->Add(stmt, zone());
-      }
+      ParseModuleItemList(body, &ok);
     } else {
       ParseStatementList(body, Token::EOS, info->is_eval(), eval_scope, &ok);
     }
 
     if (ok && is_strict(language_mode())) {
       CheckStrictOctalLiteral(beg_pos, scanner()->location().end_pos, &ok);
-    }
-
-    if (ok && allow_harmony_scoping() && is_strict(language_mode())) {
       CheckConflictingVarDeclarations(scope_, &ok);
     }
 
@@ -1000,13 +1054,13 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope,
 }
 
 
-FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) {
+FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info) {
   // It's OK to use the Isolate & counters here, since this function is only
   // called in the main thread.
   DCHECK(parsing_on_main_thread_);
-  HistogramTimerScope timer_scope(info->isolate()->counters()->parse_lazy());
+  HistogramTimerScope timer_scope(isolate->counters()->parse_lazy());
   Handle<String> source(String::cast(info->script()->source()));
-  info->isolate()->counters()->total_parse_size()->Increment(source->length());
+  isolate->counters()->total_parse_size()->Increment(source->length());
   base::ElapsedTimer timer;
   if (FLAG_trace_parse) {
     timer.Start();
@@ -1021,12 +1075,12 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) {
         Handle<ExternalTwoByteString>::cast(source),
         shared_info->start_position(),
         shared_info->end_position());
-    result = ParseLazy(info, &stream);
+    result = ParseLazy(isolate, info, &stream);
   } else {
     GenericStringUtf16CharacterStream stream(source,
                                              shared_info->start_position(),
                                              shared_info->end_position());
-    result = ParseLazy(info, &stream);
+    result = ParseLazy(isolate, info, &stream);
   }
 
   if (FLAG_trace_parse && result != NULL) {
@@ -1038,7 +1092,7 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) {
 }
 
 
-FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
+FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
                                    Utf16CharacterStream* source) {
   Handle<SharedFunctionInfo> shared_info = info->shared_info();
   scanner_.Initialize(source);
@@ -1059,12 +1113,12 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
   {
     // Parse the function literal.
     Scope* scope = NewScope(scope_, SCRIPT_SCOPE);
-    info->SetScriptScope(scope);
+    info->set_script_scope(scope);
     if (!info->closure().is_null()) {
       // Ok to use Isolate here, since lazy function parsing is only done in the
       // main thread.
       DCHECK(parsing_on_main_thread_);
-      scope = Scope::DeserializeScopeChain(info->isolate(), zone(),
+      scope = Scope::DeserializeScopeChain(isolate, zone(),
                                            info->closure()->context(), scope);
     }
     original_scope_ = scope;
@@ -1088,8 +1142,24 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
       // from creating unresolved variables in already-resolved scopes.
       parsing_lazy_arrow_parameters_ = true;
       Expression* expression = ParseExpression(false, &ok);
-      DCHECK(expression->IsFunctionLiteral());
-      result = expression->AsFunctionLiteral();
+      if (ok) {
+        // Scanning must end at the same position that was recorded
+        // previously. If not, parsing has been interrupted due to a
+        // stack overflow, at which point the partially parsed arrow
+        // function concise body happens to be a valid expression. This
+        // is a problem only for arrow functions with single statement
+        // bodies, since there is no end token such as "}" for normal
+        // functions.
+        if (scanner()->location().end_pos == shared_info->end_position()) {
+          // The pre-parser saw an arrow function here, so the full parser
+          // must produce a FunctionLiteral.
+          DCHECK(expression->IsFunctionLiteral());
+          result = expression->AsFunctionLiteral();
+        } else {
+          result = NULL;
+          ok = false;
+        }
+      }
     } else if (shared_info->is_default_constructor()) {
       result = DefaultConstructor(IsSubclassConstructor(shared_info->kind()),
                                   scope, shared_info->start_position(),
@@ -1135,8 +1205,27 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
       directive_prologue = false;
     }
 
+    Token::Value token = peek();
     Scanner::Location token_loc = scanner()->peek_location();
+    Scanner::Location old_super_loc = function_state_->super_call_location();
     Statement* stat = ParseStatementListItem(CHECK_OK);
+    Scanner::Location super_loc = function_state_->super_call_location();
+
+    if (is_strong(language_mode()) &&
+        i::IsConstructor(function_state_->kind()) &&
+        !old_super_loc.IsValid() && super_loc.IsValid() &&
+        token != Token::SUPER) {
+      // TODO(rossberg): This is more permissive than spec'ed, it allows e.g.
+      //   super(), 1;
+      //   super() + "";
+      //   super() = 0;
+      // That should still be safe, though, thanks to left-to-right evaluation.
+      // The proper check would be difficult to implement in the preparser.
+      ReportMessageAt(super_loc, "strong_super_call_nested");
+      *ok = false;
+      return NULL;
+    }
+
     if (stat == NULL || stat->IsEmpty()) {
       directive_prologue = false;   // End of directive prologue.
       continue;
@@ -1229,7 +1318,6 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
     case Token::VAR:
       return ParseVariableStatement(kStatementListItem, NULL, ok);
     case Token::LET:
-      DCHECK(allow_harmony_scoping());
       if (is_strict(language_mode())) {
         return ParseVariableStatement(kStatementListItem, NULL, ok);
       }
@@ -1258,7 +1346,7 @@ Statement* Parser::ParseModuleItem(bool* ok) {
 }
 
 
-Statement* Parser::ParseModule(bool* ok) {
+void* Parser::ParseModuleItemList(ZoneList<Statement*>* body, bool* ok) {
   // (Ecma 262 6th Edition, 15.2):
   // Module :
   //    ModuleBody?
@@ -1266,53 +1354,48 @@ Statement* Parser::ParseModule(bool* ok) {
   // ModuleBody :
   //    ModuleItem*
 
-  Block* body = factory()->NewBlock(NULL, 16, false, RelocInfo::kNoPosition);
-  Scope* scope = NewScope(scope_, MODULE_SCOPE);
-  scope->set_start_position(scanner()->location().beg_pos);
-  scope->SetLanguageMode(
-      static_cast<LanguageMode>(scope->language_mode() | STRICT_BIT));
-
-  {
-    BlockState block_state(&scope_, scope);
+  DCHECK(scope_->is_module_scope());
+  scope_->SetLanguageMode(
+      static_cast<LanguageMode>(scope_->language_mode() | STRICT_BIT));
 
-    while (peek() != Token::EOS) {
-      Statement* stat = ParseModuleItem(CHECK_OK);
-      if (stat && !stat->IsEmpty()) {
-        body->AddStatement(stat, zone());
-      }
+  while (peek() != Token::EOS) {
+    Statement* stat = ParseModuleItem(CHECK_OK);
+    if (stat && !stat->IsEmpty()) {
+      body->Add(stat, zone());
     }
   }
 
-  scope->set_end_position(scanner()->location().end_pos);
-  body->set_scope(scope);
-
   // Check that all exports are bound.
-  ModuleDescriptor* descriptor = scope->module();
+  ModuleDescriptor* descriptor = scope_->module();
   for (ModuleDescriptor::Iterator it = descriptor->iterator(); !it.done();
        it.Advance()) {
-    if (scope->LookupLocal(it.name()) == NULL) {
-      ParserTraits::ReportMessage("module_export_undefined", it.name());
+    if (scope_->LookupLocal(it.local_name()) == NULL) {
+      // TODO(adamk): Pass both local_name and export_name once ParserTraits
+      // supports multiple arg error messages.
+      // Also try to report this at a better location.
+      ParserTraits::ReportMessage("module_export_undefined", it.local_name());
       *ok = false;
       return NULL;
     }
   }
 
-  scope->module()->Freeze();
-  return body;
+  scope_->module()->Freeze();
+  return NULL;
 }
 
 
-Literal* Parser::ParseModuleSpecifier(bool* ok) {
+const AstRawString* Parser::ParseModuleSpecifier(bool* ok) {
   // ModuleSpecifier :
   //    StringLiteral
 
-  int pos = peek_position();
   Expect(Token::STRING, CHECK_OK);
-  return factory()->NewStringLiteral(GetSymbol(scanner()), pos);
+  return GetSymbol(scanner());
 }
 
 
-void* Parser::ParseExportClause(ZoneList<const AstRawString*>* names,
+void* Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names,
+                                ZoneList<Scanner::Location>* export_locations,
+                                ZoneList<const AstRawString*>* local_names,
                                 Scanner::Location* reserved_loc, bool* ok) {
   // ExportClause :
   //   '{' '}'
@@ -1337,14 +1420,17 @@ void* Parser::ParseExportClause(ZoneList<const AstRawString*>* names,
         !Token::IsIdentifier(name_tok, STRICT, false)) {
       *reserved_loc = scanner()->location();
     }
-    const AstRawString* name = ParseIdentifierName(CHECK_OK);
-    names->Add(name, zone());
+    const AstRawString* local_name = ParseIdentifierName(CHECK_OK);
     const AstRawString* export_name = NULL;
     if (CheckContextualKeyword(CStrVector("as"))) {
       export_name = ParseIdentifierName(CHECK_OK);
     }
-    // TODO(ES6): Return the export_name as well as the name.
-    USE(export_name);
+    if (export_name == NULL) {
+      export_name = local_name;
+    }
+    export_names->Add(export_name, zone());
+    local_names->Add(local_name, zone());
+    export_locations->Add(scanner()->location(), zone());
     if (peek() == Token::RBRACE) break;
     Expect(Token::COMMA, CHECK_OK);
   }
@@ -1355,8 +1441,7 @@ void* Parser::ParseExportClause(ZoneList<const AstRawString*>* names,
 }
 
 
-void* Parser::ParseNamedImports(ZoneList<const AstRawString*>* names,
-                                bool* ok) {
+ZoneList<ImportDeclaration*>* Parser::ParseNamedImports(int pos, bool* ok) {
   // NamedImports :
   //   '{' '}'
   //   '{' ImportsList '}'
@@ -1372,34 +1457,38 @@ void* Parser::ParseNamedImports(ZoneList<const AstRawString*>* names,
 
   Expect(Token::LBRACE, CHECK_OK);
 
-  Token::Value name_tok;
-  while ((name_tok = peek()) != Token::RBRACE) {
-    const AstRawString* name = ParseIdentifierName(CHECK_OK);
-    const AstRawString* import_name = NULL;
+  ZoneList<ImportDeclaration*>* result =
+      new (zone()) ZoneList<ImportDeclaration*>(1, zone());
+  while (peek() != Token::RBRACE) {
+    const AstRawString* import_name = ParseIdentifierName(CHECK_OK);
+    const AstRawString* local_name = import_name;
     // In the presence of 'as', the left-side of the 'as' can
     // be any IdentifierName. But without 'as', it must be a valid
-    // BindingIdentiifer.
+    // BindingIdentifier.
     if (CheckContextualKeyword(CStrVector("as"))) {
-      import_name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
-    } else if (!Token::IsIdentifier(name_tok, STRICT, false)) {
+      local_name = ParseIdentifierName(CHECK_OK);
+    }
+    if (!Token::IsIdentifier(scanner()->current_token(), STRICT, false)) {
       *ok = false;
-      ReportMessageAt(scanner()->location(), "unexpected_reserved");
+      ReportMessage("unexpected_reserved");
       return NULL;
-    } else if (IsEvalOrArguments(name)) {
+    } else if (IsEvalOrArguments(local_name)) {
       *ok = false;
-      ReportMessageAt(scanner()->location(), "strict_eval_arguments");
+      ReportMessage("strict_eval_arguments");
       return NULL;
     }
-    // TODO(ES6): Return the import_name as well as the name.
-    names->Add(name, zone());
-    USE(import_name);
+    VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
+    ImportDeclaration* declaration =
+        factory()->NewImportDeclaration(proxy, import_name, NULL, scope_, pos);
+    Declare(declaration, true, CHECK_OK);
+    result->Add(declaration, zone());
     if (peek() == Token::RBRACE) break;
     Expect(Token::COMMA, CHECK_OK);
   }
 
   Expect(Token::RBRACE, CHECK_OK);
 
-  return NULL;
+  return result;
 }
 
 
@@ -1425,32 +1514,39 @@ Statement* Parser::ParseImportDeclaration(bool* ok) {
 
   // 'import' ModuleSpecifier ';'
   if (tok == Token::STRING) {
-    ParseModuleSpecifier(CHECK_OK);
+    const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
     ExpectSemicolon(CHECK_OK);
+    // TODO(ES6): Add module to the requested modules of scope_->module().
+    USE(module_specifier);
     return factory()->NewEmptyStatement(pos);
   }
 
   // Parse ImportedDefaultBinding if present.
-  const AstRawString* imported_default_binding = NULL;
+  ImportDeclaration* import_default_declaration = NULL;
   if (tok != Token::MUL && tok != Token::LBRACE) {
-    imported_default_binding =
+    const AstRawString* local_name =
         ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+    VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
+    import_default_declaration = factory()->NewImportDeclaration(
+        proxy, ast_value_factory()->default_string(), NULL, scope_, pos);
+    Declare(import_default_declaration, true, CHECK_OK);
   }
 
   const AstRawString* module_instance_binding = NULL;
-  ZoneList<const AstRawString*> names(1, zone());
-  if (imported_default_binding == NULL || Check(Token::COMMA)) {
+  ZoneList<ImportDeclaration*>* named_declarations = NULL;
+  if (import_default_declaration == NULL || Check(Token::COMMA)) {
     switch (peek()) {
       case Token::MUL: {
         Consume(Token::MUL);
         ExpectContextualKeyword(CStrVector("as"), CHECK_OK);
         module_instance_binding =
             ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+        // TODO(ES6): Add an appropriate declaration.
         break;
       }
 
       case Token::LBRACE:
-        ParseNamedImports(&names, CHECK_OK);
+        named_declarations = ParseNamedImports(pos, CHECK_OK);
         break;
 
       default:
@@ -1461,21 +1557,21 @@ Statement* Parser::ParseImportDeclaration(bool* ok) {
   }
 
   ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
-  Literal* module = ParseModuleSpecifier(CHECK_OK);
-  USE(module);
-
+  const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
   ExpectSemicolon(CHECK_OK);
 
   if (module_instance_binding != NULL) {
-    // TODO(ES6): Bind name to the Module Instance Object of module.
+    // TODO(ES6): Set the module specifier for the module namespace binding.
   }
 
-  if (imported_default_binding != NULL) {
-    // TODO(ES6): Add an appropriate declaration.
+  if (import_default_declaration != NULL) {
+    import_default_declaration->set_module_specifier(module_specifier);
   }
 
-  for (int i = 0; i < names.length(); ++i) {
-    // TODO(ES6): Add an appropriate declaration for each name
+  if (named_declarations != NULL) {
+    for (int i = 0; i < named_declarations->length(); ++i) {
+      named_declarations->at(i)->set_module_specifier(module_specifier);
+    }
   }
 
   return factory()->NewEmptyStatement(pos);
@@ -1488,16 +1584,20 @@ Statement* Parser::ParseExportDefault(bool* ok) {
   //    'export' 'default' ClassDeclaration
   //    'export' 'default' AssignmentExpression[In] ';'
 
+  Expect(Token::DEFAULT, CHECK_OK);
+  Scanner::Location default_loc = scanner()->location();
+
+  ZoneList<const AstRawString*> names(1, zone());
   Statement* result = NULL;
   switch (peek()) {
     case Token::FUNCTION:
       // TODO(ES6): Support parsing anonymous function declarations here.
-      result = ParseFunctionDeclaration(NULL, CHECK_OK);
+      result = ParseFunctionDeclaration(&names, CHECK_OK);
       break;
 
     case Token::CLASS:
       // TODO(ES6): Support parsing anonymous class declarations here.
-      result = ParseClassDeclaration(NULL, CHECK_OK);
+      result = ParseClassDeclaration(&names, CHECK_OK);
       break;
 
     default: {
@@ -1509,7 +1609,20 @@ Statement* Parser::ParseExportDefault(bool* ok) {
     }
   }
 
-  // TODO(ES6): Add default export to scope_->module()
+  const AstRawString* default_string = ast_value_factory()->default_string();
+
+  DCHECK_LE(names.length(), 1);
+  if (names.length() == 1) {
+    scope_->module()->AddLocalExport(default_string, names.first(), zone(), ok);
+    if (!*ok) {
+      ParserTraits::ReportMessageAt(default_loc, "duplicate_export",
+                                    default_string);
+      return NULL;
+    }
+  } else {
+    // TODO(ES6): Assign result to a const binding with the name "*default*"
+    // and add an export entry with "*default*" as the local name.
+  }
 
   return result;
 }
@@ -1528,23 +1641,18 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
 
   Statement* result = NULL;
   ZoneList<const AstRawString*> names(1, zone());
-  bool is_export_from = false;
   switch (peek()) {
     case Token::DEFAULT:
-      Consume(Token::DEFAULT);
       return ParseExportDefault(ok);
 
     case Token::MUL: {
       Consume(Token::MUL);
       ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
-      Literal* module = ParseModuleSpecifier(CHECK_OK);
+      const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
       ExpectSemicolon(CHECK_OK);
-      // TODO(ES6): Do something with the return value
-      // of ParseModuleSpecifier.
-      USE(module);
-      is_export_from = true;
-      result = factory()->NewEmptyStatement(pos);
-      break;
+      // TODO(ES6): scope_->module()->AddStarExport(...)
+      USE(module_specifier);
+      return factory()->NewEmptyStatement(pos);
     }
 
     case Token::LBRACE: {
@@ -1560,13 +1668,14 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
       // encountered, and then throw a SyntaxError if we are in the
       // non-FromClause case.
       Scanner::Location reserved_loc = Scanner::Location::invalid();
-      ParseExportClause(&names, &reserved_loc, CHECK_OK);
+      ZoneList<const AstRawString*> export_names(1, zone());
+      ZoneList<Scanner::Location> export_locations(1, zone());
+      ZoneList<const AstRawString*> local_names(1, zone());
+      ParseExportClause(&export_names, &export_locations, &local_names,
+                        &reserved_loc, CHECK_OK);
+      const AstRawString* indirect_export_module_specifier = NULL;
       if (CheckContextualKeyword(CStrVector("from"))) {
-        Literal* module = ParseModuleSpecifier(CHECK_OK);
-        // TODO(ES6): Do something with the return value
-        // of ParseModuleSpecifier.
-        USE(module);
-        is_export_from = true;
+        indirect_export_module_specifier = ParseModuleSpecifier(CHECK_OK);
       } else if (reserved_loc.IsValid()) {
         // No FromClause, so reserved words are invalid in ExportClause.
         *ok = false;
@@ -1574,8 +1683,25 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
         return NULL;
       }
       ExpectSemicolon(CHECK_OK);
-      result = factory()->NewEmptyStatement(pos);
-      break;
+      const int length = export_names.length();
+      DCHECK_EQ(length, local_names.length());
+      DCHECK_EQ(length, export_locations.length());
+      if (indirect_export_module_specifier == NULL) {
+        for (int i = 0; i < length; ++i) {
+          scope_->module()->AddLocalExport(export_names[i], local_names[i],
+                                           zone(), ok);
+          if (!*ok) {
+            ParserTraits::ReportMessageAt(export_locations[i],
+                                          "duplicate_export", export_names[i]);
+            return NULL;
+          }
+        }
+      } else {
+        for (int i = 0; i < length; ++i) {
+          // TODO(ES6): scope_->module()->AddIndirectExport(...);(
+        }
+      }
+      return factory()->NewEmptyStatement(pos);
     }
 
     case Token::FUNCTION:
@@ -1598,37 +1724,18 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
       return NULL;
   }
 
-  // Every export of a module may be assigned.
+  // Extract declared names into export declarations.
+  ModuleDescriptor* descriptor = scope_->module();
   for (int i = 0; i < names.length(); ++i) {
-    Variable* var = scope_->Lookup(names[i]);
-    if (var == NULL) {
-      // TODO(sigurds) This is an export that has no definition yet,
-      // not clear what to do in this case.
-      continue;
-    }
-    if (!IsImmutableVariableMode(var->mode())) {
-      var->set_maybe_assigned();
-    }
-  }
-
-  // TODO(ES6): Handle 'export from' once imports are properly implemented.
-  // For now we just drop such exports on the floor.
-  if (!is_export_from) {
-    // Extract declared names into export declarations and module descriptor.
-    ModuleDescriptor* descriptor = scope_->module();
-    for (int i = 0; i < names.length(); ++i) {
-      // TODO(adamk): Make early errors here provide the right error message
-      // (duplicate exported names).
-      descriptor->Add(names[i], zone(), CHECK_OK);
-      // TODO(rossberg): Rethink whether we actually need to store export
-      // declarations (for compilation?).
-      // ExportDeclaration* declaration =
-      //     factory()->NewExportDeclaration(proxy, scope_, position);
-      // scope_->AddDeclaration(declaration);
+    descriptor->AddLocalExport(names[i], names[i], zone(), ok);
+    if (!*ok) {
+      // TODO(adamk): Possibly report this error at the right place.
+      ParserTraits::ReportMessage("duplicate_export", names[i]);
+      return NULL;
     }
   }
 
-  DCHECK(result != NULL);
+  DCHECK_NOT_NULL(result);
   return result;
 }
 
@@ -1777,11 +1884,13 @@ VariableProxy* Parser::NewUnresolved(const AstRawString* name,
   // scope.
   // Let/const variables in harmony mode are always added to the immediately
   // enclosing scope.
-  return DeclarationScope(mode)->NewUnresolved(factory(), name, position());
+  return DeclarationScope(mode)->NewUnresolved(factory(), name,
+                                               scanner()->location().beg_pos,
+                                               scanner()->location().end_pos);
 }
 
 
-void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
+Variable* Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
   VariableProxy* proxy = declaration->proxy();
   DCHECK(proxy->raw_name() != NULL);
   const AstRawString* name = proxy->raw_name();
@@ -1807,10 +1916,14 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
     if (var == NULL) {
       // Declare the name.
       var = declaration_scope->DeclareLocal(
-          name, mode, declaration->initialization(), kNotAssigned);
-    } else if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(var->mode())
-               || ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) &&
-                   !declaration_scope->is_script_scope())) {
+          name, mode, declaration->initialization(),
+          declaration->IsFunctionDeclaration() ? Variable::FUNCTION
+                                               : Variable::NORMAL,
+          kNotAssigned);
+    } else if (IsLexicalVariableMode(mode) ||
+               IsLexicalVariableMode(var->mode()) ||
+               ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) &&
+                !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 script scope, we also have to ignore legacy const for
@@ -1825,12 +1938,12 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
       // because the var declaration is hoisted to the function scope where 'x'
       // is already bound.
       DCHECK(IsDeclaredVariableMode(var->mode()));
-      if (allow_harmony_scoping() && is_strict(language_mode())) {
+      if (is_strict(language_mode())) {
         // In harmony we treat re-declarations as early errors. See
         // ES5 16 for a definition of early errors.
         ParserTraits::ReportMessage("var_redeclaration", name);
         *ok = false;
-        return;
+        return nullptr;
       }
       Expression* expression = NewThrowTypeError(
           "var_redeclaration", name, declaration->position());
@@ -1862,7 +1975,7 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
     // For global const variables we bind the proxy to a variable.
     DCHECK(resolve);  // should be set by all callers
     Variable::Kind kind = Variable::NORMAL;
-    var = new (zone()) Variable(declaration_scope, name, mode, true, kind,
+    var = new (zone()) Variable(declaration_scope, name, mode, kind,
                                 kNeedsInitialization, kNotAssigned);
   } else if (declaration_scope->is_eval_scope() &&
              is_sloppy(declaration_scope->language_mode())) {
@@ -1871,7 +1984,7 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
     // DeclareLookupSlot runtime function.
     Variable::Kind kind = Variable::NORMAL;
     // TODO(sigurds) figure out if kNotAssigned is OK here
-    var = new (zone()) Variable(declaration_scope, name, mode, true, kind,
+    var = new (zone()) Variable(declaration_scope, name, mode, kind,
                                 declaration->initialization(), kNotAssigned);
     var->AllocateTo(Variable::LOOKUP, -1);
     resolve = true;
@@ -1904,6 +2017,7 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
   if (resolve && var != NULL) {
     proxy->BindTo(var);
   }
+  return var;
 }
 
 
@@ -1975,12 +2089,13 @@ Statement* Parser::ParseFunctionDeclaration(
   // 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 =
-      is_strong(language_mode()) ? CONST :
-      allow_harmony_scoping() && is_strict(language_mode()) &&
-              !(scope_->is_script_scope() || scope_->is_eval_scope() ||
-                scope_->is_function_scope())
-          ? LET
-          : VAR;
+      is_strong(language_mode())
+          ? CONST
+          : is_strict(language_mode()) &&
+                    !(scope_->is_script_scope() || scope_->is_eval_scope() ||
+                      scope_->is_function_scope())
+                ? LET
+                : VAR;
   VariableProxy* proxy = NewUnresolved(name, mode);
   Declaration* declaration =
       factory()->NewFunctionDeclaration(proxy, mode, fun, scope_, pos);
@@ -2024,7 +2139,7 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
   Declaration* declaration =
       factory()->NewVariableDeclaration(proxy, mode, scope_, pos);
   Declare(declaration, true, CHECK_OK);
-  proxy->var()->set_initializer_position(pos);
+  proxy->var()->set_initializer_position(position());
 
   Token::Value init_op =
       is_strong(language_mode()) ? Token::INIT_CONST : Token::INIT_LET;
@@ -2037,7 +2152,7 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
 
 
 Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) {
-  if (allow_harmony_scoping() && is_strict(language_mode())) {
+  if (is_strict(language_mode())) {
     return ParseScopedBlock(labels, ok);
   }
 
@@ -2159,19 +2274,12 @@ Block* Parser::ParseVariableDeclarations(
       init_op = Token::INIT_CONST_LEGACY;
     } else {
       DCHECK(var_context != kStatement);
-      // In ES5 const is not allowed in strict mode.
-      if (!allow_harmony_scoping()) {
-        ReportMessage("strict_const");
-        *ok = false;
-        return NULL;
-      }
       mode = CONST;
       init_op = Token::INIT_CONST;
     }
     is_const = true;
     needs_init = true;
   } else if (peek() == Token::LET && is_strict(language_mode())) {
-    DCHECK(allow_harmony_scoping());
     Consume(Token::LET);
     DCHECK(var_context != kStatement);
     mode = LET;
@@ -2233,7 +2341,9 @@ Block* Parser::ParseVariableDeclarations(
     VariableProxy* proxy = NewUnresolved(name, mode);
     Declaration* declaration =
         factory()->NewVariableDeclaration(proxy, mode, scope_, pos);
-    Declare(declaration, mode != VAR, CHECK_OK);
+    Variable* var = Declare(declaration, mode != VAR, CHECK_OK);
+    DCHECK_NOT_NULL(var);
+    DCHECK(!proxy->is_resolved() || proxy->var() == var);
     nvars++;
     if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
       ReportMessage("too_many_variables");
@@ -2287,11 +2397,11 @@ Block* Parser::ParseVariableDeclarations(
         fni_->RemoveLastFunction();
       }
       if (decl_props != NULL) *decl_props = kHasInitializers;
-    }
-
-    // Record the end position of the initializer.
-    if (proxy->is_resolved()) {
-      proxy->var()->set_initializer_position(position());
+      // End position of the initializer is after the assignment expression.
+      var->set_initializer_position(scanner()->location().end_pos);
+    } else {
+      // End position of the initializer is after the variable.
+      var->set_initializer_position(position());
     }
 
     // Make sure that 'const x' and 'let x' initialize 'x' to undefined.
@@ -2610,6 +2720,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
   // reported (underlining).
   Expect(Token::RETURN, CHECK_OK);
   Scanner::Location loc = scanner()->location();
+  function_state_->set_return_location(loc);
 
   Token::Value tok = peek();
   Statement* result;
@@ -2624,6 +2735,14 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
       return_value = GetLiteralUndefined(position());
     }
   } else {
+    if (is_strong(language_mode()) &&
+        i::IsConstructor(function_state_->kind())) {
+      int pos = peek_position();
+      ReportMessageAt(Scanner::Location(pos, pos + 1),
+                      "strong_constructor_return_value");
+      *ok = false;
+      return NULL;
+    }
     return_value = ParseExpression(true, CHECK_OK);
   }
   ExpectSemicolon(CHECK_OK);
@@ -2680,8 +2799,8 @@ Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels,
 
 CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
   // CaseClause ::
-  //   'case' Expression ':' Statement*
-  //   'default' ':' Statement*
+  //   'case' Expression ':' StatementList
+  //   'default' ':' StatementList
 
   Expression* label = NULL;  // NULL expression indicates default case
   if (peek() == Token::CASE) {
@@ -2703,7 +2822,7 @@ CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
   while (peek() != Token::CASE &&
          peek() != Token::DEFAULT &&
          peek() != Token::RBRACE) {
-    Statement* stat = ParseStatement(NULL, CHECK_OK);
+    Statement* stat = ParseStatementListItem(CHECK_OK);
     statements->Add(stat, zone());
   }
 
@@ -2796,7 +2915,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
 
     Expect(Token::RPAREN, CHECK_OK);
 
-    catch_variable = catch_scope->DeclareLocal(name, VAR, kCreatedInitialized);
+    catch_variable = catch_scope->DeclareLocal(name, VAR, kCreatedInitialized,
+                                               Variable::NORMAL);
     BlockState block_state(&scope_, catch_scope);
     catch_block = ParseBlock(NULL, CHECK_OK);
 
@@ -2910,25 +3030,51 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
     Expression* result_done;
     Expression* assign_each;
 
-    // var iterator = subject[Symbol.iterator]();
+    // iterator = subject[Symbol.iterator]()
     assign_iterator = factory()->NewAssignment(
         Token::ASSIGN, factory()->NewVariableProxy(iterator),
         GetIterator(subject, factory()), subject->position());
 
-    // var result = iterator.next();
+    // !%_IsSpecObject(result = iterator.next()) &&
+    //     %ThrowIteratorResultNotAnObject(result)
     {
+      // result = iterator.next()
       Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
       Expression* next_literal = factory()->NewStringLiteral(
           ast_value_factory()->next_string(), RelocInfo::kNoPosition);
       Expression* next_property = factory()->NewProperty(
           iterator_proxy, next_literal, RelocInfo::kNoPosition);
       ZoneList<Expression*>* next_arguments =
-          new(zone()) ZoneList<Expression*>(0, zone());
+          new (zone()) ZoneList<Expression*>(0, zone());
       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, subject->position());
+
+      // %_IsSpecObject(...)
+      ZoneList<Expression*>* is_spec_object_args =
+          new (zone()) ZoneList<Expression*>(1, zone());
+      is_spec_object_args->Add(next_result, zone());
+      Expression* is_spec_object_call = factory()->NewCallRuntime(
+          ast_value_factory()->is_spec_object_string(),
+          Runtime::FunctionForId(Runtime::kInlineIsSpecObject),
+          is_spec_object_args, subject->position());
+
+      // %ThrowIteratorResultNotAnObject(result)
+      Expression* result_proxy_again = factory()->NewVariableProxy(result);
+      ZoneList<Expression*>* throw_arguments =
+          new (zone()) ZoneList<Expression*>(1, zone());
+      throw_arguments->Add(result_proxy_again, zone());
+      Expression* throw_call = factory()->NewCallRuntime(
+          ast_value_factory()->throw_iterator_result_not_an_object_string(),
+          Runtime::FunctionForId(Runtime::kThrowIteratorResultNotAnObject),
+          throw_arguments, subject->position());
+
+      next_result = factory()->NewBinaryOperation(
+          Token::AND, factory()->NewUnaryOperation(
+                          Token::NOT, is_spec_object_call, subject->position()),
+          throw_call, subject->position());
     }
 
     // result.done
@@ -2962,8 +3108,8 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
 }
 
 
-Statement* Parser::DesugarLetBindingsInForStatement(
-    Scope* inner_scope, ZoneList<const AstRawString*>* names,
+Statement* Parser::DesugarLexicalBindingsInForStatement(
+    Scope* inner_scope, bool is_const, ZoneList<const AstRawString*>* names,
     ForStatement* loop, Statement* init, Expression* cond, Statement* next,
     Statement* body, bool* ok) {
   // ES6 13.6.3.4 specifies that on each loop iteration the let variables are
@@ -2973,16 +3119,16 @@ Statement* Parser::DesugarLetBindingsInForStatement(
   //
   // We rewrite a for statement of the form
   //
-  //  labels: for (let x = i; cond; next) body
+  //  labels: for (let/const x = i; cond; next) body
   //
   // into
   //
   //  {
-  //    let x = i;
+  //    let/const x = i;
   //    temp_x = x;
   //    first = 1;
   //    outer: for (;;) {
-  //      let x = temp_x;
+  //      let/const x = temp_x;
   //      if (first == 1) {
   //        first = 0;
   //      } else {
@@ -3009,12 +3155,12 @@ Statement* Parser::DesugarLetBindingsInForStatement(
   Block* outer_block = factory()->NewBlock(NULL, names->length() + 3, false,
                                            RelocInfo::kNoPosition);
 
-  // Add statement: let x = i.
+  // Add statement: let/const x = i.
   outer_block->AddStatement(init, zone());
 
   const AstRawString* temp_name = ast_value_factory()->dot_for_string();
 
-  // For each let variable x:
+  // For each lexical variable x:
   //   make statement: temp_x = x.
   for (int i = 0; i < names->length(); i++) {
     VariableProxy* proxy = NewUnresolved(names->at(i), LET);
@@ -3055,23 +3201,24 @@ Statement* Parser::DesugarLetBindingsInForStatement(
 
   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());
 
   // For each let variable x:
-  //    make statement: let x = temp_x.
+  //    make statement: let/const x = temp_x.
+  VariableMode mode = is_const ? CONST : LET;
   for (int i = 0; i < names->length(); i++) {
-    VariableProxy* proxy = NewUnresolved(names->at(i), LET);
-    Declaration* declaration =
-        factory()->NewVariableDeclaration(proxy, LET, scope_, pos);
+    VariableProxy* proxy = NewUnresolved(names->at(i), mode);
+    Declaration* declaration = factory()->NewVariableDeclaration(
+        proxy, mode, scope_, RelocInfo::kNoPosition);
     Declare(declaration, true, CHECK_OK);
     inner_vars.Add(declaration->proxy()->var(), zone());
     VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
-    Assignment* assignment = factory()->NewAssignment(
-        Token::INIT_LET, proxy, temp_proxy, pos);
-    Statement* assignment_statement = factory()->NewExpressionStatement(
-        assignment, pos);
-    proxy->var()->set_initializer_position(pos);
+    Assignment* assignment =
+        factory()->NewAssignment(is_const ? Token::INIT_CONST : Token::INIT_LET,
+                                 proxy, temp_proxy, RelocInfo::kNoPosition);
+    Statement* assignment_statement =
+        factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+    proxy->var()->set_initializer_position(init->position());
     inner_block->AddStatement(assignment_statement, zone());
   }
 
@@ -3083,8 +3230,8 @@ Statement* Parser::DesugarLetBindingsInForStatement(
     {
       Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
       VariableProxy* first_proxy = factory()->NewVariableProxy(first);
-      compare =
-          factory()->NewCompareOperation(Token::EQ, first_proxy, const1, pos);
+      compare = factory()->NewCompareOperation(Token::EQ, first_proxy, const1,
+                                               RelocInfo::kNoPosition);
     }
     Statement* clear_first = NULL;
     // Make statement: first = 0.
@@ -3096,8 +3243,8 @@ Statement* Parser::DesugarLetBindingsInForStatement(
       clear_first =
           factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
     }
-    Statement* clear_first_or_next = factory()->NewIfStatement(
-        compare, clear_first, next, RelocInfo::kNoPosition);
+    Statement* clear_first_or_next =
+        factory()->NewIfStatement(compare, clear_first, next, next->position());
     inner_block->AddStatement(clear_first_or_next, zone());
   }
 
@@ -3118,8 +3265,8 @@ Statement* Parser::DesugarLetBindingsInForStatement(
   {
     Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
     VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
-    flag_cond =
-        factory()->NewCompareOperation(Token::EQ, flag_proxy, const1, pos);
+    flag_cond = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
+                                               RelocInfo::kNoPosition);
   }
 
   // Create chain of expressions "flag = 0, temp_x = x, ..."
@@ -3135,9 +3282,11 @@ Statement* Parser::DesugarLetBindingsInForStatement(
     }
 
     // Make the comma-separated list of temp_x = x assignments.
+    int inner_var_proxy_pos = scanner()->location().beg_pos;
     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);
+      VariableProxy* proxy =
+          factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos);
       Assignment* assignment = factory()->NewAssignment(
           Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
       compound_next = factory()->NewBinaryOperation(
@@ -3171,8 +3320,8 @@ Statement* Parser::DesugarLetBindingsInForStatement(
     {
       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,
+                                               RelocInfo::kNoPosition);
     }
     Statement* stop =
         factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
@@ -3197,8 +3346,9 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
   //   'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
 
   int stmt_pos = peek_position();
+  bool is_const = false;
   Statement* init = NULL;
-  ZoneList<const AstRawString*> let_bindings(1, zone());
+  ZoneList<const AstRawString*> lexical_bindings(1, zone());
 
   // Create an in-between scope for let-bound iteration variables.
   Scope* saved_scope = scope_;
@@ -3219,7 +3369,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
                                     CHECK_OK);
       bool accept_OF = decl_props == kHasNoInitializers;
       ForEachStatement::VisitMode mode;
-      int each_pos = position();
+      int each_beg_pos = scanner()->location().beg_pos;
+      int each_end_pos = scanner()->location().end_pos;
 
       if (name != NULL && CheckInOrOf(accept_OF, &mode, ok)) {
         if (!*ok) return nullptr;
@@ -3230,7 +3381,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
         Expression* enumerable = ParseExpression(true, CHECK_OK);
         Expect(Token::RPAREN, CHECK_OK);
 
-        VariableProxy* each = scope_->NewUnresolved(factory(), name, each_pos);
+        VariableProxy* each =
+            scope_->NewUnresolved(factory(), name, each_beg_pos, each_end_pos);
         Statement* body = ParseSubStatement(NULL, CHECK_OK);
         InitializeForEachStatement(loop, each, enumerable, body);
         Block* result =
@@ -3248,16 +3400,17 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
       }
     } else if ((peek() == Token::LET || peek() == Token::CONST) &&
                is_strict(language_mode())) {
-      bool is_const = peek() == Token::CONST;
+      is_const = peek() == Token::CONST;
       const AstRawString* name = NULL;
       VariableDeclarationProperties decl_props = kHasNoInitializers;
       Block* variable_statement =
-          ParseVariableDeclarations(kForStatement, &decl_props, &let_bindings,
-                                    &name, CHECK_OK);
+          ParseVariableDeclarations(kForStatement, &decl_props,
+                                    &lexical_bindings, &name, CHECK_OK);
       bool accept_IN = name != NULL && decl_props != kHasInitializers;
       bool accept_OF = decl_props == kHasNoInitializers;
       ForEachStatement::VisitMode mode;
-      int each_pos = position();
+      int each_beg_pos = scanner()->location().beg_pos;
+      int each_end_pos = scanner()->location().end_pos;
 
       if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) {
         if (!*ok) return nullptr;
@@ -3279,7 +3432,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
         // implementing stack allocated block scoped variables.
         Variable* temp = scope_->DeclarationScope()->NewTemporary(
             ast_value_factory()->dot_for_string());
-        VariableProxy* temp_proxy = factory()->NewVariableProxy(temp, each_pos);
+        VariableProxy* temp_proxy =
+            factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos);
         ForEachStatement* loop =
             factory()->NewForEachStatement(mode, labels, stmt_pos);
         Target target(&this->target_stack_, loop);
@@ -3290,7 +3444,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
         scope_ = for_scope;
         Expect(Token::RPAREN, CHECK_OK);
 
-        VariableProxy* each = scope_->NewUnresolved(factory(), name, each_pos);
+        VariableProxy* each =
+            scope_->NewUnresolved(factory(), name, each_beg_pos, each_end_pos);
         Statement* body = ParseSubStatement(NULL, CHECK_OK);
         Block* body_block =
             factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
@@ -3367,7 +3522,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
   // If there are let bindings, then condition and the next statement of the
   // for loop must be parsed in a new scope.
   Scope* inner_scope = NULL;
-  if (let_bindings.length() > 0) {
+  if (lexical_bindings.length() > 0) {
     inner_scope = NewScope(for_scope, BLOCK_SCOPE);
     inner_scope->set_start_position(scanner()->location().beg_pos);
     scope_ = inner_scope;
@@ -3390,10 +3545,11 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
   Statement* body = ParseSubStatement(NULL, CHECK_OK);
 
   Statement* result = NULL;
-  if (let_bindings.length() > 0) {
+  if (lexical_bindings.length() > 0) {
     scope_ = for_scope;
-    result = DesugarLetBindingsInForStatement(inner_scope, &let_bindings, loop,
-                                              init, cond, next, body, CHECK_OK);
+    result = DesugarLexicalBindingsInForStatement(
+                 inner_scope, is_const, &lexical_bindings, loop, init, cond,
+                 next, body, CHECK_OK);
     scope_ = saved_scope;
     for_scope->set_end_position(scanner()->location().end_pos);
   } else {
@@ -3512,6 +3668,10 @@ bool CheckAndDeclareArrowParameter(ParserTraits* traits, Expression* expression,
       return false;
     }
 
+    // When the variable was seen, it was recorded as unresolved in the outer
+    // scope. But it's really not unresolved.
+    scope->outer_scope()->RemoveUnresolved(expression->AsVariableProxy());
+
     scope->DeclareParameter(raw_name, VAR);
     ++(*num_params);
     return true;
@@ -3609,13 +3769,12 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
   //   nested function, and hoisting works normally relative to that.
   Scope* declaration_scope = scope_->DeclarationScope();
   Scope* original_declaration_scope = original_scope_->DeclarationScope();
-  Scope* scope =
-      function_type == FunctionLiteral::DECLARATION &&
-              (!allow_harmony_scoping() || is_sloppy(language_mode())) &&
-              (original_scope_ == original_declaration_scope ||
-               declaration_scope != original_declaration_scope)
-          ? NewScope(declaration_scope, FUNCTION_SCOPE, kind)
-          : NewScope(scope_, FUNCTION_SCOPE, kind);
+  Scope* scope = function_type == FunctionLiteral::DECLARATION &&
+                         is_sloppy(language_mode()) &&
+                         (original_scope_ == original_declaration_scope ||
+                          declaration_scope != original_declaration_scope)
+                     ? NewScope(declaration_scope, FUNCTION_SCOPE, kind)
+                     : NewScope(scope_, FUNCTION_SCOPE, kind);
   ZoneList<Statement*>* body = NULL;
   int materialized_literal_count = -1;
   int expected_property_count = -1;
@@ -3723,16 +3882,15 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
     Variable* fvar = NULL;
     Token::Value fvar_init_op = Token::INIT_CONST_LEGACY;
     if (function_type == FunctionLiteral::NAMED_EXPRESSION) {
-      if (allow_harmony_scoping() && is_strict(language_mode())) {
+      if (is_strict(language_mode())) {
         fvar_init_op = Token::INIT_CONST;
       }
       VariableMode fvar_mode =
-          allow_harmony_scoping() && is_strict(language_mode()) ? CONST
-                                                                : CONST_LEGACY;
+          is_strict(language_mode()) ? CONST : CONST_LEGACY;
       DCHECK(function_name != NULL);
       fvar = new (zone())
-          Variable(scope_, function_name, fvar_mode, true /* is valid LHS */,
-                   Variable::NORMAL, kCreatedInitialized, kNotAssigned);
+          Variable(scope_, function_name, fvar_mode, Variable::NORMAL,
+                   kCreatedInitialized, kNotAssigned);
       VariableProxy* proxy = factory()->NewVariableProxy(fvar);
       VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration(
           proxy, fvar_mode, scope_, RelocInfo::kNoPosition);
@@ -3802,9 +3960,17 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
       CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
                               CHECK_OK);
     }
-    if (allow_harmony_scoping() && is_strict(language_mode())) {
+    if (is_strict(language_mode())) {
       CheckConflictingVarDeclarations(scope, CHECK_OK);
     }
+    if (is_strong(language_mode()) && IsSubclassConstructor(kind)) {
+      if (!function_state.super_call_location().IsValid()) {
+        ReportMessageAt(function_name_location, "strong_super_call_missing",
+                        kReferenceError);
+        *ok = false;
+        return nullptr;
+      }
+    }
   }
 
   FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
@@ -3870,7 +4036,7 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name,
   if (logger.has_error()) {
     ParserTraits::ReportMessageAt(
         Scanner::Location(logger.start(), logger.end()), logger.message(),
-        logger.argument_opt(), logger.is_reference_error());
+        logger.argument_opt(), logger.error_type());
     *ok = false;
     return;
   }
@@ -4002,7 +4168,6 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
                                         NULL, stack_limit_);
     reusable_preparser_->set_allow_lazy(true);
     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());
@@ -4011,7 +4176,6 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
     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());
     reusable_preparser_->set_allow_harmony_computed_property_names(
@@ -4045,7 +4209,11 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
     return NULL;
   }
 
+  // Create a block scope which is additionally tagged as class scope; this is
+  // important for resolving variable references to the class name in the strong
+  // mode.
   Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
+  block_scope->tag_as_class_scope();
   BlockState block_state(&scope_, block_scope);
   scope_->SetLanguageMode(
       static_cast<LanguageMode>(scope_->language_mode() | STRICT_BIT));
@@ -4074,6 +4242,7 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
   bool has_seen_constructor = false;
 
   Expect(Token::LBRACE, CHECK_OK);
+
   const bool has_extends = extends != nullptr;
   while (peek() != Token::RBRACE) {
     if (Check(Token::SEMICOLON)) continue;
@@ -4108,12 +4277,14 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
   }
 
   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);
+  } else {
+    // Unnamed classes should not have scopes (the scope will be empty).
+    DCHECK_EQ(block_scope->num_var_or_const(), 0);
+    block_scope = nullptr;
   }
 
   return factory()->NewClassLiteral(name, block_scope, proxy, extends,
@@ -4239,79 +4410,30 @@ IterationStatement* Parser::LookupContinueTarget(const AstRawString* label,
 }
 
 
-void Parser::HandleSourceURLComments(CompilationInfo* info) {
+void Parser::HandleSourceURLComments(Isolate* isolate, Handle<Script> script) {
   if (scanner_.source_url()->length() > 0) {
-    Handle<String> source_url =
-        scanner_.source_url()->Internalize(info->isolate());
-    info->script()->set_source_url(*source_url);
+    Handle<String> source_url = scanner_.source_url()->Internalize(isolate);
+    script->set_source_url(*source_url);
   }
   if (scanner_.source_mapping_url()->length() > 0) {
     Handle<String> source_mapping_url =
-        scanner_.source_mapping_url()->Internalize(info->isolate());
-    info->script()->set_source_mapping_url(*source_mapping_url);
+        scanner_.source_mapping_url()->Internalize(isolate);
+    script->set_source_mapping_url(*source_mapping_url);
   }
 }
 
 
-void Parser::ThrowPendingError(Isolate* isolate, Handle<Script> script) {
-  DCHECK(ast_value_factory()->IsInternalized());
-  if (has_pending_error_) {
-    MessageLocation location(script, pending_error_location_.beg_pos,
-                             pending_error_location_.end_pos);
-    Factory* factory = isolate->factory();
-    bool has_arg =
-        pending_error_arg_ != NULL || pending_error_char_arg_ != NULL;
-    Handle<FixedArray> elements = factory->NewFixedArray(has_arg ? 1 : 0);
-    if (pending_error_arg_ != NULL) {
-      Handle<String> arg_string = pending_error_arg_->string();
-      elements->set(0, *arg_string);
-    } else if (pending_error_char_arg_ != NULL) {
-      Handle<String> arg_string =
-          factory->NewStringFromUtf8(CStrVector(pending_error_char_arg_))
-          .ToHandleChecked();
-      elements->set(0, *arg_string);
-    }
-    isolate->debug()->OnCompileError(script);
-
-    Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
-    Handle<Object> error;
-    MaybeHandle<Object> maybe_error =
-        pending_error_is_reference_error_
-            ? factory->NewReferenceError(pending_error_message_, array)
-            : factory->NewSyntaxError(pending_error_message_, array);
-
-    if (maybe_error.ToHandle(&error)) {
-      Handle<JSObject> jserror = Handle<JSObject>::cast(error);
-
-      Handle<Name> key_start_pos = factory->error_start_pos_symbol();
-      JSObject::SetProperty(jserror, key_start_pos,
-                            handle(Smi::FromInt(location.start_pos()), isolate),
-                            SLOPPY).Check();
-
-      Handle<Name> key_end_pos = factory->error_end_pos_symbol();
-      JSObject::SetProperty(jserror, key_end_pos,
-                            handle(Smi::FromInt(location.end_pos()), isolate),
-                            SLOPPY).Check();
-
-      Handle<Name> key_script = factory->error_script_symbol();
-      JSObject::SetProperty(jserror, key_script, script, SLOPPY).Check();
-
-      isolate->Throw(*error, &location);
-    }
-  }
-}
-
-
-void Parser::Internalize(CompilationInfo* info) {
+void Parser::Internalize(Isolate* isolate, Handle<Script> script, bool error) {
   // Internalize strings.
-  ast_value_factory()->Internalize(info->isolate());
+  ast_value_factory()->Internalize(isolate);
 
   // Error processing.
-  if (info->function() == NULL) {
+  if (error) {
     if (stack_overflow()) {
-      info->isolate()->StackOverflow();
+      isolate->StackOverflow();
     } else {
-      ThrowPendingError(info->isolate(), info->script());
+      DCHECK(pending_error_handler_.has_pending_error());
+      pending_error_handler_.ThrowPendingError(isolate, script);
     }
   }
 
@@ -4319,10 +4441,10 @@ void Parser::Internalize(CompilationInfo* info) {
   for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
        ++feature) {
     for (int i = 0; i < use_counts_[feature]; ++i) {
-      info->isolate()->CountUsage(v8::Isolate::UseCounterFeature(feature));
+      isolate->CountUsage(v8::Isolate::UseCounterFeature(feature));
     }
   }
-  info->isolate()->counters()->total_preparse_skipped()->Increment(
+  isolate->counters()->total_preparse_skipped()->Increment(
       total_preparse_skipped_);
 }
 
@@ -5240,20 +5362,17 @@ bool RegExpParser::ParseRegExp(Isolate* isolate, Zone* zone,
 }
 
 
-bool Parser::ParseStatic(CompilationInfo* info, bool allow_lazy) {
-  Parser parser(info, info->isolate()->stack_guard()->real_climit(),
-                info->isolate()->heap()->HashSeed(),
-                info->isolate()->unicode_cache());
-  parser.set_allow_lazy(allow_lazy);
+bool Parser::ParseStatic(ParseInfo* info) {
+  Parser parser(info);
   if (parser.Parse(info)) {
-    info->SetLanguageMode(info->function()->language_mode());
+    info->set_language_mode(info->function()->language_mode());
     return true;
   }
   return false;
 }
 
 
-bool Parser::Parse(CompilationInfo* info) {
+bool Parser::Parse(ParseInfo* info) {
   DCHECK(info->function() == NULL);
   FunctionLiteral* result = NULL;
   // Ok to use Isolate here; this function is only called in the main thread.
@@ -5270,23 +5389,23 @@ bool Parser::Parse(CompilationInfo* info) {
   if (info->is_lazy()) {
     DCHECK(!info->is_eval());
     if (info->shared_info()->is_function()) {
-      result = ParseLazy(info);
+      result = ParseLazy(isolate, info);
     } else {
-      result = ParseProgram(info);
+      result = ParseProgram(isolate, info);
     }
   } else {
     SetCachedData(info);
-    result = ParseProgram(info);
+    result = ParseProgram(isolate, info);
   }
-  info->SetFunction(result);
+  info->set_literal(result);
 
-  Internalize(info);
+  Internalize(isolate, info->script(), result == NULL);
   DCHECK(ast_value_factory()->IsInternalized());
   return (result != NULL);
 }
 
 
-void Parser::ParseOnBackground(CompilationInfo* info) {
+void Parser::ParseOnBackground(ParseInfo* info) {
   parsing_on_main_thread_ = false;
 
   DCHECK(info->function() == NULL);
@@ -5317,7 +5436,7 @@ void Parser::ParseOnBackground(CompilationInfo* info) {
     eval_scope->set_end_position(scanner()->location().end_pos);
   }
 
-  info->SetFunction(result);
+  info->set_literal(result);
 
   // We cannot internalize on a background thread; a foreground task will take
   // care of calling Parser::Internalize just before compilation.
@@ -5363,27 +5482,24 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start,
 
   if (!tag) {
     // Build tree of BinaryOps to simplify code-generation
-    Expression* expr = NULL;
+    Expression* expr = cooked_strings->at(0);
+    int i = 0;
+    while (i < expressions->length()) {
+      Expression* sub = expressions->at(i++);
+      Expression* cooked_str = cooked_strings->at(i);
+
+      // Let middle be ToString(sub).
+      ZoneList<Expression*>* args =
+          new (zone()) ZoneList<Expression*>(1, zone());
+      args->Add(sub, zone());
+      Expression* middle = factory()->NewCallRuntime(
+          ast_value_factory()->to_string_string(), NULL, args,
+          sub->position());
 
-    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());
+          Token::ADD, factory()->NewBinaryOperation(
+                          Token::ADD, expr, middle, expr->position()),
+          cooked_str, sub->position());
     }
     return expr;
   } else {
index 713133a..d93faaf 100644 (file)
 
 #include "src/allocation.h"
 #include "src/ast.h"
-#include "src/compiler.h"  // For CachedDataMode
+#include "src/compiler.h"  // TODO(titzer): remove this include dependency
+#include "src/pending-compilation-error-handler.h"
 #include "src/preparse-data.h"
 #include "src/preparse-data-format.h"
 #include "src/preparser.h"
 #include "src/scopes.h"
 
 namespace v8 {
+
 class ScriptCompiler;
 
 namespace internal {
 
-class CompilationInfo;
-class ParserLog;
-class PositionStack;
 class Target;
 
+// A container for the inputs, configuration options, and outputs of parsing.
+class ParseInfo {
+ public:
+  explicit ParseInfo(Zone* zone);
+  ParseInfo(Zone* zone, Handle<JSFunction> function);
+  ParseInfo(Zone* zone, Handle<Script> script);
+  // TODO(all) Only used via Debug::FindSharedFunctionInfoInScript, remove?
+  ParseInfo(Zone* zone, Handle<SharedFunctionInfo> shared);
+
+  ~ParseInfo() {
+    if (ast_value_factory_owned()) {
+      delete ast_value_factory_;
+      set_ast_value_factory_owned(false);
+    }
+    ast_value_factory_ = nullptr;
+  }
+
+  Zone* zone() { return zone_; }
+
+// Convenience accessor methods for flags.
+#define FLAG_ACCESSOR(flag, getter, setter)     \
+  bool getter() const { return GetFlag(flag); } \
+  void setter() { SetFlag(flag); }              \
+  void setter(bool val) { SetFlag(flag, val); }
+
+  FLAG_ACCESSOR(kToplevel, is_toplevel, set_toplevel)
+  FLAG_ACCESSOR(kLazy, is_lazy, set_lazy)
+  FLAG_ACCESSOR(kEval, is_eval, set_eval)
+  FLAG_ACCESSOR(kGlobal, is_global, set_global)
+  FLAG_ACCESSOR(kStrictMode, is_strict_mode, set_strict_mode)
+  FLAG_ACCESSOR(kStrongMode, is_strong_mode, set_strong_mode)
+  FLAG_ACCESSOR(kNative, is_native, set_native)
+  FLAG_ACCESSOR(kModule, is_module, set_module)
+  FLAG_ACCESSOR(kAllowLazyParsing, allow_lazy_parsing, set_allow_lazy_parsing)
+  FLAG_ACCESSOR(kAstValueFactoryOwned, ast_value_factory_owned,
+                set_ast_value_factory_owned)
+
+#undef FLAG_ACCESSOR
+
+  void set_parse_restriction(ParseRestriction restriction) {
+    SetFlag(kParseRestriction, restriction != NO_PARSE_RESTRICTION);
+  }
+
+  ParseRestriction parse_restriction() const {
+    return GetFlag(kParseRestriction) ? ONLY_SINGLE_FUNCTION_LITERAL
+                                      : NO_PARSE_RESTRICTION;
+  }
+
+  ScriptCompiler::ExternalSourceStream* source_stream() {
+    return source_stream_;
+  }
+  void set_source_stream(ScriptCompiler::ExternalSourceStream* source_stream) {
+    source_stream_ = source_stream;
+  }
+
+  ScriptCompiler::StreamedSource::Encoding source_stream_encoding() {
+    return source_stream_encoding_;
+  }
+  void set_source_stream_encoding(
+      ScriptCompiler::StreamedSource::Encoding source_stream_encoding) {
+    source_stream_encoding_ = source_stream_encoding;
+  }
+
+  v8::Extension* extension() { return extension_; }
+  void set_extension(v8::Extension* extension) { extension_ = extension; }
+
+  ScriptData** cached_data() { return cached_data_; }
+  void set_cached_data(ScriptData** cached_data) { cached_data_ = cached_data; }
+
+  ScriptCompiler::CompileOptions compile_options() { return compile_options_; }
+  void set_compile_options(ScriptCompiler::CompileOptions compile_options) {
+    compile_options_ = compile_options;
+  }
+
+  Scope* script_scope() { return script_scope_; }
+  void set_script_scope(Scope* script_scope) { script_scope_ = script_scope; }
+
+  AstValueFactory* ast_value_factory() { return ast_value_factory_; }
+  void set_ast_value_factory(AstValueFactory* ast_value_factory) {
+    ast_value_factory_ = ast_value_factory;
+  }
+
+  FunctionLiteral* function() {  // TODO(titzer): temporary name adapter
+    return literal_;
+  }
+  FunctionLiteral* literal() { return literal_; }
+  void set_literal(FunctionLiteral* literal) { literal_ = literal; }
+
+  Scope* scope() { return scope_; }
+  void set_scope(Scope* scope) { scope_ = scope; }
+
+  UnicodeCache* unicode_cache() { return unicode_cache_; }
+  void set_unicode_cache(UnicodeCache* unicode_cache) {
+    unicode_cache_ = unicode_cache;
+  }
+
+  uintptr_t stack_limit() { return stack_limit_; }
+  void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
+
+  uint32_t hash_seed() { return hash_seed_; }
+  void set_hash_seed(uint32_t hash_seed) { hash_seed_ = hash_seed; }
+
+  //--------------------------------------------------------------------------
+  // TODO(titzer): these should not be part of ParseInfo.
+  //--------------------------------------------------------------------------
+  Isolate* isolate() { return isolate_; }
+  Handle<JSFunction> closure() { return closure_; }
+  Handle<SharedFunctionInfo> shared_info() { return shared_; }
+  Handle<Script> script() { return script_; }
+  Handle<Context> context() { return context_; }
+  void clear_script() { script_ = Handle<Script>::null(); }
+  void set_isolate(Isolate* isolate) { isolate_ = isolate; }
+  void set_context(Handle<Context> context) { context_ = context; }
+  void set_script(Handle<Script> script) { script_ = script; }
+  //--------------------------------------------------------------------------
+
+  LanguageMode language_mode() {
+    return construct_language_mode(is_strict_mode(), is_strong_mode());
+  }
+  void set_language_mode(LanguageMode language_mode) {
+    STATIC_ASSERT(LANGUAGE_END == 3);
+    set_strict_mode(language_mode & STRICT_BIT);
+    set_strong_mode(language_mode & STRONG_BIT);
+  }
+
+  void ReopenHandlesInNewHandleScope() {
+    closure_ = Handle<JSFunction>(*closure_);
+    shared_ = Handle<SharedFunctionInfo>(*shared_);
+    script_ = Handle<Script>(*script_);
+    context_ = Handle<Context>(*context_);
+  }
+
+ private:
+  // Various configuration flags for parsing.
+  enum Flag {
+    // ---------- Input flags ---------------------------
+    kToplevel = 1 << 0,
+    kLazy = 1 << 1,
+    kEval = 1 << 2,
+    kGlobal = 1 << 3,
+    kStrictMode = 1 << 4,
+    kStrongMode = 1 << 5,
+    kNative = 1 << 6,
+    kParseRestriction = 1 << 7,
+    kModule = 1 << 8,
+    kAllowLazyParsing = 1 << 9,
+    // ---------- Output flags --------------------------
+    kAstValueFactoryOwned = 1 << 10
+  };
+
+  //------------- Inputs to parsing and scope analysis -----------------------
+  Zone* zone_;
+  unsigned flags_;
+  ScriptCompiler::ExternalSourceStream* source_stream_;
+  ScriptCompiler::StreamedSource::Encoding source_stream_encoding_;
+  v8::Extension* extension_;
+  ScriptCompiler::CompileOptions compile_options_;
+  Scope* script_scope_;
+  UnicodeCache* unicode_cache_;
+  uintptr_t stack_limit_;
+  uint32_t hash_seed_;
+
+  // TODO(titzer): Move handles and isolate out of ParseInfo.
+  Isolate* isolate_;
+  Handle<JSFunction> closure_;
+  Handle<SharedFunctionInfo> shared_;
+  Handle<Script> script_;
+  Handle<Context> context_;
+
+  //----------- Inputs+Outputs of parsing and scope analysis -----------------
+  ScriptData** cached_data_;  // used if available, populated if requested.
+  AstValueFactory* ast_value_factory_;  // used if available, otherwise new.
+
+  //----------- Outputs of parsing and scope analysis ------------------------
+  FunctionLiteral* literal_;  // produced by full parser.
+  Scope* scope_;              // produced by scope analysis.
+
+  void SetFlag(Flag f) { flags_ |= f; }
+  void SetFlag(Flag f, bool v) { flags_ = v ? flags_ | f : flags_ & ~f; }
+  bool GetFlag(Flag f) const { return (flags_ & f) != 0; }
+
+  void set_shared_info(Handle<SharedFunctionInfo> shared) { shared_ = shared; }
+  void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
+};
 
 class FunctionEntry BASE_EMBEDDED {
  public:
@@ -492,20 +675,16 @@ class ParserTraits {
       const AstRawString* arg, int pos);
 
   // Reporting errors.
-  void ReportMessageAt(Scanner::Location source_location,
-                       const char* message,
+  void ReportMessageAt(Scanner::Location source_location, const char* message,
                        const char* arg = NULL,
-                       bool is_reference_error = false);
-  void ReportMessage(const char* message,
-                     const char* arg = NULL,
-                     bool is_reference_error = false);
-  void ReportMessage(const char* message,
-                     const AstRawString* arg,
-                     bool is_reference_error = false);
-  void ReportMessageAt(Scanner::Location source_location,
-                       const char* message,
+                       ParseErrorType error_type = kSyntaxError);
+  void ReportMessage(const char* message, const char* arg = NULL,
+                     ParseErrorType error_type = kSyntaxError);
+  void ReportMessage(const char* message, const AstRawString* arg,
+                     ParseErrorType error_type = kSyntaxError);
+  void ReportMessageAt(Scanner::Location source_location, const char* message,
                        const AstRawString* arg,
-                       bool is_reference_error = false);
+                       ParseErrorType error_type = kSyntaxError);
 
   // "null" return type creators.
   static const AstRawString* EmptyIdentifier() {
@@ -545,7 +724,8 @@ class ParserTraits {
                                  int end_pos);
   Literal* ExpressionFromLiteral(Token::Value token, int pos, Scanner* scanner,
                                  AstNodeFactory* factory);
-  Expression* ExpressionFromIdentifier(const AstRawString* name, int pos,
+  Expression* ExpressionFromIdentifier(const AstRawString* name,
+                                       int start_position, int end_position,
                                        Scope* scope, AstNodeFactory* factory);
   Expression* ExpressionFromString(int pos, Scanner* scanner,
                                    AstNodeFactory* factory);
@@ -638,8 +818,7 @@ class ParserTraits {
 
 class Parser : public ParserBase<ParserTraits> {
  public:
-  Parser(CompilationInfo* info, uintptr_t stack_limit, uint32_t hash_seed,
-         UnicodeCache* unicode_cache);
+  explicit Parser(ParseInfo* info);
   ~Parser() {
     delete reusable_preparser_;
     reusable_preparser_ = NULL;
@@ -650,14 +829,14 @@ class Parser : public ParserBase<ParserTraits> {
   // Parses the source code represented by the compilation info and sets its
   // function literal.  Returns false (and deallocates any allocated AST
   // nodes) if parsing failed.
-  static bool ParseStatic(CompilationInfo* info, bool allow_lazy = false);
-  bool Parse(CompilationInfo* info);
-  void ParseOnBackground(CompilationInfo* info);
+  static bool ParseStatic(ParseInfo* info);
+  bool Parse(ParseInfo* info);
+  void ParseOnBackground(ParseInfo* info);
 
   // Handle errors detected during parsing, move statistics to Isolate,
   // internalize strings (move them to the heap).
-  void Internalize(CompilationInfo* info);
-  void HandleSourceURLComments(CompilationInfo* info);
+  void Internalize(Isolate* isolate, Handle<Script> script, bool error);
+  void HandleSourceURLComments(Isolate* isolate, Handle<Script> script);
 
  private:
   friend class ParserTraits;
@@ -672,17 +851,17 @@ class Parser : public ParserBase<ParserTraits> {
   static const int kMaxNumFunctionLocals = 4194303;  // 2^22-1
 
   // Returns NULL if parsing failed.
-  FunctionLiteral* ParseProgram(CompilationInfo* info);
+  FunctionLiteral* ParseProgram(Isolate* isolate, ParseInfo* info);
 
-  FunctionLiteral* ParseLazy(CompilationInfo* info);
-  FunctionLiteral* ParseLazy(CompilationInfo* info,
+  FunctionLiteral* ParseLazy(Isolate* isolate, ParseInfo* info);
+  FunctionLiteral* ParseLazy(Isolate* isolate, ParseInfo* info,
                              Utf16CharacterStream* source);
 
   // Called by ParseProgram after setting up the scanner.
-  FunctionLiteral* DoParseProgram(CompilationInfo* info, Scope** scope,
+  FunctionLiteral* DoParseProgram(ParseInfo* info, Scope** scope,
                                   Scope** ad_hoc_eval_scope);
 
-  void SetCachedData(CompilationInfo* info);
+  void SetCachedData(ParseInfo* info);
 
   bool inside_with() const { return scope_->inside_with(); }
   ScriptCompiler::CompileOptions compile_options() const {
@@ -707,15 +886,17 @@ class Parser : public ParserBase<ParserTraits> {
   void* ParseStatementList(ZoneList<Statement*>* body, int end_token,
                            bool is_eval, Scope** ad_hoc_eval_scope, bool* ok);
   Statement* ParseStatementListItem(bool* ok);
-  Statement* ParseModule(bool* ok);
+  void* ParseModuleItemList(ZoneList<Statement*>* body, bool* ok);
   Statement* ParseModuleItem(bool* ok);
-  Literal* ParseModuleSpecifier(bool* ok);
+  const AstRawString* ParseModuleSpecifier(bool* ok);
   Statement* ParseImportDeclaration(bool* ok);
   Statement* ParseExportDeclaration(bool* ok);
   Statement* ParseExportDefault(bool* ok);
-  void* ParseExportClause(ZoneList<const AstRawString*>* names,
+  void* ParseExportClause(ZoneList<const AstRawString*>* export_names,
+                          ZoneList<Scanner::Location>* export_locations,
+                          ZoneList<const AstRawString*>* local_names,
                           Scanner::Location* reserved_loc, bool* ok);
-  void* ParseNamedImports(ZoneList<const AstRawString*>* names, bool* ok);
+  ZoneList<ImportDeclaration*>* ParseNamedImports(int pos, bool* ok);
   Statement* ParseStatement(ZoneList<const AstRawString*>* labels, bool* ok);
   Statement* ParseSubStatement(ZoneList<const AstRawString*>* labels, bool* ok);
   Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names,
@@ -763,8 +944,8 @@ class Parser : public ParserBase<ParserTraits> {
                                   Expression* each,
                                   Expression* subject,
                                   Statement* body);
-  Statement* DesugarLetBindingsInForStatement(
-      Scope* inner_scope, ZoneList<const AstRawString*>* names,
+  Statement* DesugarLexicalBindingsInForStatement(
+      Scope* inner_scope, bool is_const, ZoneList<const AstRawString*>* names,
       ForStatement* loop, Statement* init, Expression* cond, Statement* next,
       Statement* body, bool* ok);
 
@@ -799,7 +980,7 @@ class Parser : public ParserBase<ParserTraits> {
 
   // Parser support
   VariableProxy* NewUnresolved(const AstRawString* name, VariableMode mode);
-  void Declare(Declaration* declaration, bool resolve, bool* ok);
+  Variable* Declare(Declaration* declaration, bool resolve, bool* ok);
 
   bool TargetStackContainsLabel(const AstRawString* label);
   BreakableStatement* LookupBreakTarget(const AstRawString* label, bool* ok);
@@ -845,13 +1026,7 @@ class Parser : public ParserBase<ParserTraits> {
 
   bool parsing_lazy_arrow_parameters_;  // for lazily parsed arrow functions.
 
-  // Pending errors.
-  bool has_pending_error_;
-  Scanner::Location pending_error_location_;
-  const char* pending_error_message_;
-  const AstRawString* pending_error_arg_;
-  const char* pending_error_char_arg_;
-  bool pending_error_is_reference_error_;
+  PendingCompilationErrorHandler pending_error_handler_;
 
   // Other information which will be stored in Parser and moved to Isolate after
   // parsing.
diff --git a/deps/v8/src/pending-compilation-error-handler.cc b/deps/v8/src/pending-compilation-error-handler.cc
new file mode 100644 (file)
index 0000000..f0449d8
--- /dev/null
@@ -0,0 +1,64 @@
+// 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.
+
+#include "src/pending-compilation-error-handler.h"
+
+#include "src/debug.h"
+#include "src/handles.h"
+#include "src/isolate.h"
+#include "src/messages.h"
+
+namespace v8 {
+namespace internal {
+
+void PendingCompilationErrorHandler::ThrowPendingError(Isolate* isolate,
+                                                       Handle<Script> script) {
+  if (!has_pending_error_) return;
+  MessageLocation location(script, start_position_, end_position_);
+  Factory* factory = isolate->factory();
+  bool has_arg = arg_ != NULL || char_arg_ != NULL || !handle_arg_.is_null();
+  Handle<FixedArray> elements = factory->NewFixedArray(has_arg ? 1 : 0);
+  if (arg_ != NULL) {
+    Handle<String> arg_string = arg_->string();
+    elements->set(0, *arg_string);
+  } else if (char_arg_ != NULL) {
+    Handle<String> arg_string =
+        factory->NewStringFromUtf8(CStrVector(char_arg_)).ToHandleChecked();
+    elements->set(0, *arg_string);
+  } else if (!handle_arg_.is_null()) {
+    elements->set(0, *handle_arg_);
+  }
+  isolate->debug()->OnCompileError(script);
+
+  Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
+  Handle<Object> error;
+
+  switch (error_type_) {
+    case kReferenceError:
+      error = factory->NewReferenceError(message_, array);
+      break;
+    case kSyntaxError:
+      error = factory->NewSyntaxError(message_, array);
+      break;
+  }
+
+  Handle<JSObject> jserror = Handle<JSObject>::cast(error);
+
+  Handle<Name> key_start_pos = factory->error_start_pos_symbol();
+  JSObject::SetProperty(jserror, key_start_pos,
+                        handle(Smi::FromInt(location.start_pos()), isolate),
+                        SLOPPY).Check();
+
+  Handle<Name> key_end_pos = factory->error_end_pos_symbol();
+  JSObject::SetProperty(jserror, key_end_pos,
+                        handle(Smi::FromInt(location.end_pos()), isolate),
+                        SLOPPY).Check();
+
+  Handle<Name> key_script = factory->error_script_symbol();
+  JSObject::SetProperty(jserror, key_script, script, SLOPPY).Check();
+
+  isolate->Throw(*error, &location);
+}
+}
+}  // namespace v8::internal
diff --git a/deps/v8/src/pending-compilation-error-handler.h b/deps/v8/src/pending-compilation-error-handler.h
new file mode 100644 (file)
index 0000000..c75f23d
--- /dev/null
@@ -0,0 +1,91 @@
+// 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.
+
+#ifndef V8_PENDING_COMPILATION_ERROR_HANDLER_H_
+#define V8_PENDING_COMPILATION_ERROR_HANDLER_H_
+
+#include "src/base/macros.h"
+#include "src/globals.h"
+#include "src/handles.h"
+
+namespace v8 {
+namespace internal {
+
+class AstRawString;
+class Isolate;
+class Script;
+
+// Helper class for handling pending compilation errors consistently in various
+// compilation phases.
+class PendingCompilationErrorHandler {
+ public:
+  PendingCompilationErrorHandler()
+      : has_pending_error_(false),
+        start_position_(-1),
+        end_position_(-1),
+        message_(nullptr),
+        arg_(nullptr),
+        char_arg_(nullptr),
+        error_type_(kSyntaxError) {}
+
+  void ReportMessageAt(int start_position, int end_position,
+                       const char* message, const char* arg = nullptr,
+                       ParseErrorType error_type = kSyntaxError) {
+    if (has_pending_error_) return;
+    has_pending_error_ = true;
+    start_position_ = start_position;
+    end_position_ = end_position;
+    message_ = message;
+    char_arg_ = arg;
+    arg_ = nullptr;
+    error_type_ = error_type;
+  }
+
+  void ReportMessageAt(int start_position, int end_position,
+                       const char* message, const AstRawString* arg,
+                       ParseErrorType error_type = kSyntaxError) {
+    if (has_pending_error_) return;
+    has_pending_error_ = true;
+    start_position_ = start_position;
+    end_position_ = end_position;
+    message_ = message;
+    char_arg_ = nullptr;
+    arg_ = arg;
+    error_type_ = error_type;
+  }
+
+  void ReportMessageAt(int start_position, int end_position,
+                       const char* message, Handle<String> arg,
+                       ParseErrorType error_type = kSyntaxError) {
+    if (has_pending_error_) return;
+    has_pending_error_ = true;
+    start_position_ = start_position;
+    end_position_ = end_position;
+    message_ = message;
+    char_arg_ = nullptr;
+    arg_ = nullptr;
+    handle_arg_ = arg;
+    error_type_ = error_type;
+  }
+
+  bool has_pending_error() const { return has_pending_error_; }
+
+  void ThrowPendingError(Isolate* isolate, Handle<Script> script);
+
+ private:
+  bool has_pending_error_;
+  int start_position_;
+  int end_position_;
+  const char* message_;
+  const AstRawString* arg_;
+  const char* char_arg_;
+  Handle<String> handle_arg_;
+  ParseErrorType error_type_;
+
+  DISALLOW_COPY_AND_ASSIGN(PendingCompilationErrorHandler);
+};
+
+}  // namespace internal
+}  // namespace v8
+#endif  // V8_PENDING_COMPILATION_ERROR_HANDLER_H_
diff --git a/deps/v8/src/ppc/OWNERS b/deps/v8/src/ppc/OWNERS
new file mode 100644 (file)
index 0000000..beecb3d
--- /dev/null
@@ -0,0 +1,3 @@
+joransiu@ca.ibm.com
+mbrandy@us.ibm.com
+michael_dawson@ca.ibm.com
index 6779ee3..d95c7ec 100644 (file)
@@ -51,14 +51,36 @@ 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);
+  // absolute code pointer inside code object moves with the code object.
+  if (IsInternalReference(rmode_)) {
+    // Jump table entry
+    Address target = Memory::Address_at(pc_);
+    Memory::Address_at(pc_) = target + delta;
+  } else {
+    // mov sequence
+    DCHECK(IsInternalReferenceEncoded(rmode_));
+    Address target = Assembler::target_address_at(pc_, host_);
+    Assembler::set_target_address_at(pc_, host_, target + delta,
+                                     icache_flush_mode);
+  }
+}
+
+
+Address RelocInfo::target_internal_reference() {
+  if (IsInternalReference(rmode_)) {
+    // Jump table entry
+    return Memory::Address_at(pc_);
+  } else {
+    // mov sequence
+    DCHECK(IsInternalReferenceEncoded(rmode_));
+    return Assembler::target_address_at(pc_, host_);
   }
-#endif
-  // We do not use pc relative addressing on PPC, so there is
-  // nothing else to do.
+}
+
+
+Address RelocInfo::target_internal_reference_address() {
+  DCHECK(IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_));
+  return reinterpret_cast<Address>(pc_);
 }
 
 
@@ -72,14 +94,6 @@ 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.
@@ -94,13 +108,8 @@ Address RelocInfo::target_address_address() {
 
 
 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
 }
 
 
@@ -134,22 +143,12 @@ Address Assembler::target_address_from_return_address(Address pc) {
 //  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;
+  return pc - (kMovInstructions + 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;
+  return pc + (kMovInstructions + 2) * kInstrSize;
 }
 
 
@@ -180,7 +179,7 @@ void RelocInfo::set_target_object(Object* target,
 }
 
 
-Address RelocInfo::target_reference() {
+Address RelocInfo::target_external_reference() {
   DCHECK(rmode_ == EXTERNAL_REFERENCE);
   return Assembler::target_address_at(pc_, host_);
 }
@@ -227,13 +226,8 @@ void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode write_barrier_mode,
 }
 
 
-#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 kCodeAgingInstructions = Assembler::kMovInstructions + 3;
 static const int kNoCodeAgeSequenceInstructions =
     ((kNoCodeAgeInstructions >= kCodeAgingInstructions)
          ? kNoCodeAgeInstructions
@@ -273,8 +267,8 @@ 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().
+  // BreakLocation::SetDebugBreakAtReturn(), or debug break
+  // slot per BreakLocation::SetDebugBreakAtSlot().
   return Assembler::target_address_at(pc_, host_);
 }
 
@@ -308,15 +302,25 @@ Object** RelocInfo::call_object_address() {
 
 void RelocInfo::WipeOut() {
   DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
-         IsRuntimeEntry(rmode_) || IsExternalReference(rmode_));
-  Assembler::set_target_address_at(pc_, host_, NULL);
+         IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
+         IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_));
+  if (IsInternalReference(rmode_)) {
+    // Jump table entry
+    Memory::Address_at(pc_) = NULL;
+  } else if (IsInternalReferenceEncoded(rmode_)) {
+    // mov sequence
+    // Currently used only by deserializer, no need to flush.
+    Assembler::set_target_address_at(pc_, host_, NULL, SKIP_ICACHE_FLUSH);
+  } else {
+    Assembler::set_target_address_at(pc_, host_, NULL);
+  }
 }
 
 
 bool RelocInfo::IsPatchedReturnSequence() {
   //
   // The patched return sequence is defined by
-  // BreakLocationIterator::SetDebugBreakAtReturn()
+  // BreakLocation::SetDebugBreakAtReturn()
   // FIXED_SEQUENCE
 
   Instr instr0 = Assembler::instr_at(pc_);
@@ -356,6 +360,9 @@ void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
     visitor->VisitCell(this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     visitor->VisitExternalReference(this);
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE ||
+             mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
+    visitor->VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     visitor->VisitCodeAgeSequence(this);
   } else if (((RelocInfo::IsJSReturn(mode) && IsPatchedReturnSequence()) ||
@@ -380,6 +387,9 @@ void RelocInfo::Visit(Heap* heap) {
     StaticVisitor::VisitCell(heap, this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     StaticVisitor::VisitExternalReference(this);
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE ||
+             mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
+    StaticVisitor::VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     StaticVisitor::VisitCodeAgeSequence(heap, this);
   } else if (heap->isolate()->debug()->has_break_points() &&
@@ -459,59 +469,10 @@ Address Assembler::target_address_at(Address pc,
                                      (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;
+  UNREACHABLE();
+  return NULL;
 }
-#endif
 
 
 // This sets the branch destination (which gets loaded at the call address).
@@ -523,6 +484,18 @@ void Assembler::deserialization_set_special_target_at(
   set_target_address_at(instruction_payload, code, target);
 }
 
+
+void Assembler::deserialization_set_target_internal_reference_at(
+    Address pc, Address target, RelocInfo::Mode mode) {
+  if (RelocInfo::IsInternalReferenceEncoded(mode)) {
+    Code* code = NULL;
+    set_target_address_at(pc, code, target, SKIP_ICACHE_FLUSH);
+  } else {
+    Memory::Address_at(pc) = target;
+  }
+}
+
+
 // This code assumes the FIXED_SEQUENCE of lis/ori
 void Assembler::set_target_address_at(Address pc,
                                       ConstantPoolArray* constant_pool,
@@ -578,14 +551,9 @@ void Assembler::set_target_address_at(Address pc,
       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
+    return;
   }
+  UNREACHABLE();
 }
 }
 }  // namespace v8::internal
index 8bb45e3..7778ab1 100644 (file)
@@ -42,7 +42,6 @@
 #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 {
@@ -142,45 +141,21 @@ const char* DoubleRegister::AllocationIndexToString(int index) {
 // -----------------------------------------------------------------------------
 // Implementation of RelocInfo
 
-const int RelocInfo::kApplyMask = 1 << RelocInfo::INTERNAL_REFERENCE;
+const int RelocInfo::kApplyMask = 1 << RelocInfo::INTERNAL_REFERENCE |
+                                  1 << RelocInfo::INTERNAL_REFERENCE_ENCODED;
 
 
 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.
+  // instruction sequence, 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();
 }
 
 
@@ -226,9 +201,6 @@ MemOperand::MemOperand(Register ra, Register rb) {
 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_);
 
@@ -244,11 +216,13 @@ Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
   trampoline_emitted_ = FLAG_force_long_branches;
   unbound_labels_count_ = 0;
   ClearRecordedAstId();
+  relocations_.reserve(128);
 }
 
 
 void Assembler::GetCode(CodeDesc* desc) {
-  reloc_info_writer.Finish();
+  EmitRelocations();
+
   // Set up code descriptor.
   desc->buffer = buffer_;
   desc->buffer_size = buffer_size_;
@@ -401,32 +375,43 @@ int Assembler::GetCmpImmediateRawImmediate(Instr instr) {
 const int kEndOfChain = -4;
 
 
+// Dummy opcodes for unbound label mov instructions or jump table entries.
+enum {
+  kUnboundMovLabelOffsetOpcode = 0 << 26,
+  kUnboundAddLabelOffsetOpcode = 1 << 26,
+  kUnboundMovLabelAddrOpcode = 2 << 26,
+  kUnboundJumpTableEntryOpcode = 3 << 26
+};
+
+
 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);
-    }
+  int link;
+  switch (opcode) {
+    case BX:
+      link = SIGN_EXT_IMM26(instr & kImm26Mask);
+      link &= ~(kAAMask | kLKMask);  // discard AA|LK bits if present
+      break;
+    case BCX:
+      link = SIGN_EXT_IMM16((instr & kImm16Mask));
+      link &= ~(kAAMask | kLKMask);  // discard AA|LK bits if present
+      break;
+    case kUnboundMovLabelOffsetOpcode:
+    case kUnboundAddLabelOffsetOpcode:
+    case kUnboundMovLabelAddrOpcode:
+    case kUnboundJumpTableEntryOpcode:
+      link = SIGN_EXT_IMM26(instr & kImm26Mask);
+      link <<= 2;
+      break;
+    default:
+      DCHECK(false);
+      return -1;
   }
 
-  DCHECK(false);
-  return -1;
+  if (link == 0) return kEndOfChain;
+  return pos + link;
 }
 
 
@@ -434,51 +419,74 @@ 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(is_int26(imm26) && (imm26 & (kAAMask | kLKMask)) == 0);
-    if (imm26 == kInstrSize && !(instr & kLKMask)) {
-      // Branch to next instr without link.
-      instr = ORI;  // nop: ori, 0,0,0
-    } else {
-      instr &= ((~kImm26Mask) | kAAMask | kLKMask);
-      instr |= (imm26 & kImm26Mask);
+  switch (opcode) {
+    case BX: {
+      int imm26 = target_pos - pos;
+      DCHECK(is_int26(imm26) && (imm26 & (kAAMask | kLKMask)) == 0);
+      if (imm26 == kInstrSize && !(instr & kLKMask)) {
+        // Branch to next instr without link.
+        instr = ORI;  // nop: ori, 0,0,0
+      } else {
+        instr &= ((~kImm26Mask) | kAAMask | kLKMask);
+        instr |= (imm26 & kImm26Mask);
+      }
+      instr_at_put(pos, instr);
+      break;
     }
-    instr_at_put(pos, instr);
-    return;
-  } else if (BCX == opcode) {
-    int imm16 = target_pos - pos;
-    DCHECK(is_int16(imm16) && (imm16 & (kAAMask | kLKMask)) == 0);
-    if (imm16 == kInstrSize && !(instr & kLKMask)) {
-      // Branch to next instr without link.
-      instr = ORI;  // nop: ori, 0,0,0
-    } else {
-      instr &= ((~kImm16Mask) | kAAMask | kLKMask);
-      instr |= (imm16 & kImm16Mask);
+    case BCX: {
+      int imm16 = target_pos - pos;
+      DCHECK(is_int16(imm16) && (imm16 & (kAAMask | kLKMask)) == 0);
+      if (imm16 == kInstrSize && !(instr & kLKMask)) {
+        // Branch to next instr without link.
+        instr = ORI;  // nop: ori, 0,0,0
+      } else {
+        instr &= ((~kImm16Mask) | kAAMask | kLKMask);
+        instr |= (imm16 & kImm16Mask);
+      }
+      instr_at_put(pos, instr);
+      break;
     }
-    instr_at_put(pos, instr);
-    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;
+    case kUnboundMovLabelOffsetOpcode: {
+      // Load the position of the label relative to the generated code object
+      // pointer in a register.
+      Register dst = Register::from_code(instr_at(pos + kInstrSize));
+      int32_t offset = target_pos + (Code::kHeaderSize - kHeapObjectTag);
+      CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), 2,
+                          CodePatcher::DONT_FLUSH);
+      patcher.masm()->bitwise_mov32(dst, offset);
+      break;
+    }
+    case kUnboundAddLabelOffsetOpcode: {
+      // dst = base + position + immediate
+      Instr operands = instr_at(pos + kInstrSize);
+      Register dst = Register::from_code((operands >> 21) & 0x1f);
+      Register base = Register::from_code((operands >> 16) & 0x1f);
+      int32_t offset = target_pos + SIGN_EXT_IMM16(operands & kImm16Mask);
+      CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), 2,
+                          CodePatcher::DONT_FLUSH);
+      patcher.masm()->bitwise_add32(dst, base, offset);
+      break;
+    }
+    case kUnboundMovLabelAddrOpcode: {
+      // Load the address of the label in a register.
+      Register dst = Register::from_code(instr_at(pos + kInstrSize));
+      CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos),
+                          kMovInstructions, CodePatcher::DONT_FLUSH);
+      // Keep internal references relative until EmitRelocations.
+      patcher.masm()->bitwise_mov(dst, target_pos);
+      break;
+    }
+    case kUnboundJumpTableEntryOpcode: {
+      CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos),
+                          kPointerSize / kInstrSize, CodePatcher::DONT_FLUSH);
+      // Keep internal references relative until EmitRelocations.
+      patcher.masm()->emit_ptr(target_pos);
+      break;
+    }
+    default:
+      DCHECK(false);
+      break;
   }
-
-  DCHECK(false);
 }
 
 
@@ -487,13 +495,16 @@ int Assembler::max_reach_from(int 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;
+  switch (opcode) {
+    case BX:
+      return 26;
+    case BCX:
+      return 16;
+    case kUnboundMovLabelOffsetOpcode:
+    case kUnboundAddLabelOffsetOpcode:
+    case kUnboundMovLabelAddrOpcode:
+    case kUnboundJumpTableEntryOpcode:
+      return 0;  // no limit on reach
   }
 
   DCHECK(false);
@@ -514,7 +525,7 @@ void Assembler::bind_to(Label* L, int 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 (maxReach && is_intn(offset, maxReach) == false) {
       if (trampoline_pos == kInvalidSlotPos) {
         trampoline_pos = get_trampoline_entry();
         CHECK(trampoline_pos != kInvalidSlotPos);
@@ -636,19 +647,19 @@ int32_t Assembler::get_trampoline_entry() {
 }
 
 
-int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
-  int target_pos;
+int Assembler::link(Label* L) {
+  int position;
   if (L->is_bound()) {
-    target_pos = L->pos();
+    position = L->pos();
   } else {
     if (L->is_linked()) {
-      target_pos = L->pos();  // L's link
+      position = L->pos();  // L's link
     } else {
       // was: target_pos = kEndOfChain;
-      // However, using branch to self to mark the first reference
+      // However, using 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();
+      position = pc_offset();
       if (!trampoline_emitted_) {
         unbound_labels_count_++;
         next_buffer_check_ -= kTrampolineSlotsSize;
@@ -657,7 +668,7 @@ int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
     L->link_to(pc_offset());
   }
 
-  return target_pos - pc_offset();
+  return position;
 }
 
 
@@ -1478,102 +1489,21 @@ void Assembler::divdu(Register dst, Register src1, Register src2, OEBit o,
 // TOC and static chain are ignored and set to 0.
 void Assembler::function_descriptor() {
 #if ABI_USES_FUNCTION_DESCRIPTORS
+  Label instructions;
   DCHECK(pc_offset() == 0);
-  RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
-  emit_ptr(reinterpret_cast<uintptr_t>(pc_) + 3 * kPointerSize);
+  emit_label_addr(&instructions);
   emit_ptr(0);
   emit_ptr(0);
+  bind(&instructions);
 #endif
 }
 
 
-#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();
+    GrowBuffer(space_needed);
   }
 }
-#endif
 
 
 bool Operand::must_output_reloc_info(const Assembler* assembler) const {
@@ -1595,32 +1525,11 @@ bool Operand::must_output_reloc_info(const Assembler* assembler) const {
 // 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 relocatable = src.must_output_reloc_info(this);
   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() && !is_int16(value)));
-
-#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
+  canOptimize =
+      !(relocatable || (is_trampoline_pool_blocked() && !is_int16(value)));
 
   if (canOptimize) {
     if (is_int16(value)) {
@@ -1658,8 +1567,14 @@ void Assembler::mov(Register dst, const Operand& src) {
   }
 
   DCHECK(!canOptimize);
+  if (relocatable) {
+    RecordRelocInfo(src.rmode_);
+  }
+  bitwise_mov(dst, value);
+}
+
 
-  {
+void Assembler::bitwise_mov(Register dst, intptr_t value) {
     BlockTrampolinePoolScope block_trampoline_pool(this);
 #if V8_TARGET_ARCH_PPC64
     int32_t hi_32 = static_cast<int32_t>(value >> 32);
@@ -1679,37 +1594,138 @@ void Assembler::mov(Register dst, const Operand& src) {
     lis(dst, Operand(SIGN_EXT_IMM16(hi_word)));
     ori(dst, dst, Operand(lo_word));
 #endif
+}
+
+
+void Assembler::bitwise_mov32(Register dst, int32_t value) {
+  BlockTrampolinePoolScope block_trampoline_pool(this);
+  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));
+}
+
+
+void Assembler::bitwise_add32(Register dst, Register src, int32_t value) {
+  BlockTrampolinePoolScope block_trampoline_pool(this);
+  if (is_int16(value)) {
+    addi(dst, src, Operand(value));
+    nop();
+  } else {
+    int hi_word = static_cast<int>(value >> 16);
+    int lo_word = static_cast<int>(value & 0xffff);
+    if (lo_word & 0x8000) hi_word++;
+    addis(dst, src, Operand(SIGN_EXT_IMM16(hi_word)));
+    addic(dst, dst, Operand(SIGN_EXT_IMM16(lo_word)));
   }
 }
 
 
 void Assembler::mov_label_offset(Register dst, Label* label) {
+  int position = link(label);
   if (label->is_bound()) {
-    int target = label->pos();
-    mov(dst, Operand(target + Code::kHeaderSize - kHeapObjectTag));
+    // Load the position of the label relative to the generated code object.
+    mov(dst, Operand(position + 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;
-    }
+    // Encode internal reference to unbound label. We use a dummy opcode
+    // such that it won't collide with any opcode that might appear in the
+    // label's chain.  Encode the destination register in the 2nd instruction.
+    int link = position - pc_offset();
+    DCHECK_EQ(0, link & 3);
+    link >>= 2;
+    DCHECK(is_int26(link));
 
     // 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.
+    // target_at extracts the link and target_at_put patches the instructions.
     BlockTrampolinePoolScope block_trampoline_pool(this);
-    emit(link);
+    emit(kUnboundMovLabelOffsetOpcode | (link & kImm26Mask));
+    emit(dst.code());
+  }
+}
+
+
+void Assembler::add_label_offset(Register dst, Register base, Label* label,
+                                 int delta) {
+  int position = link(label);
+  if (label->is_bound()) {
+    // dst = base + position + delta
+    position += delta;
+    bitwise_add32(dst, base, position);
+  } else {
+    // Encode internal reference to unbound label. We use a dummy opcode
+    // such that it won't collide with any opcode that might appear in the
+    // label's chain.  Encode the operands in the 2nd instruction.
+    int link = position - pc_offset();
+    DCHECK_EQ(0, link & 3);
+    link >>= 2;
+    DCHECK(is_int26(link));
+    DCHECK(is_int16(delta));
+
+    BlockTrampolinePoolScope block_trampoline_pool(this);
+    emit(kUnboundAddLabelOffsetOpcode | (link & kImm26Mask));
+    emit(dst.code() * B21 | base.code() * B16 | (delta & kImm16Mask));
+  }
+}
+
+
+void Assembler::mov_label_addr(Register dst, Label* label) {
+  CheckBuffer();
+  RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
+  int position = link(label);
+  if (label->is_bound()) {
+    // Keep internal references relative until EmitRelocations.
+    bitwise_mov(dst, position);
+  } else {
+    // Encode internal reference to unbound label. We use a dummy opcode
+    // such that it won't collide with any opcode that might appear in the
+    // label's chain.  Encode the destination register in the 2nd instruction.
+    int link = position - pc_offset();
+    DCHECK_EQ(0, link & 3);
+    link >>= 2;
+    DCHECK(is_int26(link));
+
+    // When the label is bound, these instructions will be patched
+    // with a multi-instruction mov sequence that will load the
+    // destination register with the address of the label.
+    //
+    // target_at extracts the link and target_at_put patches the instructions.
+    BlockTrampolinePoolScope block_trampoline_pool(this);
+    emit(kUnboundMovLabelAddrOpcode | (link & kImm26Mask));
+    emit(dst.code());
+    DCHECK(kMovInstructions >= 2);
+    for (int i = 0; i < kMovInstructions - 2; i++) nop();
+  }
+}
+
+
+void Assembler::emit_label_addr(Label* label) {
+  CheckBuffer();
+  RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
+  int position = link(label);
+  if (label->is_bound()) {
+    // Keep internal references relative until EmitRelocations.
+    emit_ptr(position);
+  } else {
+    // Encode internal reference to unbound label. We use a dummy opcode
+    // such that it won't collide with any opcode that might appear in the
+    // label's chain.
+    int link = position - pc_offset();
+    DCHECK_EQ(0, link & 3);
+    link >>= 2;
+    DCHECK(is_int26(link));
+
+    // When the label is bound, the instruction(s) will be patched
+    // as a jump table entry containing the label address.  target_at extracts
+    // the link and target_at_put patches the instruction(s).
+    BlockTrampolinePoolScope block_trampoline_pool(this);
+    emit(kUnboundJumpTableEntryOpcode | (link & kImm26Mask));
+#if V8_TARGET_ARCH_PPC64
     nop();
+#endif
   }
 }
 
@@ -2172,8 +2188,7 @@ bool Assembler::IsNop(Instr instr, int type) {
 }
 
 
-// Debugging.
-void Assembler::GrowBuffer() {
+void Assembler::GrowBuffer(int needed) {
   if (!own_buffer_) FATAL("external code buffer is too small");
 
   // Compute new buffer size.
@@ -2185,6 +2200,10 @@ void Assembler::GrowBuffer() {
   } else {
     desc.buffer_size = buffer_size_ + 1 * MB;
   }
+  int space = buffer_space() + (desc.buffer_size - buffer_size_);
+  if (space < needed) {
+    desc.buffer_size += needed - space;
+  }
   CHECK_GT(desc.buffer_size, 0);  // no overflow
 
   // Set up new buffer.
@@ -2209,22 +2228,9 @@ void Assembler::GrowBuffer() {
   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
+  // Nothing else to do here since we keep all internal references and
+  // deferred relocation entries relative to the buffer (until
+  // EmitRelocations).
 }
 
 
@@ -2242,20 +2248,27 @@ void Assembler::dd(uint32_t data) {
 }
 
 
-void Assembler::emit_ptr(uintptr_t data) {
+void Assembler::emit_ptr(intptr_t data) {
   CheckBuffer();
-  *reinterpret_cast<uintptr_t*>(pc_) = data;
-  pc_ += sizeof(uintptr_t);
+  *reinterpret_cast<intptr_t*>(pc_) = data;
+  pc_ += sizeof(intptr_t);
+}
+
+
+void Assembler::emit_double(double value) {
+  CheckBuffer();
+  *reinterpret_cast<double*>(pc_) = value;
+  pc_ += sizeof(double);
 }
 
 
 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
-  RelocInfo rinfo(pc_, rmode, data, NULL);
+  DeferredRelocInfo rinfo(pc_offset(), rmode, data);
   RecordRelocInfo(rinfo);
 }
 
 
-void Assembler::RecordRelocInfo(const RelocInfo& rinfo) {
+void Assembler::RecordRelocInfo(const DeferredRelocInfo& rinfo) {
   if (rinfo.rmode() >= RelocInfo::JS_RETURN &&
       rinfo.rmode() <= RelocInfo::DEBUG_BREAK_SLOT) {
     // Adjust code for new modes.
@@ -2271,19 +2284,46 @@ void Assembler::RecordRelocInfo(const RelocInfo& rinfo) {
         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);
+      DeferredRelocInfo reloc_info_with_ast_id(rinfo.position(), rinfo.rmode(),
+                                               RecordedAstId().ToInt());
       ClearRecordedAstId();
-      reloc_info_writer.Write(&reloc_info_with_ast_id);
+      relocations_.push_back(reloc_info_with_ast_id);
     } else {
-      reloc_info_writer.Write(&rinfo);
+      relocations_.push_back(rinfo);
     }
   }
 }
 
 
+void Assembler::EmitRelocations() {
+  EnsureSpaceFor(relocations_.size() * kMaxRelocSize);
+
+  for (std::vector<DeferredRelocInfo>::iterator it = relocations_.begin();
+       it != relocations_.end(); it++) {
+    RelocInfo::Mode rmode = it->rmode();
+    Address pc = buffer_ + it->position();
+    Code* code = NULL;
+    RelocInfo rinfo(pc, rmode, it->data(), code);
+
+    // Fix up internal references now that they are guaranteed to be bound.
+    if (RelocInfo::IsInternalReference(rmode)) {
+      // Jump table entry
+      intptr_t pos = reinterpret_cast<intptr_t>(Memory::Address_at(pc));
+      Memory::Address_at(pc) = buffer_ + pos;
+    } else if (RelocInfo::IsInternalReferenceEncoded(rmode)) {
+      // mov sequence
+      intptr_t pos = reinterpret_cast<intptr_t>(target_address_at(pc, code));
+      set_target_address_at(pc, code, buffer_ + pos, SKIP_ICACHE_FLUSH);
+    }
+
+    reloc_info_writer.Write(&rinfo);
+  }
+
+  reloc_info_writer.Finish();
+}
+
+
 void Assembler::BlockTrampolinePoolFor(int instructions) {
   BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
 }
@@ -2339,193 +2379,14 @@ void Assembler::CheckTrampolinePool() {
 
 
 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
 
index a394955..bcc2d8f 100644 (file)
@@ -44,8 +44,8 @@
 #include <vector>
 
 #include "src/assembler.h"
+#include "src/compiler.h"
 #include "src/ppc/constants-ppc.h"
-#include "src/serialize.h"
 
 #define ABI_USES_FUNCTION_DESCRIPTORS \
   (V8_HOST_ARCH_PPC && (V8_OS_AIX ||    \
@@ -108,11 +108,7 @@ struct Register {
   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 =
@@ -178,14 +174,18 @@ struct Register {
       "r25",
       "r26",
       "r27",
-#if !V8_OOL_CONSTANT_POOL
       "r28",
-#endif
       "cp",
     };
     return names[index];
   }
 
+  static const RegList kAllocatable =
+      1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 | 1 << 8 | 1 << 9 | 1 << 10 |
+      1 << 14 | 1 << 15 | 1 << 16 | 1 << 17 | 1 << 18 | 1 << 19 | 1 << 20 |
+      1 << 21 | 1 << 22 | 1 << 23 | 1 << 24 | 1 << 25 | 1 << 26 | 1 << 27 |
+      1 << 28 | 1 << 30;
+
   static Register from_code(int code) {
     Register r = {code};
     return r;
@@ -242,7 +242,7 @@ 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_r28_Code = 28;
 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
@@ -286,9 +286,6 @@ 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 {
@@ -467,13 +464,6 @@ class Operand BASE_EMBEDDED {
   // 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 {
@@ -527,75 +517,21 @@ class MemOperand BASE_EMBEDDED {
 };
 
 
-#if V8_OOL_CONSTANT_POOL
-// Class used to build a constant pool.
-class ConstantPoolBuilder BASE_EMBEDDED {
+class DeferredRelocInfo {
  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];
-  }
+  DeferredRelocInfo() {}
+  DeferredRelocInfo(int position, RelocInfo::Mode rmode, intptr_t data)
+      : position_(position), rmode_(rmode), data_(data) {}
 
-  inline ConstantPoolArray::NumberOfEntries* small_entries() {
-    return number_of_entries(ConstantPoolArray::SMALL_SECTION);
-  }
-
-  inline ConstantPoolArray::NumberOfEntries* extended_entries() {
-    return number_of_entries(ConstantPoolArray::EXTENDED_SECTION);
-  }
+  int position() const { return position_; }
+  RelocInfo::Mode rmode() const { return rmode_; }
+  intptr_t data() const { return data_; }
 
  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];
+  int position_;
+  RelocInfo::Mode rmode_;
+  intptr_t data_;
 };
-#endif
 
 
 class Assembler : public AssemblerBase {
@@ -637,6 +573,12 @@ class Assembler : public AssemblerBase {
   // but it may be bound only once.
 
   void bind(Label* L);  // binds an unbound label L to the current code position
+
+  // Links a label at the current pc_offset().  If already bound, returns the
+  // bound position.  If already linked, returns the position of the prior link.
+  // Otherwise, returns the current pc_offset().
+  int link(Label* L);
+
   // 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);
@@ -644,24 +586,15 @@ class Assembler : public AssemblerBase {
   // 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);
+  int branch_offset(Label* L, bool jump_elimination_allowed) {
+    int position = link(L);
+    return position - pc_offset();
+  }
 
   // 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));
@@ -669,13 +602,13 @@ class Assembler : public AssemblerBase {
       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;
+    ConstantPoolArray* 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;
+    ConstantPoolArray* constant_pool = NULL;
     set_target_address_at(pc, constant_pool, target, icache_flush_mode);
   }
 
@@ -695,6 +628,11 @@ class Assembler : public AssemblerBase {
   inline static void deserialization_set_special_target_at(
       Address instruction_payload, Code* code, Address target);
 
+  // This sets the internal reference at the pc.
+  inline static void deserialization_set_target_internal_reference_at(
+      Address pc, Address target,
+      RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
+
   // Size of an instruction.
   static const int kInstrSize = sizeof(Instr);
 
@@ -708,16 +646,11 @@ class Assembler : public AssemblerBase {
 
 // 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;
+  static const int kMovInstructions = 5;
+  static const int kTaggedLoadInstructions = 2;
 #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;
+  static const int kMovInstructions = 2;
+  static const int kTaggedLoadInstructions = 1;
 #endif
 
   // Distance between the instruction referring to the address of the call
@@ -747,15 +680,15 @@ class Assembler : public AssemblerBase {
   //   blrl
   static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
 
-  // This is the length of the BreakLocationIterator::SetDebugBreakAtReturn()
+  // This is the length of the BreakLocation::SetDebugBreakAtReturn()
   // code patch FIXED_SEQUENCE
-  static const int kJSReturnSequenceInstructions =
-      kMovInstructionsNoConstantPool + 3;
+  static const int kJSReturnSequenceInstructions = kMovInstructions + 3;
+  static const int kJSReturnSequenceLength =
+      kJSReturnSequenceInstructions * kInstrSize;
 
   // This is the length of the code sequence from SetDebugBreakAtSlot()
   // FIXED_SEQUENCE
-  static const int kDebugBreakSlotInstructions =
-      kMovInstructionsNoConstantPool + 2;
+  static const int kDebugBreakSlotInstructions = kMovInstructions + 2;
   static const int kDebugBreakSlotLength =
       kDebugBreakSlotInstructions * kInstrSize;
 
@@ -1076,11 +1009,26 @@ class Assembler : public AssemblerBase {
   void cmplw(Register src1, Register src2, CRegister cr = cr7);
 
   void mov(Register dst, const Operand& src);
+  void bitwise_mov(Register dst, intptr_t value);
+  void bitwise_mov32(Register dst, int32_t value);
+  void bitwise_add32(Register dst, Register src, int32_t value);
 
   // Load the position of the label relative to the generated code object
   // pointer in a register.
   void mov_label_offset(Register dst, Label* label);
 
+  // dst = base + label position + delta
+  void add_label_offset(Register dst, Register base, Label* label,
+                        int delta = 0);
+
+  // Load the address of the label in a register and associate with an
+  // internal reference relocation.
+  void mov_label_addr(Register dst, Label* label);
+
+  // Emit the address of the label (i.e. a jump table entry) and associate with
+  // an internal reference relocation.
+  void emit_label_addr(Label* label);
+
   // Multiply instructions
   void mul(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
            RCBit r = LeaveRC);
@@ -1283,13 +1231,14 @@ class Assembler : public AssemblerBase {
 
   // Record a deoptimization reason that can be used by a log or cpu profiler.
   // Use --trace-deopt to enable.
-  void RecordDeoptReason(const int reason, const int raw_position);
+  void RecordDeoptReason(const int reason, const SourcePosition position);
 
   // 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);
+  void emit_ptr(intptr_t data);
+  void emit_double(double data);
 
   PositionsRecorder* positions_recorder() { return &positions_recorder_; }
 
@@ -1335,22 +1284,12 @@ class Assembler : public AssemblerBase {
   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);
@@ -1358,23 +1297,7 @@ class Assembler : public AssemblerBase {
   // 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
+  void EmitRelocations();
 
  protected:
   // Relocation for a type-recording IC has the AST id added to it.  This
@@ -1392,13 +1315,7 @@ class Assembler : public AssemblerBase {
 
   // 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
+  void RecordRelocInfo(const DeferredRelocInfo& rinfo);
 
   // Block the emission of the trampoline pool before pc_offset.
   void BlockTrampolinePoolBefore(int pc_offset) {
@@ -1407,9 +1324,7 @@ class Assembler : public AssemblerBase {
   }
 
   void StartBlockTrampolinePool() { trampoline_pool_blocked_nesting_++; }
-
   void EndBlockTrampolinePool() { trampoline_pool_blocked_nesting_--; }
-
   bool is_trampoline_pool_blocked() const {
     return trampoline_pool_blocked_nesting_ > 0;
   }
@@ -1439,17 +1354,14 @@ class Assembler : public AssemblerBase {
   // Each relocation is encoded as a variable size value
   static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
   RelocInfoWriter reloc_info_writer;
+  std::vector<DeferredRelocInfo> relocations_;
 
   // 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();
+  void GrowBuffer(int needed = 0);
   inline void emit(Instr x);
   inline void CheckTrampolinePoolQuick();
 
index ca8704f..c6f0336 100644 (file)
@@ -125,6 +125,7 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
     __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
   }
 
+  __ mr(r6, r4);
   // Run the native code for the Array function called as a normal function.
   // tail call a stub
   __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
@@ -232,7 +233,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
   __ push(function);  // Preserve the function.
   __ IncrementCounter(counters->string_ctor_conversions(), 1, r6, r7);
   {
-    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    FrameScope scope(masm, StackFrame::INTERNAL);
     __ push(r3);
     __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
   }
@@ -252,7 +253,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
   __ bind(&gc_required);
   __ IncrementCounter(counters->string_ctor_gc_required(), 1, r6, r7);
   {
-    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    FrameScope scope(masm, StackFrame::INTERNAL);
     __ push(argument);
     __ CallRuntime(Runtime::kNewStringWrapper, 1);
   }
@@ -262,7 +263,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
 
 static void CallRuntimePassFunction(MacroAssembler* masm,
                                     Runtime::FunctionId function_id) {
-  FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+  FrameScope scope(masm, StackFrame::INTERNAL);
   // Push a copy of the function onto the stack.
   // Push function as parameter to the runtime call.
   __ Push(r4, r4);
@@ -353,7 +354,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
 
   // Enter a construct frame.
   {
-    FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT);
+    FrameScope scope(masm, StackFrame::CONSTRUCT);
 
     if (create_memento) {
       __ AssertUndefinedOrAllocationSite(r5, r7);
@@ -752,7 +753,7 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
   CHECK(!FLAG_pretenuring_call_new);
 
   {
-    FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT);
+    FrameScope scope(masm, StackFrame::CONSTRUCT);
 
     // Smi-tagged arguments count.
     __ mr(r7, r3);
@@ -760,7 +761,9 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
 
     // receiver is the hole.
     __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
-    __ Push(r7, ip);
+
+    // smi arguments count, new.target, receiver
+    __ Push(r7, r6, ip);
 
     // Set up pointer to last argument.
     __ addi(r5, fp, Operand(StandardFrameConstants::kCallerSPOffset));
@@ -772,7 +775,8 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
     // r7: number of arguments (smi-tagged)
     // cr0: compare against zero of arguments
     // sp[0]: receiver
-    // sp[1]: number of arguments (smi-tagged)
+    // sp[1]: new.target
+    // sp[2]: number of arguments (smi-tagged)
     Label loop, no_args;
     __ beq(&no_args, cr0);
     __ ShiftLeftImm(ip, r3, Operand(kPointerSizeLog2));
@@ -784,6 +788,23 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
     __ bdnz(&loop);
     __ bind(&no_args);
 
+    __ addi(r3, r3, Operand(1));
+
+    // Handle step in.
+    Label skip_step_in;
+    ExternalReference debug_step_in_fp =
+        ExternalReference::debug_step_in_fp_address(masm->isolate());
+    __ mov(r5, Operand(debug_step_in_fp));
+    __ LoadP(r5, MemOperand(r5));
+    __ and_(r0, r5, r5, SetRC);
+    __ beq(&skip_step_in, cr0);
+
+    __ Push(r3, r4, r4);
+    __ CallRuntime(Runtime::kHandleStepInForDerivedConstructors, 1);
+    __ Pop(r3, r4);
+
+    __ bind(&skip_step_in);
+
     // Call the function.
     // r3: number of arguments
     // r4: constructor function
@@ -896,12 +917,14 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
 
 
 static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
-  FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+  FrameScope 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));
+  __ LoadRoot(
+      r0, concurrent ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex);
+  __ push(r0);
 
   __ CallRuntime(Runtime::kCompileOptimized, 2);
   // Restore receiver.
@@ -1007,7 +1030,7 @@ void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
 static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
                                              SaveFPRegsMode save_doubles) {
   {
-    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    FrameScope 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
@@ -1036,7 +1059,7 @@ void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
 static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
                                              Deoptimizer::BailoutType type) {
   {
-    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    FrameScope scope(masm, StackFrame::INTERNAL);
     // Pass the function and deoptimization type to the runtime system.
     __ LoadSmiLiteral(r3, Smi::FromInt(static_cast<int>(type)));
     __ push(r3);
@@ -1084,7 +1107,7 @@ void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
   // Lookup the function in the JavaScript frame.
   __ LoadP(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
   {
-    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    FrameScope scope(masm, StackFrame::INTERNAL);
     // Pass function as argument.
     __ push(r3);
     __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
@@ -1102,12 +1125,8 @@ void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
   // <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
+    __ addi(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag));  // Code start
 
     // Load the OSR entrypoint offset from the deoptimization data.
     // <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset]
@@ -1116,17 +1135,13 @@ void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
                              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);
+    // Compute the target address = code start + osr_offset
+    __ add(r0, r3, r4);
 
     // And "return" to the OSR entry point of the function.
-    __ Ret();
-#if V8_OOL_CONSTANT_POOL
+    __ mtlr(r0);
+    __ blr();
   }
-#endif
 }
 
 
@@ -1137,7 +1152,7 @@ void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
   __ cmpl(sp, ip);
   __ bge(&ok);
   {
-    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    FrameScope scope(masm, StackFrame::INTERNAL);
     __ CallRuntime(Runtime::kStackGuard, 0);
   }
   __ Jump(masm->isolate()->builtins()->OnStackReplacement(),
@@ -1228,7 +1243,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
 
     {
       // Enter an internal frame in order to preserve argument count.
-      FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+      FrameScope scope(masm, StackFrame::INTERNAL);
       __ SmiTag(r3);
       __ Push(r3, r5);
       __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
@@ -1351,50 +1366,99 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
 }
 
 
-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;
+static void Generate_CheckStackOverflow(MacroAssembler* masm,
+                                        const int calleeOffset) {
+  // 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, calleeOffset));
+  __ Push(r4, r3);
+  __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+
+  __ bind(&okay);
+}
+
+
+static void Generate_PushAppliedArguments(MacroAssembler* masm,
+                                          const int argumentsOffset,
+                                          const int indexOffset,
+                                          const int limitOffset) {
+  Label entry, loop;
+  __ LoadP(r3, MemOperand(fp, indexOffset));
+  __ 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, argumentsOffset));
+  __ 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, indexOffset));
+  __ AddSmiLiteral(r3, r3, Smi::FromInt(1), r0);
+  __ StoreP(r3, MemOperand(fp, indexOffset));
+
+  // Test if the copy loop has finished copying all the elements from the
+  // arguments object.
+  __ bind(&entry);
+  __ LoadP(r4, MemOperand(fp, limitOffset));
+  __ cmp(r3, r4);
+  __ bne(&loop);
+
+  // On exit, the pushed arguments count is in r0, untagged
+  __ SmiUntag(r3);
+}
+
+
+// Used by FunctionApply and ReflectApply
+static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
+  const int kFormalParameters = targetIsArgument ? 3 : 2;
+  const int kStackSize = kFormalParameters + 1;
 
   {
-    FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL);
+    FrameScope frame_scope(masm, StackFrame::INTERNAL);
+    const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize;
+    const int kReceiverOffset = kArgumentsOffset + kPointerSize;
+    const int kFunctionOffset = kReceiverOffset + kPointerSize;
 
     __ LoadP(r3, MemOperand(fp, kFunctionOffset));  // get the function
     __ push(r3);
-    __ LoadP(r3, MemOperand(fp, kArgsOffset));  // get the args array
+    __ LoadP(r3, MemOperand(fp, kArgumentsOffset));  // 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.
+    if (targetIsArgument) {
+      __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION);
+    } else {
+      __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
+    }
+
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
 
     // Push current limit and index.
-    __ bind(&okay);
+    const int kIndexOffset =
+        StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
+    const int kLimitOffset =
+        StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
     __ li(r4, Operand::Zero());
     __ Push(r3, r4);  // limit and initial index.
 
     // Get the receiver.
-    __ LoadP(r3, MemOperand(fp, kRecvOffset));
+    __ LoadP(r3, MemOperand(fp, kReceiverOffset));
 
     // Check that the function is a JS function (otherwise it must be a proxy).
     Label push_receiver;
@@ -1462,43 +1526,18 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
     __ 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);
+    Generate_PushAppliedArguments(masm, kArgumentsOffset, kIndexOffset,
+                                  kLimitOffset);
 
     // 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);
+    __ LeaveFrame(StackFrame::INTERNAL, kStackSize * kPointerSize);
     __ blr();
 
     // Call the function proxy.
@@ -1512,11 +1551,90 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
 
     // Tear down the internal frame and remove function, receiver and args.
   }
-  __ addi(sp, sp, Operand(3 * kPointerSize));
+  __ addi(sp, sp, Operand(kStackSize * kPointerSize));
   __ blr();
 }
 
 
+static void Generate_ConstructHelper(MacroAssembler* masm) {
+  const int kFormalParameters = 3;
+  const int kStackSize = kFormalParameters + 1;
+
+  {
+    FrameScope frame_scope(masm, StackFrame::INTERNAL);
+    const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize;
+    const int kArgumentsOffset = kNewTargetOffset + kPointerSize;
+    const int kFunctionOffset = kArgumentsOffset + kPointerSize;
+
+    // If newTarget is not supplied, set it to constructor
+    Label validate_arguments;
+    __ LoadP(r3, MemOperand(fp, kNewTargetOffset));
+    __ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
+    __ bne(&validate_arguments);
+    __ LoadP(r3, MemOperand(fp, kFunctionOffset));
+    __ StoreP(r3, MemOperand(fp, kNewTargetOffset));
+
+    // Validate arguments
+    __ bind(&validate_arguments);
+    __ LoadP(r3, MemOperand(fp, kFunctionOffset));  // get the function
+    __ push(r3);
+    __ LoadP(r3, MemOperand(fp, kArgumentsOffset));  // get the args array
+    __ push(r3);
+    __ LoadP(r3, MemOperand(fp, kNewTargetOffset));  // get the new.target
+    __ push(r3);
+    __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION);
+
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
+
+    // Push current limit and index.
+    const int kIndexOffset =
+        StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
+    const int kLimitOffset =
+        StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
+    __ li(r4, Operand::Zero());
+    __ Push(r3, r4);  // limit and initial index.
+    // Push newTarget and callee functions
+    __ LoadP(r3, MemOperand(fp, kNewTargetOffset));
+    __ push(r3);
+    __ LoadP(r3, MemOperand(fp, kFunctionOffset));
+    __ push(r3);
+
+    // Copy all arguments from the array to the stack.
+    Generate_PushAppliedArguments(masm, kArgumentsOffset, kIndexOffset,
+                                  kLimitOffset);
+
+    // Use undefined feedback vector
+    __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
+    __ LoadP(r4, MemOperand(fp, kFunctionOffset));
+
+    // Call the function.
+    CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
+    __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
+
+    __ Drop(1);
+
+    // Leave internal frame.
+  }
+  __ addi(sp, sp, Operand(kStackSize * kPointerSize));
+  __ blr();
+}
+
+
+void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+  Generate_ApplyHelper(masm, false);
+}
+
+
+void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
+  Generate_ApplyHelper(masm, true);
+}
+
+
+void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
+  Generate_ConstructHelper(masm);
+}
+
+
 static void ArgumentAdaptorStackCheck(MacroAssembler* masm,
                                       Label* stack_overflow) {
   // ----------- S t a t e -------------
@@ -1543,11 +1661,7 @@ static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
   __ 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));
 }
index 0226ffb..589f6d8 100644 (file)
@@ -12,6 +12,7 @@
 #include "src/codegen.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
@@ -110,7 +111,7 @@ void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm,
   int param_count = descriptor.GetEnvironmentParameterCount();
   {
     // Call the runtime system in a fresh internal frame.
-    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    FrameScope scope(masm, StackFrame::INTERNAL);
     DCHECK(param_count == 0 ||
            r3.is(descriptor.GetEnvironmentParameterRegister(param_count - 1)));
     // Push arguments
@@ -1070,22 +1071,11 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // 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);
-  }
+  Label after_call;
+  __ mov_label_addr(r0, &after_call);
+  __ StoreP(r0, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize));
+  __ Call(target);
+  __ bind(&after_call);
 
 #if !ABI_RETURNS_OBJECT_PAIRS_IN_REGS
   // If return value is on the stack, pop it to registers.
@@ -1110,13 +1100,13 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   __ 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;
+    ExternalReference pending_exception_address(
+        Isolate::kPendingExceptionAddress, isolate());
+
     __ mov(r5, Operand(pending_exception_address));
     __ LoadP(r5, MemOperand(r5));
     __ CompareRoot(r5, Heap::kTheHoleValueRootIndex);
@@ -1137,25 +1127,53 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // 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);
+  ExternalReference pending_handler_context_address(
+      Isolate::kPendingHandlerContextAddress, isolate());
+  ExternalReference pending_handler_code_address(
+      Isolate::kPendingHandlerCodeAddress, isolate());
+  ExternalReference pending_handler_offset_address(
+      Isolate::kPendingHandlerOffsetAddress, isolate());
+  ExternalReference pending_handler_fp_address(
+      Isolate::kPendingHandlerFPAddress, isolate());
+  ExternalReference pending_handler_sp_address(
+      Isolate::kPendingHandlerSPAddress, isolate());
+
+  // Ask the runtime for help to determine the handler. This will set r3 to
+  // contain the current pending exception, don't clobber it.
+  ExternalReference find_handler(Runtime::kFindExceptionHandler, isolate());
+  {
+    FrameScope scope(masm, StackFrame::MANUAL);
+    __ PrepareCallCFunction(3, 0, r3);
+    __ li(r3, Operand::Zero());
+    __ li(r4, Operand::Zero());
+    __ mov(r5, Operand(ExternalReference::isolate_address(isolate())));
+    __ CallCFunction(find_handler, 3);
+  }
 
-  __ bind(&throw_termination_exception);
-  __ ThrowUncatchable(r3);
+  // Retrieve the handler context, SP and FP.
+  __ mov(cp, Operand(pending_handler_context_address));
+  __ LoadP(cp, MemOperand(cp));
+  __ mov(sp, Operand(pending_handler_sp_address));
+  __ LoadP(sp, MemOperand(sp));
+  __ mov(fp, Operand(pending_handler_fp_address));
+  __ LoadP(fp, MemOperand(fp));
+
+  // If the handler is a JS frame, restore the context to the frame. Note that
+  // the context will be set to (cp == 0) for non-JS frames.
+  Label skip;
+  __ cmpi(cp, Operand::Zero());
+  __ beq(&skip);
+  __ StoreP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  __ bind(&skip);
+
+  // Compute the handler entry address and jump to it.
+  __ mov(r4, Operand(pending_handler_code_address));
+  __ LoadP(r4, MemOperand(r4));
+  __ mov(r5, Operand(pending_handler_offset_address));
+  __ LoadP(r5, MemOperand(r5));
+  __ addi(r4, r4, Operand(Code::kHeaderSize - kHeapObjectTag));  // Code start
+  __ add(ip, r4, r5);
+  __ Jump(ip);
 }
 
 
@@ -1195,11 +1213,6 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   // 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);
@@ -1236,7 +1249,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   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
+  // fp will be invalid because the PushStackHandler below sets it to 0 to
   // signal the existence of the JSEntry frame.
   __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
                                        isolate())));
@@ -1245,11 +1258,10 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ 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.
+  // Invoke: Link this frame into the handler chain.
   __ bind(&invoke);
-  // Must preserve r0-r4, r5-r7 are available. (needs update for PPC)
-  __ PushTryHandler(StackHandler::JS_ENTRY, 0);
+  // Must preserve r3-r7.
+  __ PushStackHandler();
   // 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
@@ -1288,7 +1300,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ bctrl();  // make the call
 
   // Unlink this frame from the handler chain.
-  __ PopTryHandler();
+  __ PopStackHandler();
 
   __ bind(&exit);  // r3 holds result
   // Check if the current stack frame is marked as the outermost JS frame.
@@ -1347,14 +1359,10 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
   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
+  // delta = mov + tagged LoadP + cmp + bne
   const int32_t kDeltaToLoadBoolResult =
-      (Assembler::kMovInstructions + 3) * Assembler::kInstrSize;
-#endif
+      (Assembler::kMovInstructions + Assembler::kTaggedLoadInstructions + 2) *
+      Assembler::kInstrSize;
 
   Label slow, loop, is_instance, is_not_instance, not_js_object;
 
@@ -1514,7 +1522,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
     __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
   } else {
     {
-      FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+      FrameScope scope(masm, StackFrame::INTERNAL);
       __ Push(r3, r4);
       __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
     }
@@ -1584,7 +1592,7 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
   __ Ret();
 
   StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
+  char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&miss);
   PropertyAccessCompiler::TailCallBuiltin(
@@ -1593,6 +1601,7 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
 
 
 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
+  CHECK(!has_new_target());
   // The displacement is the offset of the last parameter (if any)
   // relative to the frame pointer.
   const int kDisplacement =
@@ -1653,6 +1662,8 @@ void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
   // sp[1] : receiver displacement
   // sp[2] : function
 
+  CHECK(!has_new_target());
+
   // Check if the calling frame is an arguments adaptor frame.
   Label runtime;
   __ LoadP(r6, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
@@ -1683,6 +1694,8 @@ void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
   //  r9 : allocated object (tagged)
   //  r11 : mapped parameter count (tagged)
 
+  CHECK(!has_new_target());
+
   __ LoadP(r4, MemOperand(sp, 0 * kPointerSize));
   // r4 = parameter count (tagged)
 
@@ -1965,6 +1978,14 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
   // Patch the arguments.length and the parameters pointer.
   __ bind(&adaptor_frame);
   __ LoadP(r4, MemOperand(r5, ArgumentsAdaptorFrameConstants::kLengthOffset));
+  if (has_new_target()) {
+    __ CmpSmiLiteral(r4, Smi::FromInt(0), r0);
+    Label skip_decrement;
+    __ beq(&skip_decrement);
+    // Subtract 1 from smi-tagged arguments count.
+    __ SubSmiLiteral(r4, r4, Smi::FromInt(1), r0);
+    __ bind(&skip_decrement);
+  }
   __ StoreP(r4, MemOperand(sp, 0));
   __ SmiToPtrArrayOffset(r6, r4);
   __ add(r6, r5, r6);
@@ -2051,12 +2072,37 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
 }
 
 
+void RestParamAccessStub::GenerateNew(MacroAssembler* masm) {
+  // Stack layout on entry.
+  //  sp[0] : index of rest parameter
+  //  sp[4] : number of parameters
+  //  sp[8] : receiver displacement
+
+  Label runtime;
+  __ LoadP(r5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ LoadP(r6, MemOperand(r5, StandardFrameConstants::kContextOffset));
+  __ CmpSmiLiteral(r6, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
+  __ bne(&runtime);
+
+  // Patch the arguments.length and the parameters pointer.
+  __ LoadP(r4, MemOperand(r5, ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ StoreP(r4, MemOperand(sp, 1 * kPointerSize));
+  __ SmiToPtrArrayOffset(r6, r4);
+  __ add(r6, r5, r6);
+  __ addi(r6, r6, Operand(StandardFrameConstants::kCallerSPOffset));
+  __ StoreP(r6, MemOperand(sp, 2 * kPointerSize));
+
+  __ bind(&runtime);
+  __ TailCallRuntime(Runtime::kNewRestParam, 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);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 #else  // V8_INTERPRETED_REGEXP
 
   // Stack frame on entry.
@@ -2323,20 +2369,20 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
 
   __ LeaveExitFrame(false, no_reg, true);
 
-  // r3: result
+  // r3: result (int32)
   // 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));
+  __ cmpwi(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));
+  __ cmpwi(r3, Operand(NativeRegExpMacroAssembler::FAILURE));
   __ beq(&failure);
-  __ cmpi(r3, Operand(NativeRegExpMacroAssembler::EXCEPTION));
+  __ cmpwi(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
@@ -2350,18 +2396,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   __ 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);
+  // For exception, throw the exception again.
+  __ TailCallRuntime(Runtime::kRegExpExecReThrow, 4, 1);
 
   __ bind(&failure);
   // For failure and exception return null.
@@ -2450,7 +2486,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
 
   // Do the runtime call to execute the regexp.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 
   // Deferred code for string handling.
   // (6) Not a long external string?  If yes, go to (8).
@@ -2562,7 +2598,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
     // Create an AllocationSite if we don't already have it, store it in the
     // slot.
     {
-      FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+      FrameScope scope(masm, StackFrame::INTERNAL);
 
       // Arguments register must be smi-tagged to call out.
       __ SmiTag(r3);
@@ -2648,7 +2684,7 @@ static void EmitSlowCase(MacroAssembler* masm, int argc, Label* non_function) {
 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);
+    FrameScope frame_scope(masm, StackFrame::INTERNAL);
     __ Push(r4, r6);
     __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
     __ pop(r4);
@@ -2760,7 +2796,13 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
   }
 
   // Pass function as original constructor.
-  __ mr(r6, r4);
+  if (IsSuperConstructorCall()) {
+    __ ShiftLeftImm(r7, r3, Operand(kPointerSizeLog2));
+    __ addi(r7, r7, Operand(kPointerSize));
+    __ LoadPX(r6, MemOperand(sp, r7));
+  } else {
+    __ mr(r6, r4);
+  }
 
   // Jump to the function-specific construct stub.
   Register jmp_reg = r7;
@@ -2823,6 +2865,7 @@ void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
   __ bne(&miss);
 
   __ mr(r5, r7);
+  __ mr(r6, r4);
   ArrayConstructorStub stub(masm->isolate(), arg_count());
   __ TailCallStub(&stub);
 
@@ -2959,7 +3002,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
   // r6 - slot
   // r4 - function
   {
-    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    FrameScope scope(masm, StackFrame::INTERNAL);
     CreateWeakCellStub create_stub(masm->isolate());
     __ Push(r4);
     __ CallStub(&create_stub);
@@ -2987,7 +3030,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
 
 
 void CallICStub::GenerateMiss(MacroAssembler* masm) {
-  FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+  FrameScope scope(masm, StackFrame::INTERNAL);
 
   // Push the function and feedback info.
   __ Push(r4, r5, r6);
@@ -3038,7 +3081,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
 
 
 void StringCharCodeAtGenerator::GenerateSlow(
-    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
+    MacroAssembler* masm, EmbedMode embed_mode,
+    const RuntimeCallHelper& call_helper) {
   __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
 
   // Index is not a smi.
@@ -3047,8 +3091,13 @@ void StringCharCodeAtGenerator::GenerateSlow(
   __ 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 (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ Push(VectorLoadICDescriptor::VectorRegister(),
+            VectorLoadICDescriptor::SlotRegister(), object_, index_);
+  } else {
+    // index_ is consumed by runtime conversion function.
+    __ Push(object_, index_);
+  }
   if (index_flags_ == STRING_INDEX_IS_NUMBER) {
     __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
   } else {
@@ -3059,7 +3108,12 @@ void StringCharCodeAtGenerator::GenerateSlow(
   // Save the conversion result before the pop instructions below
   // have a chance to overwrite it.
   __ Move(index_, r3);
-  __ pop(object_);
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ Pop(VectorLoadICDescriptor::VectorRegister(),
+           VectorLoadICDescriptor::SlotRegister(), object_);
+  } else {
+    __ pop(object_);
+  }
   // Reload the instance type.
   __ LoadP(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
   __ lbz(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
@@ -3371,7 +3425,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
 
   // Just jump to runtime to create the sub string.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kSubString, 3, 1);
+  __ TailCallRuntime(Runtime::kSubStringRT, 3, 1);
 
   __ bind(&single_char);
   // r3: original string
@@ -3504,8 +3558,8 @@ void StringHelper::GenerateCompareFlatOneByteStrings(
   // Conditionally update the result based either on length_delta or
   // the last comparion performed in the loop above.
   if (CpuFeatures::IsSupported(ISELECT)) {
-    __ li(r4, Operand(GREATER));
-    __ li(r5, Operand(LESS));
+    __ LoadSmiLiteral(r4, Smi::FromInt(GREATER));
+    __ LoadSmiLiteral(r5, Smi::FromInt(LESS));
     __ isel(eq, r3, r0, r4);
     __ isel(lt, r3, r5, r3);
     __ Ret();
@@ -3584,7 +3638,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
   // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
   // tagged as a small integer.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+  __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
 }
 
 
@@ -3890,7 +3944,7 @@ void CompareICStub::GenerateStrings(MacroAssembler* masm) {
   if (equality) {
     __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
   } else {
-    __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+    __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
   }
 
   __ bind(&miss);
@@ -3945,7 +3999,7 @@ void CompareICStub::GenerateMiss(MacroAssembler* masm) {
     ExternalReference miss =
         ExternalReference(IC_Utility(IC::kCompareIC_Miss), isolate());
 
-    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    FrameScope scope(masm, StackFrame::INTERNAL);
     __ Push(r4, r3);
     __ Push(r4, r3);
     __ LoadSmiLiteral(r0, Smi::FromInt(op()));
@@ -4509,15 +4563,15 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
 
 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorLoadStub stub(isolate(), state());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawLoadStub stub(isolate(), state());
+  stub.GenerateForTrampoline(masm);
 }
 
 
 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorKeyedLoadStub stub(isolate());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawKeyedLoadStub stub(isolate());
+  stub.GenerateForTrampoline(masm);
 }
 
 
@@ -4535,6 +4589,248 @@ void CallIC_ArrayTrampolineStub::Generate(MacroAssembler* masm) {
 }
 
 
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+                             Register key, Register vector, Register slot,
+                             Register feedback, Register scratch1,
+                             Register scratch2, Register scratch3,
+                             bool is_polymorphic, Label* miss) {
+  // feedback initially contains the feedback array
+  Label next_loop, prepare_next;
+  Label load_smi_map, compare_map;
+  Label start_polymorphic;
+
+  Register receiver_map = scratch1;
+  Register cached_map = scratch2;
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &load_smi_map);
+  __ LoadP(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ bind(&compare_map);
+  __ LoadP(cached_map,
+           FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+  __ LoadP(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ cmp(receiver_map, cached_map);
+  __ bne(&start_polymorphic);
+  // found, now call handler.
+  Register handler = feedback;
+  __ LoadP(handler,
+           FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+  __ addi(ip, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(ip);
+
+
+  Register length = scratch3;
+  __ bind(&start_polymorphic);
+  __ LoadP(length, FieldMemOperand(feedback, FixedArray::kLengthOffset));
+  if (!is_polymorphic) {
+    // If the IC could be monomorphic we have to make sure we don't go past the
+    // end of the feedback array.
+    __ CmpSmiLiteral(length, Smi::FromInt(2), r0);
+    __ beq(miss);
+  }
+
+  Register too_far = length;
+  Register pointer_reg = feedback;
+
+  // +-----+------+------+-----+-----+ ... ----+
+  // | map | len  | wm0  | h0  | wm1 |      hN |
+  // +-----+------+------+-----+-----+ ... ----+
+  //                 0      1     2        len-1
+  //                              ^              ^
+  //                              |              |
+  //                         pointer_reg      too_far
+  //                         aka feedback     scratch3
+  // also need receiver_map (aka scratch1)
+  // use cached_map (scratch2) to look in the weak map values.
+  __ SmiToPtrArrayOffset(r0, length);
+  __ add(too_far, feedback, r0);
+  __ addi(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ addi(pointer_reg, feedback,
+          Operand(FixedArray::OffsetOfElementAt(2) - kHeapObjectTag));
+
+  __ bind(&next_loop);
+  __ LoadP(cached_map, MemOperand(pointer_reg));
+  __ LoadP(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ cmp(receiver_map, cached_map);
+  __ bne(&prepare_next);
+  __ LoadP(handler, MemOperand(pointer_reg, kPointerSize));
+  __ addi(ip, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(ip);
+
+  __ bind(&prepare_next);
+  __ addi(pointer_reg, pointer_reg, Operand(kPointerSize * 2));
+  __ cmp(pointer_reg, too_far);
+  __ blt(&next_loop);
+
+  // We exhausted our array of map handler pairs.
+  __ b(miss);
+
+  __ bind(&load_smi_map);
+  __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
+  __ b(&compare_map);
+}
+
+
+static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+                                  Register key, Register vector, Register slot,
+                                  Register weak_cell, Register scratch,
+                                  Label* miss) {
+  // feedback initially contains the feedback array
+  Label compare_smi_map;
+  Register receiver_map = scratch;
+  Register cached_map = weak_cell;
+
+  // Move the weak map into the weak_cell register.
+  __ LoadP(cached_map, FieldMemOperand(weak_cell, WeakCell::kValueOffset));
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &compare_smi_map);
+  __ LoadP(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ cmp(cached_map, receiver_map);
+  __ bne(miss);
+
+  Register handler = weak_cell;
+  __ SmiToPtrArrayOffset(r0, slot);
+  __ add(handler, vector, r0);
+  __ LoadP(handler,
+           FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ addi(ip, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(ip);
+
+  // In microbenchmarks, it made sense to unroll this code so that the call to
+  // the handler is duplicated for a HeapObject receiver and a Smi receiver.
+  __ bind(&compare_smi_map);
+  __ CompareRoot(weak_cell, Heap::kHeapNumberMapRootIndex);
+  __ bne(miss);
+  __ SmiToPtrArrayOffset(r0, slot);
+  __ add(handler, vector, r0);
+  __ LoadP(handler,
+           FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ addi(ip, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(ip);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // r4
+  Register name = VectorLoadICDescriptor::NameRegister();          // r5
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // r6
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // r3
+  Register feedback = r7;
+  Register scratch1 = r8;
+
+  __ SmiToPtrArrayOffset(r0, slot);
+  __ add(feedback, vector, r0);
+  __ LoadP(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ LoadP(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ CompareRoot(scratch1, Heap::kWeakCellMapRootIndex);
+  __ bne(&try_array);
+  HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback, scratch1,
+                        &miss);
+
+  // Is it a fixed array?
+  __ bind(&try_array);
+  __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex);
+  __ bne(&not_array);
+  HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, r9,
+                   r10, true, &miss);
+
+  __ bind(&not_array);
+  __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+  __ bne(&miss);
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, code_flags,
+                                               false, receiver, name, feedback,
+                                               scratch1, r9, r10);
+
+  __ bind(&miss);
+  LoadIC::GenerateMiss(masm);
+}
+
+
+void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // r4
+  Register key = VectorLoadICDescriptor::NameRegister();           // r5
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // r6
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // r3
+  Register feedback = r7;
+  Register scratch1 = r8;
+
+  __ SmiToPtrArrayOffset(r0, slot);
+  __ add(feedback, vector, r0);
+  __ LoadP(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ LoadP(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ CompareRoot(scratch1, Heap::kWeakCellMapRootIndex);
+  __ bne(&try_array);
+  HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, scratch1,
+                        &miss);
+
+  __ bind(&try_array);
+  // Is it a fixed array?
+  __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex);
+  __ bne(&not_array);
+
+  // We have a polymorphic element handler.
+  Label polymorphic, try_poly_name;
+  __ bind(&polymorphic);
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, r9,
+                   r10, true, &miss);
+
+  __ bind(&not_array);
+  // Is it generic?
+  __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+  __ bne(&try_poly_name);
+  Handle<Code> megamorphic_stub =
+      KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+  __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET);
+
+  __ bind(&try_poly_name);
+  // We might have a name in feedback, and a fixed array in the next slot.
+  __ cmp(key, feedback);
+  __ bne(&miss);
+  // If the name comparison succeeded, we know we have a fixed array with
+  // at least one map/handler pair.
+  __ SmiToPtrArrayOffset(r0, slot);
+  __ add(feedback, vector, r0);
+  __ LoadP(feedback,
+           FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, r9,
+                   r10, false, &miss);
+
+  __ bind(&miss);
+  KeyedLoadIC::GenerateMiss(masm);
+}
+
+
 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
   if (masm->isolate()->function_entry_hook() != NULL) {
     PredictableCodeSizeScope predictable(masm,
@@ -4802,6 +5098,7 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
   //  -- r3 : argc (only if argument_count() == ANY)
   //  -- r4 : constructor
   //  -- r5 : AllocationSite or undefined
+  //  -- r6 : original constructor
   //  -- sp[0] : return address
   //  -- sp[4] : last argument
   // -----------------------------------
@@ -4822,6 +5119,10 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
     __ AssertUndefinedOrAllocationSite(r5, r7);
   }
 
+  Label subclassing;
+  __ cmp(r6, r4);
+  __ bne(&subclassing);
+
   Label no_info;
   // Get the elements kind and case on that.
   __ CompareRoot(r5, Heap::kUndefinedValueRootIndex);
@@ -4835,6 +5136,27 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
 
   __ bind(&no_info);
   GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
+
+  __ bind(&subclassing);
+  __ push(r4);
+  __ push(r6);
+
+  // Adjust argc.
+  switch (argument_count()) {
+    case ANY:
+    case MORE_THAN_ONE:
+      __ addi(r3, r3, Operand(2));
+      break;
+    case NONE:
+      __ li(r3, Operand(2));
+      break;
+    case ONE:
+      __ li(r3, Operand(3));
+      break;
+  }
+
+  __ JumpToExternalReference(
+      ExternalReference(Runtime::kArrayConstructorWithSubclassing, isolate()));
 }
 
 
@@ -4997,7 +5319,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
   }
 
   Label promote_scheduled_exception;
-  Label exception_handled;
   Label delete_allocated_handles;
   Label leave_exit_frame;
   Label return_value_loaded;
@@ -5019,15 +5340,8 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
   __ cmp(r15, r0);
   __ bne(&delete_allocated_handles);
 
-  // Check if the function scheduled an exception.
+  // Leave the API exit frame.
   __ 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);
@@ -5039,15 +5353,19 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
     __ mov(r14, Operand(stack_space));
   }
   __ LeaveExitFrame(false, r14, !restore_context, stack_space_operand != NULL);
+
+  // Check if the function scheduled an exception.
+  __ LoadRoot(r14, Heap::kTheHoleValueRootIndex);
+  __ mov(r15, Operand(ExternalReference::scheduled_exception_address(isolate)));
+  __ LoadP(r15, MemOperand(r15));
+  __ cmp(r14, r15);
+  __ bne(&promote_scheduled_exception);
+
   __ blr();
 
+  // Re-throw by promoting a scheduled exception.
   __ bind(&promote_scheduled_exception);
-  {
-    FrameScope frame(masm, StackFrame::INTERNAL);
-    __ CallExternalReference(
-        ExternalReference(Runtime::kPromoteScheduledException, isolate), 0);
-  }
-  __ jmp(&exception_handled);
+  __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
 
   // HandleScope limit has changed. Delete allocated extensions.
   __ bind(&delete_allocated_handles);
index 93d32c2..c0398ae 100644 (file)
@@ -646,9 +646,9 @@ void Code::GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age,
     *age = kNoAgeCodeAge;
     *parity = NO_MARKING_PARITY;
   } else {
-    ConstantPoolArray* constant_pool = NULL;
-    Address target_address = Assembler::target_address_at(
-        sequence + kCodeAgingTargetDelta, constant_pool);
+    Code* code = NULL;
+    Address target_address =
+        Assembler::target_address_at(sequence + kCodeAgingTargetDelta, code);
     Code* stub = GetCodeFromTargetAddress(target_address);
     GetCodeAgeAndParity(stub, age, parity);
   }
index 8106853..f59f637 100644 (file)
 namespace v8 {
 namespace internal {
 
-bool BreakLocationIterator::IsDebugBreakAtReturn() {
-  return Debug::IsDebugBreakAtReturn(rinfo());
-}
-
-
-void BreakLocationIterator::SetDebugBreakAtReturn() {
+void BreakLocation::SetDebugBreakAtReturn() {
   // Patch the code changing the return from JS function sequence from
   //
   //   LeaveFrame
@@ -31,7 +26,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
   //   blrl
   //   bkpt
   //
-  CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
+  CodePatcher patcher(pc(), Assembler::kJSReturnSequenceInstructions);
   Assembler::BlockTrampolinePoolScope block_trampoline_pool(patcher.masm());
   patcher.masm()->mov(
       v8::internal::r0,
@@ -45,29 +40,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
 }
 
 
-// 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() {
+void BreakLocation::SetDebugBreakAtSlot() {
   DCHECK(IsDebugBreakSlot());
   // Patch the code changing the debug break slot code from
   //
@@ -83,7 +56,7 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
   //   mtlr r0
   //   blrl
   //
-  CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
+  CodePatcher patcher(pc(), Assembler::kDebugBreakSlotInstructions);
   Assembler::BlockTrampolinePoolScope block_trampoline_pool(patcher.masm());
   patcher.masm()->mov(
       v8::internal::r0,
@@ -94,13 +67,6 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
 }
 
 
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
-  DCHECK(IsDebugBreakSlot());
-  rinfo()->PatchCode(original_rinfo()->pc(),
-                     Assembler::kDebugBreakSlotInstructions);
-}
-
-
 #define __ ACCESS_MASM(masm)
 
 
@@ -108,7 +74,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
                                           RegList object_regs,
                                           RegList non_object_regs) {
   {
-    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    FrameScope scope(masm, StackFrame::INTERNAL);
 
     // Load padding words on stack.
     __ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingValue));
@@ -317,8 +283,7 @@ void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
   __ LoadP(r4, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset -
                                   kPointerSize));
 
-  // Pop return address, frame and constant pool pointer (if
-  // FLAG_enable_ool_constant_pool).
+  // Pop return address and frame
   __ LeaveFrame(StackFrame::INTERNAL);
 
   // Load context from the function.
index ac1504c..74c88e3 100644 (file)
@@ -142,7 +142,7 @@ bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
 
 // This code tries to be close to ia32 code so that any changes can be
 // easily ported.
-void Deoptimizer::EntryGenerator::Generate() {
+void Deoptimizer::TableEntryGenerator::Generate() {
   GeneratePrologue();
 
   // Unlike on ARM we don't save all the registers, just the useful ones.
@@ -172,6 +172,9 @@ void Deoptimizer::EntryGenerator::Generate() {
     }
   }
 
+  __ mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
+  __ StoreP(fp, MemOperand(ip));
+
   const int kSavedRegistersAreaSize =
       (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
 
@@ -353,13 +356,8 @@ void FrameDescription::SetCallerFp(unsigned offset, intptr_t 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
 }
 
 
index 3472828..2486741 100644 (file)
@@ -988,6 +988,15 @@ int Decoder::InstructionDecode(byte* instr_ptr) {
   out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%08x       ",
                               instr->InstructionBits());
 
+#if ABI_USES_FUNCTION_DESCRIPTORS
+  // The first field will be identified as a jump table entry.  We emit the rest
+  // of the structure as zero, so just skip past them.
+  if (instr->InstructionBits() == 0) {
+    Format(instr, "constant");
+    return Instruction::kInstrSize;
+  }
+#endif
+
   switch (instr->OpcodeValue() << 26) {
     case TWI: {
       PrintSoftwareInterrupt(instr->SvcValue());
index 4b52882..00af7c9 100644 (file)
@@ -21,38 +21,22 @@ 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
index f00fa66..40a68b3 100644 (file)
@@ -57,15 +57,8 @@ 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).
@@ -123,13 +116,8 @@ class EntryFrameConstants : public AllStatic {
 
 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;
 
@@ -193,9 +181,6 @@ inline Object* JavaScriptFrame::function_slot_object() const {
 }
 
 
-inline void StackHandler::SetFp(Address slot, Address fp) {
-  Memory::Address_at(slot) = fp;
-}
 }
 }  // namespace v8::internal
 
index 26503c8..a12f17e 100644 (file)
@@ -104,7 +104,8 @@ class JumpPatchSite BASE_EMBEDDED {
 void FullCodeGenerator::Generate() {
   CompilationInfo* info = info_;
   handler_table_ =
-      isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
+      Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray(
+          HandlerTable::LengthForRange(function()->handler_count()), TENURED));
 
   profiling_counter_ = isolate()->factory()->NewCell(
       Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
@@ -200,9 +201,9 @@ void FullCodeGenerator::Generate() {
     // 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()) {
+    if (info->scope()->is_script_scope()) {
       __ push(r4);
-      __ Push(info->scope()->GetScopeInfo());
+      __ Push(info->scope()->GetScopeInfo(info->isolate()));
       __ CallRuntime(Runtime::kNewScriptContext, 2);
     } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
       FastNewContextStub stub(isolate(), heap_slots);
@@ -245,6 +246,35 @@ void FullCodeGenerator::Generate() {
     }
   }
 
+  ArgumentsAccessStub::HasNewTarget has_new_target =
+      IsSubclassConstructor(info->function()->kind())
+          ? ArgumentsAccessStub::HAS_NEW_TARGET
+          : ArgumentsAccessStub::NO_NEW_TARGET;
+
+  // Possibly allocate RestParameters
+  int rest_index;
+  Variable* rest_param = scope()->rest_parameter(&rest_index);
+  if (rest_param) {
+    Comment cmnt(masm_, "[ Allocate rest parameter array");
+
+    int num_parameters = info->scope()->num_parameters();
+    int offset = num_parameters * kPointerSize;
+    if (has_new_target == ArgumentsAccessStub::HAS_NEW_TARGET) {
+      --num_parameters;
+      ++rest_index;
+    }
+
+    __ addi(r6, fp, Operand(StandardFrameConstants::kCallerSPOffset + offset));
+    __ mov(r5, Operand(Smi::FromInt(num_parameters)));
+    __ mov(r4, Operand(Smi::FromInt(rest_index)));
+    __ Push(r6, r5, r4);
+
+    RestParamAccessStub stub(isolate());
+    __ CallStub(&stub);
+
+    SetVar(rest_param, r3, r4, r5);
+  }
+
   Variable* arguments = scope()->arguments();
   if (arguments != NULL) {
     // Function uses arguments object.
@@ -267,14 +297,14 @@ void FullCodeGenerator::Generate() {
     // The stub will rewrite receiever and parameter count if the previous
     // stack frame was an arguments adapter frame.
     ArgumentsAccessStub::Type type;
-    if (is_strict(language_mode())) {
+    if (is_strict(language_mode()) || !is_simple_parameter_list()) {
       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);
+    ArgumentsAccessStub stub(isolate(), type, has_new_target);
     __ CallStub(&stub);
 
     SetVar(arguments, r3, r4, r5);
@@ -432,7 +462,11 @@ void FullCodeGenerator::EmitReturnSequence() {
     // sequence.
     {
       Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
-      int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize;
+      int32_t arg_count = info_->scope()->num_parameters() + 1;
+      if (IsSubclassConstructor(info_->function()->kind())) {
+        arg_count++;
+      }
+      int32_t sp_delta = arg_count * kPointerSize;
       CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
       __ RecordJSReturn();
       int no_frame_start = __ LeaveFrame(StackFrame::JAVA_SCRIPT, sp_delta);
@@ -440,9 +474,7 @@ void FullCodeGenerator::EmitReturnSequence() {
       // 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
@@ -1457,7 +1489,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
                Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
       }
-      CallLoadIC(CONTEXTUAL);
+      CallGlobalLoadIC(var->name());
       context()->Plug(r3);
       break;
     }
@@ -2101,7 +2133,6 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
 
       // 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
@@ -2112,16 +2143,17 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       // re-boxing.
       __ bind(&l_try);
       __ pop(r3);  // result
-      __ PushTryHandler(StackHandler::CATCH, expr->index());
-      const int handler_size = StackHandlerConstants::kSize;
+      EnterTryBlock(expr->index(), &l_catch);
+      const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ push(r3);  // result
       __ b(&l_suspend);
       __ bind(&l_continuation);
       __ b(&l_resume);
       __ bind(&l_suspend);
-      const int generator_object_depth = kPointerSize + handler_size;
+      const int generator_object_depth = kPointerSize + try_block_size;
       __ LoadP(r3, MemOperand(sp, generator_object_depth));
       __ push(r3);  // g
+      __ Push(Smi::FromInt(expr->index()));  // handler-index
       DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
       __ LoadSmiLiteral(r4, Smi::FromInt(l_continuation.pos()));
       __ StoreP(r4, FieldMemOperand(r3, JSGeneratorObject::kContinuationOffset),
@@ -2130,12 +2162,12 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       __ mr(r4, cp);
       __ RecordWriteField(r3, JSGeneratorObject::kContextOffset, r4, r5,
                           kLRHasBeenSaved, kDontSaveFPRegs);
-      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 2);
       __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
       __ pop(r3);  // result
       EmitReturnSequence();
       __ bind(&l_resume);  // received in r3
-      __ PopTryHandler();
+      ExitTryBlock(expr->index());
 
       // receiver = iter; f = 'next'; arg = received;
       __ bind(&l_next);
@@ -2256,13 +2288,7 @@ void FullCodeGenerator::EmitGeneratorResume(
     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);
@@ -2272,9 +2298,7 @@ void FullCodeGenerator::EmitGeneratorResume(
                 r0);
       __ Jump(ip);
       __ bind(&slow_resume);
-#if V8_OOL_CONSTANT_POOL
     }
-#endif
   } else {
     __ beq(&call_resume, cr0);
   }
@@ -2538,6 +2562,16 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
     }
     __ push(scratch);
     EmitPropertyKey(property, lit->GetIdForProperty(i));
+
+    // The static prototype property is read only. We handle the non computed
+    // property name case in the parser. Since this is the only case where we
+    // need to check for an own read only property we special case this so we do
+    // not need to do this for every property.
+    if (property->is_static() && property->is_computed_name()) {
+      __ CallRuntime(Runtime::kThrowIfStaticPrototype, 1);
+      __ push(r3);
+    }
+
     VisitForStackValue(value);
     EmitSetHomeObjectIfNeeded(value, 2);
 
@@ -2681,25 +2715,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
     __ 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());
@@ -2716,6 +2731,21 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
     __ bind(&assign);
     EmitStoreToStackLocalOrContextSlot(var, location);
 
+  } else if (var->mode() == CONST && op != Token::INIT_CONST) {
+    // Assignment to const variable needs a write barrier.
+    DCHECK(!var->IsLookupSlot());
+    DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+    Label const_error;
+    MemOperand location = VarOperand(var, r4);
+    __ LoadP(r6, location);
+    __ CompareRoot(r6, Heap::kTheHoleValueRootIndex);
+    __ bne(&const_error);
+    __ mov(r6, Operand(var->name()));
+    __ push(r6);
+    __ CallRuntime(Runtime::kThrowReferenceError, 1);
+    __ bind(&const_error);
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
   } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
     if (var->IsLookupSlot()) {
       // Assignment to var.
@@ -2737,8 +2767,32 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
-  } else if (IsSignallingAssignmentToConst(var, op, language_mode())) {
-    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+  } else if (op == Token::INIT_CONST_LEGACY) {
+    // Const initializers need a write barrier.
+    DCHECK(var->mode() == CONST_LEGACY);
+    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 {
+    DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT_CONST_LEGACY);
+    if (is_strict(language_mode())) {
+      __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+    }
+    // Silently ignore store in sloppy mode.
   }
 }
 
@@ -2865,7 +2919,8 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
     }
     // Push undefined as receiver. This is patched in the method prologue if it
     // is a sloppy mode method.
-    __ Push(isolate()->factory()->undefined_value());
+    __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
+    __ push(r0);
   } else {
     // Load the function from the receiver.
     DCHECK(callee->IsProperty());
@@ -2874,8 +2929,8 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
     EmitNamedPropertyLoad(callee->AsProperty());
     PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
     // Push the target function under the receiver.
-    __ LoadP(ip, MemOperand(sp, 0));
-    __ push(ip);
+    __ LoadP(r0, MemOperand(sp, 0));
+    __ push(r0);
     __ StoreP(r3, MemOperand(sp, kPointerSize));
   }
 
@@ -3033,8 +3088,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
 }
 
 
-void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
-  DCHECK(super_ref != NULL);
+void FullCodeGenerator::EmitLoadSuperConstructor() {
   __ LoadP(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
   __ Push(r3);
   __ CallRuntime(Runtime::kGetPrototype, 1);
@@ -3225,20 +3279,12 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
 
 
 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
-  SuperReference* super_ref = expr->expression()->AsSuperReference();
-  EmitLoadSuperConstructor(super_ref);
-  __ push(result_register());
-
-  Variable* this_var = super_ref->this_var()->var();
+  Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
+  GetVar(result_register(), new_target_var);
+  __ Push(result_register());
 
-  GetVar(r3, this_var);
-  __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
-  Label uninitialized_this;
-  __ beq(&uninitialized_this);
-  __ mov(r3, Operand(this_var->name()));
-  __ push(r3);
-  __ CallRuntime(Runtime::kThrowReferenceError, 1);
-  __ bind(&uninitialized_this);
+  EmitLoadSuperConstructor();
+  __ push(result_register());
 
   // Push the arguments ("left-to-right") on the stack.
   ZoneList<Expression*>* args = expr->arguments();
@@ -3268,12 +3314,24 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
   __ Move(r5, FeedbackVector());
   __ LoadSmiLiteral(r6, SmiFromSlot(expr->CallFeedbackSlot()));
 
-  // TODO(dslomov): use a different stub and propagate new.target.
-  CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
+  CallConstructStub stub(isolate(), SUPER_CALL_RECORD_TARGET);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
 
+  __ Drop(1);
+
   RecordJSReturnSite(expr);
 
+  SuperReference* super_ref = expr->expression()->AsSuperReference();
+  Variable* this_var = super_ref->this_var()->var();
+  GetVar(r4, this_var);
+  __ CompareRoot(r4, Heap::kTheHoleValueRootIndex);
+  Label uninitialized_this;
+  __ beq(&uninitialized_this);
+  __ mov(r4, Operand(this_var->name()));
+  __ push(r4);
+  __ CallRuntime(Runtime::kThrowReferenceError, 1);
+  __ bind(&uninitialized_this);
+
   EmitVariableAssignment(this_var, Token::INIT_CONST);
   context()->Plug(r3);
 }
@@ -3742,8 +3800,9 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   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);
+  Register instance_type = r5;
+  __ GetMapConstructor(r3, r3, r4, instance_type);
+  __ cmpi(instance_type, Operand(JS_FUNCTION_TYPE));
   __ bne(&non_function_constructor);
 
   // r3 now contains the constructor function. Grab the
@@ -4036,7 +4095,7 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
   __ b(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&done);
   context()->Plug(result);
@@ -4078,7 +4137,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
   __ b(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&done);
   context()->Plug(result);
@@ -4142,6 +4201,61 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
 }
 
 
+void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
+  Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
+  GetVar(result_register(), new_target_var);
+  __ Push(result_register());
+
+  EmitLoadSuperConstructor();
+  __ mr(r4, result_register());
+  __ Push(r4);
+
+  // Check if the calling frame is an arguments adaptor frame.
+  Label adaptor_frame, args_set_up, runtime;
+  __ LoadP(r5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ LoadP(r6, MemOperand(r5, StandardFrameConstants::kContextOffset));
+  __ CmpSmiLiteral(r6, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
+  __ beq(&adaptor_frame);
+
+  // default constructor has no arguments, so no adaptor frame means no args.
+  __ li(r3, Operand::Zero());
+  __ b(&args_set_up);
+
+  // Copy arguments from adaptor frame.
+  {
+    __ bind(&adaptor_frame);
+    __ LoadP(r3, MemOperand(r5, ArgumentsAdaptorFrameConstants::kLengthOffset));
+    __ SmiUntag(r3);
+
+    // Subtract 1 from arguments count, for new.target.
+    __ subi(r3, r3, Operand(1));
+
+    // Get arguments pointer in r5.
+    __ ShiftLeftImm(r0, r3, Operand(kPointerSizeLog2));
+    __ add(r5, r5, r0);
+    __ addi(r5, r5, Operand(StandardFrameConstants::kCallerSPOffset));
+
+    Label loop;
+    __ mtctr(r3);
+    __ bind(&loop);
+    // Pre-decrement in order to skip receiver.
+    __ LoadPU(r6, MemOperand(r5, -kPointerSize));
+    __ Push(r6);
+    __ bdnz(&loop);
+  }
+
+  __ bind(&args_set_up);
+  __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
+
+  CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
+  __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
+
+  __ Drop(1);
+
+  context()->Plug(result_register());
+}
+
+
 void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
   RegExpConstructResultStub stub(isolate());
   ZoneList<Expression*>* args = expr->arguments();
@@ -4198,7 +4312,7 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
   __ bind(&not_found);
   // Call runtime to perform the lookup.
   __ Push(cache, key);
-  __ CallRuntime(Runtime::kGetFromCache, 2);
+  __ CallRuntime(Runtime::kGetFromCacheRT, 2);
 
   __ bind(&done);
   context()->Plug(r3);
@@ -4505,18 +4619,11 @@ void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
 
 
 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()) {
+    Comment cmnt(masm_, "[ CallRuntime");
     // Push the builtins object as the receiver.
     Register receiver = LoadDescriptor::ReceiverRegister();
     __ LoadP(receiver, GlobalObjectOperand());
@@ -4540,7 +4647,6 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     __ 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));
     }
@@ -4555,15 +4661,29 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     __ 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));
-    }
+    const Runtime::Function* function = expr->function();
+    switch (function->function_id) {
+#define CALL_INTRINSIC_GENERATOR(Name)     \
+  case Runtime::kInline##Name: {           \
+    Comment cmnt(masm_, "[ Inline" #Name); \
+    return Emit##Name(expr);               \
+  }
+      FOR_EACH_FULL_CODE_INTRINSIC(CALL_INTRINSIC_GENERATOR)
+#undef CALL_INTRINSIC_GENERATOR
+      default: {
+        Comment cmnt(masm_, "[ CallRuntime for unhandled intrinsic");
+        // 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);
+        // Call the C runtime function.
+        __ CallRuntime(expr->function(), arg_count);
+        context()->Plug(r3);
+      }
+    }
   }
 }
 
@@ -5206,19 +5326,6 @@ void FullCodeGenerator::EnterFinallyBlock() {
   __ 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);
 }
 
 
@@ -5226,19 +5333,6 @@ 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));
@@ -5259,32 +5353,6 @@ void FullCodeGenerator::ExitFinallyBlock() {
 
 #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,
index f82d85d..01d0150 100644 (file)
@@ -227,6 +227,12 @@ void InternalArrayConstructorDescriptor::Initialize(
 }
 
 
+void CompareDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r4, r3};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
 void CompareNilDescriptor::Initialize(CallInterfaceDescriptorData* data) {
   Register registers[] = {cp, r3};
   data->Initialize(arraysize(registers), registers, NULL);
index 4d17189..f6147c2 100644 (file)
@@ -7,6 +7,7 @@
 #include "src/base/bits.h"
 #include "src/code-factory.h"
 #include "src/code-stubs.h"
+#include "src/cpu-profiler.h"
 #include "src/hydrogen-osr.h"
 #include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
@@ -109,7 +110,7 @@ bool LCodeGen::GeneratePrologue() {
 
     // r4: Callee's JS function.
     // cp: Callee's context.
-    // pp: Callee's constant pool pointer (if FLAG_enable_ool_constant_pool)
+    // pp: Callee's constant pool pointer (if enabled)
     // fp: Caller's frame pointer.
     // lr: Caller's pc.
     // ip: Our own function entry (required by the prologue)
@@ -117,7 +118,7 @@ bool LCodeGen::GeneratePrologue() {
     // 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() && is_sloppy(info_->language_mode()) &&
+    if (graph()->this_has_uses() && is_sloppy(info_->language_mode()) &&
         !info_->is_native()) {
       Label ok;
       int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
@@ -336,49 +337,39 @@ bool LCodeGen::GenerateJumpTable() {
 
       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);
-        }
+        Comment(";;; call deopt with frame");
+        __ PushFixedFrame();
+        __ b(&needs_frame, SetLK);
       } 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);
+        __ b(&call_deopt_entry, SetLK);
       }
+      info()->LogDeoptCallPosition(masm()->pc_offset(),
+                                   table_entry->deopt_info.inlining_id);
     }
 
-    if (!call_deopt_entry.is_bound()) {
-      Comment(";;; call deopt");
-      __ bind(&call_deopt_entry);
+    if (needs_frame.is_linked()) {
+      __ bind(&needs_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));
+      __ push(ip);
+      __ addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+    }
 
-      if (info()->saves_caller_doubles()) {
-        DCHECK(info()->IsStub());
-        RestoreCallerDoubles();
-      }
+    Comment(";;; call deopt");
+    __ 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);
+    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);
+    __ Jump(ip);
   }
 
   // The deoptimization jump table is the last part of the instruction
@@ -812,14 +803,15 @@ void LCodeGen::DeoptimizeIf(Condition cond, LInstruction* instr,
     __ stop("trap_on_deopt", cond, kDefaultStopCode, cr);
   }
 
-  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
-                                    instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info = MakeDeoptInfo(instr, deopt_reason);
+
   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(deopt_info);
     __ Call(entry, RelocInfo::RUNTIME_ENTRY);
+    info()->LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
   } else {
     Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
                                             !frame_is_built_);
@@ -941,12 +933,6 @@ void LCodeGen::RecordSafepoint(LPointerMap* pointers, Safepoint::Kind kind,
       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
 }
 
 
@@ -2787,10 +2773,11 @@ void LCodeGen::EmitClassOfTest(Label* is_true, Label* 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));
+  Register instance_type = ip;
+  __ GetMapConstructor(temp, temp, temp2, instance_type);
 
   // Objects with a non-function constructor have class 'Object'.
-  __ CompareObjectType(temp, temp2, temp2, JS_FUNCTION_TYPE);
+  __ cmpi(instance_type, Operand(JS_FUNCTION_TYPE));
   if (class_name->IsOneByteEqualTo(STATIC_CHAR_VECTOR("Object"))) {
     __ bne(is_true);
   } else {
@@ -2898,7 +2885,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
   Register map = temp;
   __ LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset));
   {
-    // Block constant pool emission to ensure the positions of instructions are
+    // Block trampoline 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.
@@ -2906,10 +2893,10 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
     // 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));
+    __ mov(ip, Operand(cell));
+    __ LoadP(ip, FieldMemOperand(ip, Cell::kValueOffset));
     __ cmp(map, ip);
-    __ bne(&cache_miss);
+    __ bc_short(ne, &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.
@@ -2957,22 +2944,25 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
   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_);
-    if (Assembler::kMovInstructions != 1 &&
-        is_int16(delta * Instruction::kInstrSize)) {
-      // The following mov will be an li rather than a multi-instruction form
-      delta -= Assembler::kMovInstructions - 1;
-    }
+    Handle<Code> code = stub.GetCode();
+    // Include instructions below in delta: bitwise_mov32 + call
+    int delta = (masm_->InstructionsGeneratedSince(map_check) + 2) *
+                    Instruction::kInstrSize +
+                masm_->CallSize(code);
     // r8 is used to communicate the offset to the location of the map check.
-    __ mov(r8, Operand(delta * Instruction::kInstrSize));
+    if (is_int16(delta)) {
+      delta -= Instruction::kInstrSize;
+      __ li(r8, Operand(delta));
+    } else {
+      __ bitwise_mov32(r8, delta);
+    }
+    CallCodeGeneric(code, RelocInfo::CODE_TARGET, instr,
+                    RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
+    DCHECK(delta / Instruction::kInstrSize ==
+           masm_->InstructionsGeneratedSince(map_check));
   }
-  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
@@ -3052,18 +3042,6 @@ void LCodeGen::DoReturn(LReturn* instr) {
 }
 
 
-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, Deoptimizer::kHole);
-  }
-}
-
-
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
@@ -3093,36 +3071,12 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
     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,
+                                                       PREMONOMORPHIC).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, Deoptimizer::kHole);
-  }
-
-  // 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());
@@ -3235,7 +3189,9 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
   if (FLAG_vector_ics) {
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(
+                        isolate(), NOT_CONTEXTUAL,
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3590,7 +3546,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
+  Handle<Code> ic =
+      CodeFactory::KeyedLoadICInOptimizedCode(
+          isolate(), instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -4529,7 +4487,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
   __ mov(StoreDescriptor::NameRegister(), Operand(instr->name()));
-  Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->language_mode());
+  Handle<Code> ic =
+      StoreIC::initialize_stub(isolate(), instr->language_mode(),
+                               instr->hydrogen()->initialization_state());
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -4793,8 +4753,9 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
   DCHECK(ToRegister(instr->key()).is(StoreDescriptor::NameRegister()));
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
-  Handle<Code> ic =
-      CodeFactory::KeyedStoreIC(isolate(), instr->language_mode()).code();
+  Handle<Code> ic = CodeFactory::KeyedStoreICInOptimizedCode(
+                        isolate(), instr->language_mode(),
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -5508,7 +5469,7 @@ void LCodeGen::DoCheckValue(LCheckValue* instr) {
   if (isolate()->heap()->InNewSpace(*object)) {
     Register reg = ToRegister(instr->value());
     Handle<Cell> cell = isolate()->factory()->NewCell(object);
-    __ mov(ip, Operand(Handle<Object>(cell)));
+    __ mov(ip, Operand(cell));
     __ LoadP(ip, FieldMemOperand(ip, Cell::kValueOffset));
     __ cmp(reg, ip);
   } else {
@@ -5519,6 +5480,7 @@ void LCodeGen::DoCheckValue(LCheckValue* instr) {
 
 
 void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
+  Register temp = ToRegister(instr->temp());
   {
     PushSafepointRegistersScope scope(this);
     __ push(object);
@@ -5526,9 +5488,9 @@ void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
     __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance);
     RecordSafepointWithRegisters(instr->pointer_map(), 1,
                                  Safepoint::kNoLazyDeopt);
-    __ StoreToSafepointRegisterSlot(r3, scratch0());
+    __ StoreToSafepointRegisterSlot(r3, temp);
   }
-  __ TestIfSmi(scratch0(), r0);
+  __ TestIfSmi(temp, r0);
   DeoptimizeIf(eq, instr, Deoptimizer::kInstanceMigrationFailed, cr0);
 }
 
@@ -5560,17 +5522,14 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
     return;
   }
 
-  Register map_reg = scratch0();
-
-  LOperand* input = instr->value();
-  DCHECK(input->IsRegister());
-  Register reg = ToRegister(input);
+  Register object = ToRegister(instr->value());
+  Register map_reg = ToRegister(instr->temp());
 
-  __ LoadP(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
+  __ LoadP(map_reg, FieldMemOperand(object, HeapObject::kMapOffset));
 
   DeferredCheckMaps* deferred = NULL;
   if (instr->hydrogen()->HasMigrationTarget()) {
-    deferred = new (zone()) DeferredCheckMaps(this, instr, reg);
+    deferred = new (zone()) DeferredCheckMaps(this, instr, object);
     __ bind(deferred->check_maps());
   }
 
index d54c7ec..ec75713 100644 (file)
@@ -2029,7 +2029,9 @@ LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
 LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
   if (instr->IsStabilityCheck()) return new (zone()) LCheckMaps;
   LOperand* value = UseRegisterAtStart(instr->value());
-  LInstruction* result = AssignEnvironment(new (zone()) LCheckMaps(value));
+  LOperand* temp = TempRegister();
+  LInstruction* result =
+      AssignEnvironment(new (zone()) LCheckMaps(value, temp));
   if (instr->HasMigrationTarget()) {
     info()->MarkAsDeferredCalling();
     result = AssignPointerMap(result);
@@ -2096,14 +2098,6 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
 }
 
 
-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 =
@@ -2118,17 +2112,6 @@ LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* 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 =
index ac7b505..5dce71c 100644 (file)
@@ -100,7 +100,6 @@ class LCodeGen;
   V(LoadRoot)                                \
   V(LoadFieldByIndex)                        \
   V(LoadFunctionPrototype)                   \
-  V(LoadGlobalCell)                          \
   V(LoadGlobalGeneric)                       \
   V(LoadKeyed)                               \
   V(LoadKeyedGeneric)                        \
@@ -142,7 +141,6 @@ class LCodeGen;
   V(StoreCodeEntry)                          \
   V(StoreContextSlot)                        \
   V(StoreFrameContext)                       \
-  V(StoreGlobalCell)                         \
   V(StoreKeyed)                              \
   V(StoreKeyedGeneric)                       \
   V(StoreNamedField)                         \
@@ -1641,13 +1639,6 @@ class LLoadKeyedGeneric FINAL : public LTemplateInstruction<1, 3, 1> {
 };
 
 
-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,
@@ -1669,21 +1660,6 @@ class LLoadGlobalGeneric FINAL : public LTemplateInstruction<1, 2, 1> {
 };
 
 
-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; }
@@ -2319,11 +2295,15 @@ class LCheckInstanceType FINAL : public LTemplateInstruction<0, 1, 0> {
 };
 
 
-class LCheckMaps FINAL : public LTemplateInstruction<0, 1, 0> {
+class LCheckMaps FINAL : public LTemplateInstruction<0, 1, 1> {
  public:
-  explicit LCheckMaps(LOperand* value = NULL) { inputs_[0] = value; }
+  explicit LCheckMaps(LOperand* value = NULL, LOperand* temp = NULL) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
 
   LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
 
   DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps")
   DECLARE_HYDROGEN_ACCESSOR(CheckMaps)
index 2c9f7aa..2f56d39 100644 (file)
@@ -104,15 +104,14 @@ void MacroAssembler::CallJSEntry(Register 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;
+  return (2 + kMovInstructions) * kInstrSize;
 }
 
 
 int MacroAssembler::CallSizeNotPredictableCodeSize(Address target,
                                                    RelocInfo::Mode rmode,
                                                    Condition cond) {
-  return (2 + kMovInstructionsNoConstantPool) * kInstrSize;
+  return (2 + kMovInstructions) * kInstrSize;
 }
 
 
@@ -274,6 +273,7 @@ void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index,
 
 void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index,
                                Condition cond) {
+  DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
   DCHECK(cond == al);
   StoreP(source, MemOperand(kRootRegister, index << kPointerSizeLog2), r0);
 }
@@ -514,40 +514,28 @@ void MacroAssembler::RememberedSetHelper(Register object,  // For debug tests.
 
 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);
 }
 
 
+const RegList MacroAssembler::kSafepointSavedRegisters = Register::kAllocatable;
+const int MacroAssembler::kNumSafepointSavedRegisters =
+    Register::kMaxNumAllocatableRegisters;
+
 // Push and pop all registers that can hold pointers.
 void MacroAssembler::PushSafepointRegisters() {
   // Safepoints expect a block of kNumSafepointRegisters values on the
@@ -664,41 +652,11 @@ void MacroAssembler::ConvertDoubleToInt64(const DoubleRegister double_input,
 }
 
 
-#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
 }
 
 
@@ -731,28 +689,13 @@ void MacroAssembler::Prologue(bool code_pre_aging, int prologue_offset) {
       }
     }
   }
-#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);
-  }
+  LoadSmiLiteral(ip, Smi::FromInt(type));
+  PushFixedFrame(ip);
   // Adjust FP to point to saved FP.
   addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
 
@@ -762,24 +705,15 @@ void MacroAssembler::EnterFrame(StackFrame::Type type,
 
 
 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.
+  // the caller's state.
   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);
@@ -826,10 +760,6 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
     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));
 
@@ -899,9 +829,6 @@ int MacroAssembler::ActivationFrameAlignment() {
 void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
                                     bool restore_context,
                                     bool argument_count_is_length) {
-#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.
@@ -1159,165 +1086,32 @@ void MacroAssembler::DebugBreak() {
 }
 
 
-void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
-                                    int handler_index) {
+void MacroAssembler::PushStackHandler() {
   // Adjust this code if not the case.
-  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kSize == 1 * 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.
+  // Preserve r3-r7.
   mov(r8, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
   LoadP(r0, MemOperand(r8));
-  StorePU(r0, MemOperand(sp, -StackHandlerConstants::kSize));
+  push(r0);
+
   // 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() {
+void MacroAssembler::PopStackHandler() {
+  STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
   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;
@@ -2107,6 +1901,20 @@ void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
 }
 
 
+void MacroAssembler::GetMapConstructor(Register result, Register map,
+                                       Register temp, Register temp2) {
+  Label done, loop;
+  LoadP(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
+  bind(&loop);
+  JumpIfSmi(result, &done);
+  CompareObjectType(result, temp, temp2, MAP_TYPE);
+  bne(&done);
+  LoadP(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset));
+  b(&loop);
+  bind(&done);
+}
+
+
 void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
                                              Register scratch, Label* miss,
                                              bool miss_on_bound_function) {
@@ -2163,7 +1971,7 @@ void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
     // Non-instance prototype: Fetch prototype from constructor field
     // in initial map.
     bind(&non_instance);
-    LoadP(result, FieldMemOperand(result, Map::kConstructorOffset));
+    GetMapConstructor(result, result, scratch, ip);
   }
 
   // All done.
@@ -3370,25 +3178,6 @@ 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.
@@ -3465,7 +3254,6 @@ void MacroAssembler::SetRelocatedValue(Register location, Register scratch,
 #else
   FlushICache(location, 2 * kInstrSize, scratch);
 #endif
-#endif
 }
 
 
@@ -3473,24 +3261,6 @@ 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)));
@@ -3543,7 +3313,6 @@ void MacroAssembler::GetRelocatedValue(Register location, Register result,
   sldi(result, result, Operand(16));
   rldimi(result, scratch, 0, 48);
 #endif
-#endif
 }
 
 
@@ -3929,23 +3698,6 @@ void MacroAssembler::LoadSmiLiteral(Register dst, Smi* 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;
@@ -4081,6 +3833,46 @@ void MacroAssembler::MovInt64ComponentsToDouble(DoubleRegister dst,
 #endif
 
 
+void MacroAssembler::InsertDoubleLow(DoubleRegister dst, Register src,
+                                     Register scratch) {
+#if V8_TARGET_ARCH_PPC64
+  if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
+    mffprd(scratch, dst);
+    rldimi(scratch, src, 0, 32);
+    mtfprd(dst, scratch);
+    return;
+  }
+#endif
+
+  subi(sp, sp, Operand(kDoubleSize));
+  stfd(dst, MemOperand(sp));
+  stw(src, MemOperand(sp, Register::kMantissaOffset));
+  nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
+  lfd(dst, MemOperand(sp));
+  addi(sp, sp, Operand(kDoubleSize));
+}
+
+
+void MacroAssembler::InsertDoubleHigh(DoubleRegister dst, Register src,
+                                      Register scratch) {
+#if V8_TARGET_ARCH_PPC64
+  if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
+    mffprd(scratch, dst);
+    rldimi(scratch, src, 32, 0);
+    mtfprd(dst, scratch);
+    return;
+  }
+#endif
+
+  subi(sp, sp, Operand(kDoubleSize));
+  stfd(dst, MemOperand(sp));
+  stw(src, MemOperand(sp, Register::kExponentOffset));
+  nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
+  lfd(dst, MemOperand(sp));
+  addi(sp, sp, Operand(kDoubleSize));
+}
+
+
 void MacroAssembler::MovDoubleLowToInt(Register dst, DoubleRegister src) {
 #if V8_TARGET_ARCH_PPC64
   if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
index 146489d..04e9bd8 100644 (file)
@@ -102,9 +102,7 @@ class MacroAssembler : public 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.
+  // Returns the size of a call in instructions.
   static int CallSize(Register target);
   int CallSize(Address target, RelocInfo::Mode rmode, Condition cond = al);
   static int CallSizeNotPredictableCodeSize(Address target,
@@ -379,8 +377,9 @@ class MacroAssembler : public Assembler {
   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);
+  // stack_space - extra stack space, used for parameters before call to C.
+  // At least one slot (for the return address) should be provided.
+  void EnterExitFrame(bool save_doubles, int stack_space = 1);
 
   // Leave the current exit frame. Expects the return value in r0.
   // Expect the number of values, pushed prior to the exit frame, to
@@ -464,6 +463,8 @@ class MacroAssembler : public Assembler {
   void MovInt64ComponentsToDouble(DoubleRegister dst, Register src_hi,
                                   Register src_lo, Register scratch);
 #endif
+  void InsertDoubleLow(DoubleRegister dst, Register src, Register scratch);
+  void InsertDoubleHigh(DoubleRegister dst, Register src, Register scratch);
   void MovDoubleLowToInt(Register dst, DoubleRegister src);
   void MovDoubleHighToInt(Register dst, DoubleRegister src);
   void MovDoubleToInt64(
@@ -543,19 +544,12 @@ class MacroAssembler : public Assembler {
   // ---------------------------------------------------------------------------
   // Exception handling
 
-  // Push a new try handler and link into try handler chain.
-  void PushTryHandler(StackHandler::Kind kind, int handler_index);
+  // Push a new stack handler and link into stack handler chain.
+  void PushStackHandler();
 
-  // Unlink the stack handler on top of the stack from the try handler chain.
+  // Unlink the stack handler on top of the stack from the stack 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);
+  void PopStackHandler();
 
   // ---------------------------------------------------------------------------
   // Inline caching support
@@ -684,6 +678,11 @@ class MacroAssembler : public Assembler {
   // ---------------------------------------------------------------------------
   // Support functions.
 
+  // Machine code version of Map::GetConstructor().
+  // |temp| holds |result|'s map when done, and |temp2| its instance type.
+  void GetMapConstructor(Register result, Register map, Register temp,
+                         Register temp2);
+
   // 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
@@ -1361,7 +1360,7 @@ class MacroAssembler : public Assembler {
   // ---------------------------------------------------------------------------
   // Patching helpers.
 
-  // Retrieve/patch the relocated value (lis/ori pair or constant pool load).
+  // Retrieve/patch the relocated value (lis/ori pair).
   void GetRelocatedValue(Register location, Register result, Register scratch);
   void SetRelocatedValue(Register location, Register scratch,
                          Register new_value);
@@ -1481,22 +1480,14 @@ class MacroAssembler : public Assembler {
   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();
+  static const RegList kSafepointSavedRegisters;
+  static const int kNumSafepointSavedRegisters;
 
   // 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.
index 0bb2da0..9b29004 100644 (file)
@@ -11,6 +11,7 @@
 #if V8_TARGET_ARCH_PPC
 
 #include "src/assembler.h"
+#include "src/base/bits.h"
 #include "src/codegen.h"
 #include "src/disasm.h"
 #include "src/ppc/constants-ppc.h"
@@ -2998,8 +2999,7 @@ void Simulator::ExecuteExt5(Instruction* instr) {
       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 result = base::bits::RotateLeft64(rs_val, sh);
       uintptr_t mask = 0xffffffffffffffff >> mb;
       result &= mask;
       set_register(ra, result);
@@ -3016,8 +3016,7 @@ void Simulator::ExecuteExt5(Instruction* instr) {
       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 result = base::bits::RotateLeft64(rs_val, sh);
       uintptr_t mask = 0xffffffffffffffff << (63 - me);
       result &= mask;
       set_register(ra, result);
@@ -3034,8 +3033,7 @@ void Simulator::ExecuteExt5(Instruction* instr) {
       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 result = base::bits::RotateLeft64(rs_val, sh);
       uintptr_t mask = (0xffffffffffffffff >> mb) & (0xffffffffffffffff << sh);
       result &= mask;
       set_register(ra, result);
@@ -3052,8 +3050,7 @@ void Simulator::ExecuteExt5(Instruction* instr) {
       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 result = base::bits::RotateLeft64(rs_val, sh);
       uintptr_t mask = 0;
       if (mb < me + 1) {
         uintptr_t bit = 0x8000000000000000 >> mb;
@@ -3092,8 +3089,7 @@ void Simulator::ExecuteExt5(Instruction* instr) {
       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 result = base::bits::RotateLeft64(rs_val, sh);
       uintptr_t mask = 0xffffffffffffffff >> mb;
       result &= mask;
       set_register(ra, result);
@@ -3268,8 +3264,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
       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));
+      uint32_t result = base::bits::RotateLeft32(rs_val, sh);
       int mask = 0;
       if (mb < me + 1) {
         int bit = 0x80000000 >> mb;
@@ -3311,8 +3306,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
       }
       int mb = instr->Bits(10, 6);
       int me = instr->Bits(5, 1);
-      // rotate left
-      uint32_t result = (rs_val << sh) | (rs_val >> (32 - sh));
+      uint32_t result = base::bits::RotateLeft32(rs_val, sh);
       int mask = 0;
       if (mb < me + 1) {
         int bit = 0x80000000 >> mb;
index 391a351..de10693 100644 (file)
@@ -27,7 +27,7 @@ struct PreparseDataConstants {
   static const int kMessageStartPos = 0;
   static const int kMessageEndPos = 1;
   static const int kMessageArgCountPos = 2;
-  static const int kIsReferenceErrorPos = 3;
+  static const int kParseErrorTypePos = 3;
   static const int kMessageTextPos = 4;
 
   static const unsigned char kNumberTerminator = 0x80u;
index a66a1ad..e1c7ad1 100644 (file)
@@ -3,9 +3,9 @@
 // found in the LICENSE file.
 
 #include "src/base/logging.h"
-#include "src/compiler.h"
 #include "src/globals.h"
 #include "src/hashmap.h"
+#include "src/parser.h"
 #include "src/preparse-data.h"
 #include "src/preparse-data-format.h"
 
@@ -28,11 +28,10 @@ CompleteParserRecorder::CompleteParserRecorder() {
 }
 
 
-void CompleteParserRecorder::LogMessage(int start_pos,
-                                        int end_pos,
+void CompleteParserRecorder::LogMessage(int start_pos, int end_pos,
                                         const char* message,
                                         const char* arg_opt,
-                                        bool is_reference_error) {
+                                        ParseErrorType error_type) {
   if (HasError()) return;
   preamble_[PreparseDataConstants::kHasErrorOffset] = true;
   function_store_.Reset();
@@ -42,8 +41,8 @@ void CompleteParserRecorder::LogMessage(int start_pos,
   function_store_.Add(end_pos);
   STATIC_ASSERT(PreparseDataConstants::kMessageArgCountPos == 2);
   function_store_.Add((arg_opt == NULL) ? 0 : 1);
-  STATIC_ASSERT(PreparseDataConstants::kIsReferenceErrorPos == 3);
-  function_store_.Add(is_reference_error ? 1 : 0);
+  STATIC_ASSERT(PreparseDataConstants::kParseErrorTypePos == 3);
+  function_store_.Add(error_type);
   STATIC_ASSERT(PreparseDataConstants::kMessageTextPos == 4);
   WriteString(CStrVector(message));
   if (arg_opt != NULL) WriteString(CStrVector(arg_opt));
index 0d78499..d78c3ed 100644 (file)
 namespace v8 {
 namespace internal {
 
-class ScriptData;
+class ScriptData {
+ public:
+  ScriptData(const byte* data, int length);
+  ~ScriptData() {
+    if (owns_data_) DeleteArray(data_);
+  }
+
+  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_);
+    owns_data_ = true;
+  }
+
+  void ReleaseDataOwnership() {
+    DCHECK(owns_data_);
+    owns_data_ = false;
+  }
 
+ private:
+  bool owns_data_ : 1;
+  bool rejected_ : 1;
+  const byte* data_;
+  int length_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScriptData);
+};
 
 // Abstract interface for preparse data recorder.
 class ParserRecorder {
@@ -30,11 +59,10 @@ class ParserRecorder {
   // Logs an error message and marks the log as containing an error.
   // Further logging will be ignored, and ExtractData will return a vector
   // representing the error only.
-  virtual void LogMessage(int start,
-                          int end,
-                          const char* message,
+  virtual void LogMessage(int start, int end, const char* message,
                           const char* argument_opt,
-                          bool is_reference_error) = 0;
+                          ParseErrorType error_type) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(ParserRecorder);
 };
@@ -43,7 +71,7 @@ class ParserRecorder {
 class SingletonLogger : public ParserRecorder {
  public:
   SingletonLogger()
-      : has_error_(false), start_(-1), end_(-1), is_reference_error_(false) {}
+      : has_error_(false), start_(-1), end_(-1), error_type_(kSyntaxError) {}
   virtual ~SingletonLogger() {}
 
   void Reset() { has_error_ = false; }
@@ -63,18 +91,15 @@ class SingletonLogger : public ParserRecorder {
   // Logs an error message and marks the log as containing an error.
   // Further logging will be ignored, and ExtractData will return a vector
   // representing the error only.
-  virtual void LogMessage(int start,
-                          int end,
-                          const char* message,
-                          const char* argument_opt,
-                          bool is_reference_error) {
+  virtual void LogMessage(int start, int end, const char* message,
+                          const char* argument_opt, ParseErrorType error_type) {
     if (has_error_) return;
     has_error_ = true;
     start_ = start;
     end_ = end;
     message_ = message;
     argument_opt_ = argument_opt;
-    is_reference_error_ = is_reference_error;
+    error_type_ = error_type;
   }
 
   bool has_error() const { return has_error_; }
@@ -97,7 +122,10 @@ class SingletonLogger : public ParserRecorder {
     DCHECK(!has_error_);
     return scope_uses_super_property_;
   }
-  int is_reference_error() const { return is_reference_error_; }
+  ParseErrorType error_type() const {
+    DCHECK(has_error_);
+    return error_type_;
+  }
   const char* message() {
     DCHECK(has_error_);
     return message_;
@@ -119,7 +147,7 @@ class SingletonLogger : public ParserRecorder {
   // For error messages.
   const char* message_;
   const char* argument_opt_;
-  bool is_reference_error_;
+  ParseErrorType error_type_;
 };
 
 
@@ -147,11 +175,8 @@ class CompleteParserRecorder : public ParserRecorder {
   // Logs an error message and marks the log as containing an error.
   // Further logging will be ignored, and ExtractData will return a vector
   // representing the error only.
-  virtual void LogMessage(int start,
-                          int end,
-                          const char* message,
-                          const char* argument_opt,
-                          bool is_reference_error_);
+  virtual void LogMessage(int start, int end, const char* message,
+                          const char* argument_opt, ParseErrorType error_type);
   ScriptData* GetScriptData();
 
   bool HasError() {
index 154a9ae..5a6a094 100644 (file)
@@ -21,24 +21,16 @@ namespace v8 {
 namespace internal {
 
 void PreParserTraits::ReportMessageAt(Scanner::Location location,
-                                      const char* message,
-                                      const char* arg,
-                                      bool is_reference_error) {
-  ReportMessageAt(location.beg_pos,
-                  location.end_pos,
-                  message,
-                  arg,
-                  is_reference_error);
+                                      const char* message, const char* arg,
+                                      ParseErrorType error_type) {
+  ReportMessageAt(location.beg_pos, location.end_pos, message, arg, error_type);
 }
 
 
-void PreParserTraits::ReportMessageAt(int start_pos,
-                                      int end_pos,
-                                      const char* message,
-                                      const char* arg,
-                                      bool is_reference_error) {
-  pre_parser_->log_->LogMessage(start_pos, end_pos, message, arg,
-                                is_reference_error);
+void PreParserTraits::ReportMessageAt(int start_pos, int end_pos,
+                                      const char* message, const char* arg,
+                                      ParseErrorType error_type) {
+  pre_parser_->log_->LogMessage(start_pos, end_pos, message, arg, error_type);
 }
 
 
@@ -182,7 +174,6 @@ PreParser::Statement PreParser::ParseStatementListItem(bool* ok) {
     case Token::CONST:
       return ParseVariableStatement(kStatementListItem, ok);
     case Token::LET:
-      DCHECK(allow_harmony_scoping());
       if (is_strict(language_mode())) {
         return ParseVariableStatement(kStatementListItem, ok);
       }
@@ -202,8 +193,19 @@ void PreParser::ParseStatementList(int end_token, bool* ok) {
     if (directive_prologue && peek() != Token::STRING) {
       directive_prologue = false;
     }
+    Token::Value token = peek();
+    Scanner::Location old_super_loc = function_state_->super_call_location();
     Statement statement = ParseStatementListItem(ok);
     if (!*ok) return;
+    Scanner::Location super_loc = function_state_->super_call_location();
+    if (is_strong(language_mode()) &&
+        i::IsConstructor(function_state_->kind()) &&
+        !old_super_loc.IsValid() && super_loc.IsValid() &&
+        token != Token::SUPER) {
+      ReportMessageAt(super_loc, "strong_super_call_nested");
+      *ok = false;
+      return;
+    }
     if (directive_prologue) {
       if (statement.IsUseStrictLiteral()) {
         scope_->SetLanguageMode(
@@ -391,7 +393,7 @@ PreParser::Statement PreParser::ParseBlock(bool* ok) {
   //
   Expect(Token::LBRACE, CHECK_OK);
   while (peek() != Token::RBRACE) {
-    if (allow_harmony_scoping() && is_strict(language_mode())) {
+    if (is_strict(language_mode())) {
       ParseStatementListItem(CHECK_OK);
     } else {
       ParseStatement(CHECK_OK);
@@ -464,12 +466,6 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
     Consume(Token::CONST);
     if (is_strict(language_mode())) {
       DCHECK(var_context != kStatement);
-      if (!allow_harmony_scoping()) {
-        Scanner::Location location = scanner()->peek_location();
-        ReportMessageAt(location, "strict_const");
-        *ok = false;
-        return Statement::Default();
-      }
       is_strict_const = true;
       require_initializer = var_context != kForStatement;
     }
@@ -617,6 +613,7 @@ PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
   // reporting any errors on it, because of the way errors are
   // reported (underlining).
   Expect(Token::RETURN, CHECK_OK);
+  function_state_->set_return_location(scanner()->location());
 
   // An ECMAScript program is considered syntactically incorrect if it
   // contains a return statement that is not within the body of a
@@ -628,6 +625,14 @@ PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
       tok != Token::SEMICOLON &&
       tok != Token::RBRACE &&
       tok != Token::EOS) {
+    if (is_strong(language_mode()) &&
+        i::IsConstructor(function_state_->kind())) {
+      int pos = peek_position();
+      ReportMessageAt(Scanner::Location(pos, pos + 1),
+                      "strong_constructor_return_value");
+      *ok = false;
+      return Statement::Default();
+    }
     ParseExpression(true, CHECK_OK);
   }
   ExpectSemicolon(CHECK_OK);
@@ -678,7 +683,7 @@ PreParser::Statement PreParser::ParseSwitchStatement(bool* ok) {
     while (token != Token::CASE &&
            token != Token::DEFAULT &&
            token != Token::RBRACE) {
-      ParseStatement(CHECK_OK);
+      ParseStatementListItem(CHECK_OK);
       token = peek();
     }
   }
@@ -953,6 +958,15 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
     CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
   }
 
+  if (is_strong(language_mode()) && IsSubclassConstructor(kind)) {
+    if (!function_state.super_call_location().IsValid()) {
+      ReportMessageAt(function_name_location, "strong_super_call_missing",
+                      kReferenceError);
+      *ok = false;
+      return Expression::Default();
+    }
+  }
+
   return Expression::Default();
 }
 
index f7f5323..08963c9 100644 (file)
@@ -100,7 +100,6 @@ class ParserBase : public Traits {
     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();
   }
@@ -108,7 +107,6 @@ class ParserBase : public Traits {
   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(); }
   bool allow_harmony_computed_property_names() const {
@@ -130,9 +128,6 @@ class ParserBase : public Traits {
   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);
   }
@@ -142,9 +137,6 @@ class ParserBase : public Traits {
   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;
   }
@@ -212,7 +204,7 @@ class ParserBase : public Traits {
       return next_materialized_literal_index_++;
     }
     int materialized_literal_count() {
-      return next_materialized_literal_index_ - JSFunction::kLiteralsPrefixSize;
+      return next_materialized_literal_index_;
     }
 
     int NextHandlerIndex() { return next_handler_index_++; }
@@ -221,6 +213,17 @@ class ParserBase : public Traits {
     void AddProperty() { expected_property_count_++; }
     int expected_property_count() { return expected_property_count_; }
 
+    Scanner::Location return_location() const { return return_location_; }
+    Scanner::Location super_call_location() const {
+      return super_call_location_;
+    }
+    void set_return_location(Scanner::Location location) {
+      return_location_ = location;
+    }
+    void set_super_call_location(Scanner::Location location) {
+      super_call_location_ = location;
+    }
+
     bool is_generator() const { return IsGeneratorFunction(kind_); }
 
     FunctionKind kind() const { return kind_; }
@@ -251,6 +254,12 @@ class ParserBase : public Traits {
     // Properties count estimation.
     int expected_property_count_;
 
+    // Location of most recent 'return' statement (invalid if none).
+    Scanner::Location return_location_;
+
+    // Location of call to the "super" constructor (invalid if none).
+    Scanner::Location super_call_location_;
+
     FunctionKind kind_;
     // For generators, this variable may hold the generator object. It variable
     // is used by yield expressions and return statements. It is not necessary
@@ -317,10 +326,9 @@ class ParserBase : public Traits {
     DCHECK(scope_type != MODULE_SCOPE || allow_harmony_modules());
     DCHECK((scope_type == FUNCTION_SCOPE && IsValidFunctionKind(kind)) ||
            kind == kNormalFunction);
-    Scope* result =
-        new (zone()) Scope(zone(), parent, scope_type, ast_value_factory());
-    bool uninitialized_this = IsSubclassConstructor(kind);
-    result->Initialize(uninitialized_this);
+    Scope* result = new (zone())
+        Scope(zone(), parent, scope_type, ast_value_factory(), kind);
+    result->Initialize();
     return result;
   }
 
@@ -527,19 +535,19 @@ class ParserBase : public Traits {
 
   // Report syntax errors.
   void ReportMessage(const char* message, const char* arg = NULL,
-                     bool is_reference_error = false) {
+                     ParseErrorType error_type = kSyntaxError) {
     Scanner::Location source_location = scanner()->location();
-    Traits::ReportMessageAt(source_location, message, arg, is_reference_error);
+    Traits::ReportMessageAt(source_location, message, arg, error_type);
   }
 
   void ReportMessageAt(Scanner::Location location, const char* message,
-                       bool is_reference_error = false) {
-    Traits::ReportMessageAt(location, message,
-                            reinterpret_cast<const char*>(0),
-                            is_reference_error);
+                       ParseErrorType error_type = kSyntaxError) {
+    Traits::ReportMessageAt(location, message, reinterpret_cast<const char*>(0),
+                            error_type);
   }
 
   void ReportUnexpectedToken(Token::Value token);
+  void ReportUnexpectedTokenAt(Scanner::Location location, Token::Value token);
 
   // Recursive descent functions:
 
@@ -821,11 +829,6 @@ class PreParserExpression {
                                ExpressionTypeField::encode(kThisExpression));
   }
 
-  static PreParserExpression Super() {
-    return PreParserExpression(TypeField::encode(kExpression) |
-                               ExpressionTypeField::encode(kSuperExpression));
-  }
-
   static PreParserExpression ThisProperty() {
     return PreParserExpression(
         TypeField::encode(kExpression) |
@@ -958,7 +961,6 @@ class PreParserExpression {
     kThisPropertyExpression,
     kPropertyExpression,
     kCallExpression,
-    kSuperExpression,
     kNoTemplateTagExpression
   };
 
@@ -1345,15 +1347,12 @@ class PreParserTraits {
   }
 
   // Reporting errors.
-  void ReportMessageAt(Scanner::Location location,
-                       const char* message,
+  void ReportMessageAt(Scanner::Location location, const char* message,
                        const char* arg = NULL,
-                       bool is_reference_error = false);
-  void ReportMessageAt(int start_pos,
-                       int end_pos,
-                       const char* message,
+                       ParseErrorType error_type = kSyntaxError);
+  void ReportMessageAt(int start_pos, int end_pos, const char* message,
                        const char* arg = NULL,
-                       bool is_reference_error = false);
+                       ParseErrorType error_type = kSyntaxError);
 
   // "null" return type creators.
   static PreParserIdentifier EmptyIdentifier() {
@@ -1403,7 +1402,7 @@ class PreParserTraits {
 
   static PreParserExpression SuperReference(Scope* scope,
                                             PreParserFactory* factory) {
-    return PreParserExpression::Super();
+    return PreParserExpression::Default();
   }
 
   static PreParserExpression DefaultConstructor(bool call_super, Scope* scope,
@@ -1418,8 +1417,8 @@ class PreParserTraits {
   }
 
   static PreParserExpression ExpressionFromIdentifier(
-      PreParserIdentifier name, int pos, Scope* scope,
-      PreParserFactory* factory) {
+      PreParserIdentifier name, int start_position, int end_position,
+      Scope* scope, PreParserFactory* factory) {
     return PreParserExpression::FromIdentifier(name);
   }
 
@@ -1668,9 +1667,11 @@ template <class Traits>
 ParserBase<Traits>::FunctionState::FunctionState(
     FunctionState** function_state_stack, Scope** scope_stack, Scope* scope,
     FunctionKind kind, typename Traits::Type::Factory* factory)
-    : next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize),
+    : next_materialized_literal_index_(0),
       next_handler_index_(0),
       expected_property_count_(0),
+      return_location_(Scanner::Location::invalid()),
+      super_call_location_(Scanner::Location::invalid()),
       kind_(kind),
       generator_object_variable_(NULL),
       function_state_stack_(function_state_stack),
@@ -1692,12 +1693,19 @@ ParserBase<Traits>::FunctionState::~FunctionState() {
 
 template<class Traits>
 void ParserBase<Traits>::ReportUnexpectedToken(Token::Value token) {
-  Scanner::Location source_location = scanner()->location();
+  return ReportUnexpectedTokenAt(scanner_->location(), token);
+}
+
+
+template<class Traits>
+void ParserBase<Traits>::ReportUnexpectedTokenAt(
+    Scanner::Location source_location, Token::Value token) {
 
   // Four of the tokens are treated specially
   switch (token) {
     case Token::EOS:
       return ReportMessageAt(source_location, "unexpected_eos");
+    case Token::SMI:
     case Token::NUMBER:
       return ReportMessageAt(source_location, "unexpected_token_number");
     case Token::STRING:
@@ -1869,23 +1877,26 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) {
   //   '(' Expression ')'
   //   TemplateLiteral
 
-  int pos = peek_position();
+  int beg_pos = scanner()->peek_location().beg_pos;
+  int end_pos = scanner()->peek_location().end_pos;
   ExpressionT result = this->EmptyExpression();
   Token::Value token = peek();
   switch (token) {
     case Token::THIS: {
       Consume(Token::THIS);
       scope_->RecordThisUsage();
-      result = this->ThisExpression(scope_, factory(), pos);
+      result = this->ThisExpression(scope_, factory(), beg_pos);
       break;
     }
 
     case Token::NULL_LITERAL:
     case Token::TRUE_LITERAL:
     case Token::FALSE_LITERAL:
+    case Token::SMI:
     case Token::NUMBER:
       Next();
-      result = this->ExpressionFromLiteral(token, pos, scanner(), factory());
+      result =
+          this->ExpressionFromLiteral(token, beg_pos, scanner(), factory());
       break;
 
     case Token::IDENTIFIER:
@@ -1895,13 +1906,14 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) {
     case Token::FUTURE_STRICT_RESERVED_WORD: {
       // Using eval or arguments in this context is OK even in strict mode.
       IdentifierT name = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
-      result = this->ExpressionFromIdentifier(name, pos, scope_, factory());
+      result = this->ExpressionFromIdentifier(name, beg_pos, end_pos, scope_,
+                                              factory());
       break;
     }
 
     case Token::STRING: {
       Consume(Token::STRING);
-      result = this->ExpressionFromString(pos, scanner(), factory());
+      result = this->ExpressionFromString(beg_pos, scanner(), factory());
       break;
     }
 
@@ -1928,7 +1940,7 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) {
         // for which an empty parameter list "()" is valid input.
         Consume(Token::RPAREN);
         result = this->ParseArrowFunctionLiteral(
-            pos, this->EmptyArrowParamList(), CHECK_OK);
+            beg_pos, this->EmptyArrowParamList(), CHECK_OK);
       } else {
         // Heuristically try to detect immediately called functions before
         // seeing the call parentheses.
@@ -1963,8 +1975,8 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) {
 
     case Token::TEMPLATE_SPAN:
     case Token::TEMPLATE_TAIL:
-      result =
-          this->ParseTemplateLiteral(Traits::NoTemplateTag(), pos, CHECK_OK);
+      result = this->ParseTemplateLiteral(Traits::NoTemplateTag(), beg_pos,
+                                          CHECK_OK);
       break;
 
     case Token::MOD:
@@ -2017,6 +2029,11 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
   while (peek() != Token::RBRACK) {
     ExpressionT elem = this->EmptyExpression();
     if (peek() == Token::COMMA) {
+      if (is_strong(language_mode())) {
+        ReportMessageAt(scanner()->peek_location(), "strong_ellision");
+        *ok = false;
+        return this->EmptyExpression();
+      }
       elem = this->GetLiteralTheHole(peek_position(), factory());
     } else {
       elem = this->ParseAssignmentExpression(true, CHECK_OK);
@@ -2057,6 +2074,11 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
       *name = this->GetSymbol(scanner());
       break;
 
+    case Token::SMI:
+      Consume(Token::SMI);
+      *name = this->GetNumberAsSymbol(scanner());
+      break;
+
     case Token::NUMBER:
       Consume(Token::NUMBER);
       *name = this->GetNumberAsSymbol(scanner());
@@ -2105,7 +2127,8 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralCheckerBase* checker,
   bool is_generator = allow_harmony_object_literals_ && Check(Token::MUL);
 
   Token::Value name_token = peek();
-  int next_pos = peek_position();
+  int next_beg_pos = scanner()->peek_location().beg_pos;
+  int next_end_pos = scanner()->peek_location().end_pos;
   ExpressionT name_expression = ParsePropertyName(
       &name, &is_get, &is_set, &name_is_static, is_computed_name,
       CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
@@ -2143,6 +2166,8 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralCheckerBase* checker,
                          : FunctionKind::kBaseConstructor;
     }
 
+    if (!in_class) kind = WithObjectLiteralBit(kind);
+
     value = this->ParseFunctionLiteral(
         name, scanner()->location(),
         false,  // reserved words are allowed here
@@ -2174,11 +2199,12 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralCheckerBase* checker,
                              CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
     }
 
+    FunctionKind kind = FunctionKind::kAccessorFunction;
+    if (!in_class) kind = WithObjectLiteralBit(kind);
     typename Traits::Type::FunctionLiteral value = this->ParseFunctionLiteral(
         name, scanner()->location(),
         false,  // reserved words are allowed here
-        FunctionKind::kAccessorFunction, RelocInfo::kNoPosition,
-        FunctionLiteral::ANONYMOUS_EXPRESSION,
+        kind, RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION,
         is_get ? FunctionLiteral::GETTER_ARITY : FunctionLiteral::SETTER_ARITY,
         CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
 
@@ -2200,7 +2226,8 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralCheckerBase* checker,
                                  this->is_generator())) {
     DCHECK(!*is_computed_name);
     DCHECK(!is_static);
-    value = this->ExpressionFromIdentifier(name, next_pos, scope_, factory());
+    value = this->ExpressionFromIdentifier(name, next_beg_pos, next_end_pos,
+                                           scope_, factory());
     return factory()->NewObjectLiteralProperty(
         name_expression, value, ObjectLiteralProperty::COMPUTED, false, false);
 
@@ -2301,13 +2328,17 @@ typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments(
       *ok = false;
       return this->NullExpressionList();
     }
-    done = (peek() == Token::RPAREN);
+    done = (peek() != Token::COMMA);
     if (!done) {
-      // Need {} because of the CHECK_OK_CUSTOM macro.
-      Expect(Token::COMMA, CHECK_OK_CUSTOM(NullExpressionList));
+      Next();
     }
   }
-  Expect(Token::RPAREN, CHECK_OK_CUSTOM(NullExpressionList));
+  Scanner::Location location = scanner_->location();
+  if (Token::RPAREN != Next()) {
+    ReportMessageAt(location, "unterminated_arg_list");
+    *ok = false;
+    return this->NullExpressionList();
+  }
   return result;
 }
 
@@ -2637,23 +2668,6 @@ ParserBase<Traits>::ParseLeftHandSideExpression(bool* ok) {
         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();
@@ -2724,7 +2738,7 @@ typename ParserBase<Traits>::ExpressionT
 ParserBase<Traits>::ParseMemberExpression(bool* ok) {
   // MemberExpression ::
   //   (PrimaryExpression | FunctionLiteral | ClassLiteral)
-  //     ('[' Expression ']' | '.' Identifier | Arguments)*
+  //     ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
 
   // The '[' Expression ']' and '.' Identifier parts are parsed by
   // ParseMemberExpressionContinuation, and the Arguments part is parsed by the
@@ -2786,6 +2800,19 @@ ParserBase<Traits>::ParseSuperExpression(bool is_new, bool* ok) {
     // new super() is never allowed.
     // super() is only allowed in derived constructor
     if (!is_new && peek() == Token::LPAREN && IsSubclassConstructor(kind)) {
+      if (is_strong(language_mode())) {
+        if (function_state->super_call_location().IsValid()) {
+          ReportMessageAt(scanner()->location(), "strong_super_call_duplicate");
+          *ok = false;
+          return this->EmptyExpression();
+        } else if (function_state->return_location().IsValid()) {
+          ReportMessageAt(function_state->return_location(),
+                          "strong_constructor_return_misplaced");
+          *ok = false;
+          return this->EmptyExpression();
+        }
+      }
+      function_state->set_super_call_location(scanner()->location());
       return this->SuperReference(scope_, factory());
     }
   }
@@ -2801,7 +2828,7 @@ typename ParserBase<Traits>::ExpressionT
 ParserBase<Traits>::ParseMemberExpressionContinuation(ExpressionT expression,
                                                       bool* ok) {
   // Parses this part of MemberExpression:
-  // ('[' Expression ']' | '.' Identifier)*
+  // ('[' Expression ']' | '.' Identifier | TemplateLiteral)*
   while (true) {
     switch (peek()) {
       case Token::LBRACK: {
@@ -2826,6 +2853,22 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(ExpressionT expression,
         }
         break;
       }
+      case Token::TEMPLATE_SPAN:
+      case Token::TEMPLATE_TAIL: {
+        int pos;
+        if (scanner()->current_token() == Token::IDENTIFIER) {
+          pos = position();
+        } else {
+          pos = peek_position();
+          if (expression->IsFunctionLiteral() && mode() == PARSE_EAGERLY) {
+            // If the tag function looks like an IIFE, set_parenthesized() to
+            // force eager compilation.
+            expression->AsFunctionLiteral()->set_parenthesized();
+          }
+        }
+        expression = ParseTemplateLiteral(expression, pos, CHECK_OK);
+        break;
+      }
       default:
         return expression;
     }
@@ -2840,12 +2883,22 @@ typename ParserBase<Traits>::ExpressionT
 ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos,
                                               ExpressionT params_ast,
                                               bool* ok) {
+  if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) {
+    // ASI inserts `;` after arrow parameters if a line terminator is found.
+    // `=> ...` is never a valid expression, so report as syntax error.
+    // If next token is not `=>`, it's a syntax error anyways.
+    ReportUnexpectedTokenAt(scanner_->peek_location(), Token::ARROW);
+    *ok = false;
+    return this->EmptyExpression();
+  }
+
   Scope* scope = this->NewScope(scope_, ARROW_SCOPE);
   typename Traits::Type::StatementList body;
   int num_parameters = -1;
   int materialized_literal_count = -1;
   int expected_property_count = -1;
   int handler_count = 0;
+  Scanner::Location super_loc;
 
   {
     typename Traits::Type::Factory function_factory(ast_value_factory());
@@ -2901,6 +2954,7 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos,
       expected_property_count = function_state.expected_property_count();
       handler_count = function_state.handler_count();
     }
+    super_loc = function_state.super_call_location();
 
     scope->set_start_position(start_pos);
     scope->set_end_position(scanner()->location().end_pos);
@@ -2918,10 +2972,8 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos,
     if (is_strict(language_mode())) {
       CheckStrictOctalLiteral(start_pos, scanner()->location().end_pos,
                               CHECK_OK);
-    }
-
-    if (allow_harmony_scoping() && is_strict(language_mode()))
       this->CheckConflictingVarDeclarations(scope, CHECK_OK);
+    }
   }
 
   FunctionLiteralT function_literal = factory()->NewFunctionLiteral(
@@ -2933,6 +2985,7 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos,
       start_pos);
 
   function_literal->set_function_token_position(start_pos);
+  if (super_loc.IsValid()) function_state_->set_super_call_location(super_loc);
 
   if (fni_ != NULL) this->InferFunctionName(fni_, function_literal);
 
@@ -2988,7 +3041,7 @@ ParserBase<Traits>::ParseTemplateLiteral(ExpressionT tag, int start, bool* ok) {
     } else if (next == Token::ILLEGAL) {
       Traits::ReportMessageAt(
           Scanner::Location(position() + 1, peek_position()),
-          "unexpected_token", "ILLEGAL", false);
+          "unexpected_token", "ILLEGAL", kSyntaxError);
       *ok = false;
       return Traits::EmptyExpression();
     }
@@ -3017,7 +3070,7 @@ ParserBase<Traits>::ParseTemplateLiteral(ExpressionT tag, int start, bool* ok) {
     } else if (next == Token::ILLEGAL) {
       Traits::ReportMessageAt(
           Scanner::Location(position() + 1, peek_position()),
-          "unexpected_token", "ILLEGAL", false);
+          "unexpected_token", "ILLEGAL", kSyntaxError);
       *ok = false;
       return Traits::EmptyExpression();
     }
@@ -3039,7 +3092,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<
                                                 const char* message, bool* ok) {
   if (is_strict(language_mode()) && this->IsIdentifier(expression) &&
       this->IsEvalOrArguments(this->AsIdentifier(expression))) {
-    this->ReportMessageAt(location, "strict_eval_arguments", false);
+    this->ReportMessageAt(location, "strict_eval_arguments", kSyntaxError);
     *ok = false;
     return this->EmptyExpression();
   } else if (expression->IsValidReferenceExpression()) {
@@ -3051,7 +3104,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<
     ExpressionT error = this->NewThrowReferenceError(message, pos);
     return factory()->NewProperty(expression, error, pos);
   } else {
-    this->ReportMessageAt(location, message, true);
+    this->ReportMessageAt(location, message, kReferenceError);
     *ok = false;
     return this->EmptyExpression();
   }
@@ -3069,7 +3122,7 @@ void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty(
   DCHECK(!is_static);
   DCHECK(!is_generator || type == kMethodProperty);
 
-  if (property == Token::NUMBER) return;
+  if (property == Token::SMI || property == Token::NUMBER) return;
 
   if (type == kValueProperty && IsProto()) {
     if (has_seen_proto_) {
@@ -3089,7 +3142,7 @@ void ParserBase<Traits>::ClassLiteralChecker::CheckProperty(
     bool* ok) {
   DCHECK(type == kMethodProperty || type == kAccessorProperty);
 
-  if (property == Token::NUMBER) return;
+  if (property == Token::SMI || property == Token::NUMBER) return;
 
   if (is_static) {
     if (IsPrototype()) {
@@ -3099,7 +3152,9 @@ void ParserBase<Traits>::ClassLiteralChecker::CheckProperty(
     }
   } else if (IsConstructor()) {
     if (is_generator || type == kAccessorProperty) {
-      this->parser()->ReportMessage("constructor_special_method");
+      const char* msg =
+          is_generator ? "constructor_is_generator" : "constructor_is_accessor";
+      this->parser()->ReportMessage(msg);
       *ok = false;
       return;
     }
index da43d0e..165e717 100644 (file)
@@ -106,7 +106,6 @@ void CallPrinter::VisitModuleDeclaration(ModuleDeclaration* node) {
 
 
 void CallPrinter::VisitImportDeclaration(ImportDeclaration* node) {
-  Find(node->module());
 }
 
 
@@ -481,7 +480,7 @@ void PrettyPrinter::VisitImportDeclaration(ImportDeclaration* node) {
   Print("import ");
   PrintLiteral(node->proxy()->name(), false);
   Print(" from ");
-  Visit(node->module());
+  PrintLiteral(node->module_specifier()->string(), true);
   Print(";");
 }
 
@@ -1213,7 +1212,7 @@ void AstPrinter::VisitModuleDeclaration(ModuleDeclaration* node) {
 void AstPrinter::VisitImportDeclaration(ImportDeclaration* node) {
   IndentedScope indent(this, "IMPORT");
   PrintLiteralIndented("NAME", node->proxy()->name(), true);
-  Visit(node->module());
+  PrintLiteralIndented("FROM", node->module_specifier()->string(), true);
 }
 
 
index d9f55dd..1e543dd 100644 (file)
@@ -21,12 +21,12 @@ CodeEntry::CodeEntry(Logger::LogEventsAndTags tag, const char* name,
       resource_name_(resource_name),
       line_number_(line_number),
       column_number_(column_number),
-      shared_id_(0),
       script_id_(v8::UnboundScript::kNoScriptId),
+      position_(0),
       no_frame_ranges_(NULL),
       bailout_reason_(kEmptyBailoutReason),
       deopt_reason_(kNoDeoptReason),
-      deopt_location_(0),
+      deopt_position_(SourcePosition::Unknown()),
       line_info_(line_info),
       instruction_start_(instruction_start) {}
 
@@ -48,6 +48,11 @@ ProfileNode::ProfileNode(ProfileTree* tree, CodeEntry* entry)
       children_(CodeEntriesMatch),
       id_(tree->next_node_id()),
       line_ticks_(LineTickMatch) {}
+
+
+inline unsigned ProfileNode::function_id() const {
+  return tree_->GetFunctionId(this);
+}
 } }  // namespace v8::internal
 
 #endif  // V8_PROFILE_GENERATOR_INL_H_
index 292e332..385e753 100644 (file)
@@ -18,120 +18,6 @@ namespace v8 {
 namespace internal {
 
 
-bool StringsStorage::StringsMatch(void* key1, void* key2) {
-  return strcmp(reinterpret_cast<char*>(key1),
-                reinterpret_cast<char*>(key2)) == 0;
-}
-
-
-StringsStorage::StringsStorage(Heap* heap)
-    : hash_seed_(heap->HashSeed()), names_(StringsMatch) {
-}
-
-
-StringsStorage::~StringsStorage() {
-  for (HashMap::Entry* p = names_.Start();
-       p != NULL;
-       p = names_.Next(p)) {
-    DeleteArray(reinterpret_cast<const char*>(p->value));
-  }
-}
-
-
-const char* StringsStorage::GetCopy(const char* src) {
-  int len = static_cast<int>(strlen(src));
-  HashMap::Entry* entry = GetEntry(src, len);
-  if (entry->value == NULL) {
-    Vector<char> dst = Vector<char>::New(len + 1);
-    StrNCpy(dst, src, len);
-    dst[len] = '\0';
-    entry->key = dst.start();
-    entry->value = entry->key;
-  }
-  return reinterpret_cast<const char*>(entry->value);
-}
-
-
-const char* StringsStorage::GetFormatted(const char* format, ...) {
-  va_list args;
-  va_start(args, format);
-  const char* result = GetVFormatted(format, args);
-  va_end(args);
-  return result;
-}
-
-
-const char* StringsStorage::AddOrDisposeString(char* str, int len) {
-  HashMap::Entry* entry = GetEntry(str, len);
-  if (entry->value == NULL) {
-    // New entry added.
-    entry->key = str;
-    entry->value = str;
-  } else {
-    DeleteArray(str);
-  }
-  return reinterpret_cast<const char*>(entry->value);
-}
-
-
-const char* StringsStorage::GetVFormatted(const char* format, va_list args) {
-  Vector<char> str = Vector<char>::New(1024);
-  int len = VSNPrintF(str, format, args);
-  if (len == -1) {
-    DeleteArray(str.start());
-    return GetCopy(format);
-  }
-  return AddOrDisposeString(str.start(), len);
-}
-
-
-const char* StringsStorage::GetName(Name* name) {
-  if (name->IsString()) {
-    String* str = String::cast(name);
-    int length = Min(kMaxNameSize, str->length());
-    int actual_length = 0;
-    SmartArrayPointer<char> data =
-        str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL, 0, length,
-                       &actual_length);
-    return AddOrDisposeString(data.Detach(), actual_length);
-  } else if (name->IsSymbol()) {
-    return "<symbol>";
-  }
-  return "";
-}
-
-
-const char* StringsStorage::GetName(int index) {
-  return GetFormatted("%d", index);
-}
-
-
-const char* StringsStorage::GetFunctionName(Name* name) {
-  return GetName(name);
-}
-
-
-const char* StringsStorage::GetFunctionName(const char* name) {
-  return GetCopy(name);
-}
-
-
-size_t StringsStorage::GetUsedMemorySize() const {
-  size_t size = sizeof(*this);
-  size += sizeof(HashMap::Entry) * names_.capacity();
-  for (HashMap::Entry* p = names_.Start(); p != NULL; p = names_.Next(p)) {
-    size += strlen(reinterpret_cast<const char*>(p->value)) + 1;
-  }
-  return size;
-}
-
-
-HashMap::Entry* StringsStorage::GetEntry(const char* str, int len) {
-  uint32_t hash = StringHasher::HashSequentialString(str, len, hash_seed_);
-  return names_.Lookup(const_cast<char*>(str), hash, true);
-}
-
-
 JITLineInfoTable::JITLineInfoTable() {}
 
 
@@ -169,10 +55,12 @@ CodeEntry::~CodeEntry() {
 }
 
 
-uint32_t CodeEntry::GetCallUid() const {
+uint32_t CodeEntry::GetHash() const {
   uint32_t hash = ComputeIntegerHash(tag(), v8::internal::kZeroHashSeed);
-  if (shared_id_ != 0) {
-    hash ^= ComputeIntegerHash(static_cast<uint32_t>(shared_id_),
+  if (script_id_ != v8::UnboundScript::kNoScriptId) {
+    hash ^= ComputeIntegerHash(static_cast<uint32_t>(script_id_),
+                               v8::internal::kZeroHashSeed);
+    hash ^= ComputeIntegerHash(static_cast<uint32_t>(position_),
                                v8::internal::kZeroHashSeed);
   } else {
     hash ^= ComputeIntegerHash(
@@ -190,13 +78,14 @@ uint32_t CodeEntry::GetCallUid() const {
 }
 
 
-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_)));
+bool CodeEntry::IsSameFunctionAs(CodeEntry* entry) const {
+  if (this == entry) return true;
+  if (script_id_ != v8::UnboundScript::kNoScriptId) {
+    return script_id_ == entry->script_id_ && position_ == entry->position_;
+  }
+  return name_prefix_ == entry->name_prefix_ && name_ == entry->name_ &&
+         resource_name_ == entry->resource_name_ &&
+         line_number_ == entry->line_number_;
 }
 
 
@@ -214,8 +103,51 @@ int CodeEntry::GetSourceLine(int pc_offset) const {
 }
 
 
+void CodeEntry::FillFunctionInfo(SharedFunctionInfo* shared) {
+  if (!shared->script()->IsScript()) return;
+  Script* script = Script::cast(shared->script());
+  set_script_id(script->id()->value());
+  set_position(shared->start_position());
+  set_bailout_reason(GetBailoutReason(shared->disable_optimization_reason()));
+}
+
+
+DeoptInfo CodeEntry::GetDeoptInfo() {
+  DCHECK(has_deopt_info());
+
+  DeoptInfo info;
+  info.deopt_reason = deopt_reason_;
+  if (inlined_function_infos_.empty()) {
+    info.stack.push_back(DeoptInfo::Frame(
+        {script_id_,
+         static_cast<int>(position_ + deopt_position_.position())}));
+    return info;
+  }
+  // Copy the only branch from the inlining tree where the deopt happened.
+  SourcePosition position = deopt_position_;
+  int inlining_id = InlinedFunctionInfo::kNoParentId;
+  for (size_t i = 0; i < inlined_function_infos_.size(); ++i) {
+    InlinedFunctionInfo& current_info = inlined_function_infos_.at(i);
+    if (std::binary_search(current_info.deopt_pc_offsets.begin(),
+                           current_info.deopt_pc_offsets.end(), pc_offset_)) {
+      inlining_id = static_cast<int>(i);
+      break;
+    }
+  }
+  while (inlining_id != InlinedFunctionInfo::kNoParentId) {
+    InlinedFunctionInfo& inlined_info = inlined_function_infos_.at(inlining_id);
+    info.stack.push_back(DeoptInfo::Frame(
+        {inlined_info.script_id,
+         static_cast<int>(inlined_info.start_position + position.raw())}));
+    position = inlined_info.inline_position;
+    inlining_id = inlined_info.parent_id;
+  }
+  return info;
+}
+
+
 void ProfileNode::CollectDeoptInfo(CodeEntry* entry) {
-  deopt_infos_.Add(DeoptInfo(entry->deopt_reason(), entry->deopt_location()));
+  deopt_infos_.push_back(entry->GetDeoptInfo());
   entry->clear_deopt_info();
 }
 
@@ -283,9 +215,17 @@ void ProfileNode::Print(int indent) {
   if (entry_->resource_name()[0] != '\0')
     base::OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number());
   base::OS::Print("\n");
-  for (auto info : deopt_infos_) {
-    base::OS::Print("%*s deopted at %d with reason '%s'\n", indent + 10, "",
-                    info.deopt_location, info.deopt_reason);
+  for (size_t i = 0; i < deopt_infos_.size(); ++i) {
+    DeoptInfo& info = deopt_infos_[i];
+    base::OS::Print(
+        "%*s;;; deopted at script_id: %d position: %d with reason '%s'.\n",
+        indent + 10, "", info.stack[0].script_id, info.stack[0].position,
+        info.deopt_reason);
+    for (size_t index = 1; index < info.stack.size(); ++index) {
+      base::OS::Print("%*s;;;     Inline point: script_id %d position: %d.\n",
+                      indent + 10, "", info.stack[index].script_id,
+                      info.stack[index].position);
+    }
   }
   const char* bailout_reason = entry_->bailout_reason();
   if (bailout_reason != GetBailoutReason(BailoutReason::kNoReason) &&
@@ -316,8 +256,9 @@ class DeleteNodesCallback {
 ProfileTree::ProfileTree()
     : root_entry_(Logger::FUNCTION_TAG, "(root)"),
       next_node_id_(1),
-      root_(new ProfileNode(this, &root_entry_)) {
-}
+      root_(new ProfileNode(this, &root_entry_)),
+      next_function_id_(1),
+      function_ids_(ProfileNode::CodeEntriesMatch) {}
 
 
 ProfileTree::~ProfileTree() {
@@ -326,6 +267,17 @@ ProfileTree::~ProfileTree() {
 }
 
 
+unsigned ProfileTree::GetFunctionId(const ProfileNode* node) {
+  CodeEntry* code_entry = node->entry();
+  HashMap::Entry* entry =
+      function_ids_.Lookup(code_entry, code_entry->GetHash(), true);
+  if (!entry->value) {
+    entry->value = reinterpret_cast<void*>(next_function_id_++);
+  }
+  return static_cast<unsigned>(reinterpret_cast<uintptr_t>(entry->value));
+}
+
+
 ProfileNode* ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path,
                                          int src_line) {
   ProfileNode* node = root_;
@@ -427,7 +379,6 @@ void CpuProfile::Print() {
 }
 
 
-CodeEntry* const CodeMap::kSharedFunctionCodeEntry = NULL;
 const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL;
 
 
@@ -469,22 +420,6 @@ CodeEntry* CodeMap::FindEntry(Address addr, Address* start) {
 }
 
 
-int CodeMap::GetSharedId(Address addr) {
-  CodeTree::Locator locator;
-  // For shared function entries, 'size' field is used to store their IDs.
-  if (tree_.Find(addr, &locator)) {
-    const CodeEntryInfo& entry = locator.value();
-    DCHECK(entry.entry == kSharedFunctionCodeEntry);
-    return entry.size;
-  } else {
-    tree_.Insert(addr, &locator);
-    int id = next_shared_id_++;
-    locator.set_value(CodeEntryInfo(kSharedFunctionCodeEntry, id));
-    return id;
-  }
-}
-
-
 void CodeMap::MoveCode(Address from, Address to) {
   if (from == to) return;
   CodeTree::Locator locator;
@@ -497,12 +432,7 @@ void CodeMap::MoveCode(Address from, Address to) {
 
 void CodeMap::CodeTreePrinter::Call(
     const Address& key, const CodeMap::CodeEntryInfo& value) {
-  // For shared function entries, 'size' field is used to store their IDs.
-  if (value.entry == kSharedFunctionCodeEntry) {
-    base::OS::Print("%p SharedFunctionInfo %d\n", key, value.size);
-  } else {
-    base::OS::Print("%p %5d %s\n", key, value.size, value.entry->name());
-  }
+  base::OS::Print("%p %5d %s\n", key, value.size, value.entry->name());
 }
 
 
index f7176a0..e013e29 100644 (file)
@@ -8,43 +8,15 @@
 #include <map>
 #include "include/v8-profiler.h"
 #include "src/allocation.h"
+#include "src/compiler.h"
 #include "src/hashmap.h"
+#include "src/strings-storage.h"
 
 namespace v8 {
 namespace internal {
 
 struct OffsetRange;
 
-// Provides a storage of strings allocated in C++ heap, to hold them
-// forever, even if they disappear from JS heap or external storage.
-class StringsStorage {
- public:
-  explicit StringsStorage(Heap* heap);
-  ~StringsStorage();
-
-  const char* GetCopy(const char* src);
-  const char* GetFormatted(const char* format, ...);
-  const char* GetVFormatted(const char* format, va_list args);
-  const char* GetName(Name* name);
-  const char* GetName(int index);
-  const char* GetFunctionName(Name* name);
-  const char* GetFunctionName(const char* name);
-  size_t GetUsedMemorySize() const;
-
- private:
-  static const int kMaxNameSize = 1024;
-
-  static bool StringsMatch(void* key1, void* key2);
-  const char* AddOrDisposeString(char* str, int len);
-  HashMap::Entry* GetEntry(const char* str, int len);
-
-  uint32_t hash_seed_;
-  HashMap names_;
-
-  DISALLOW_COPY_AND_ASSIGN(StringsStorage);
-};
-
-
 // Provides a mapping from the offsets within generated code to
 // the source line.
 class JITLineInfoTable : public Malloced {
@@ -64,6 +36,17 @@ class JITLineInfoTable : public Malloced {
   DISALLOW_COPY_AND_ASSIGN(JITLineInfoTable);
 };
 
+
+struct DeoptInfo {
+  const char* deopt_reason;
+  struct Frame {
+    int script_id;
+    int position;
+  };
+  std::vector<Frame> stack;
+};
+
+
 class CodeEntry {
  public:
   // CodeEntry doesn't own name strings, just references them.
@@ -84,41 +67,54 @@ class CodeEntry {
   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; }
+  int position() const { return position_; }
+  void set_position(int position) { position_ = position; }
   void set_bailout_reason(const char* bailout_reason) {
     bailout_reason_ = bailout_reason;
   }
   const char* bailout_reason() const { return bailout_reason_; }
 
-  void set_deopt_info(const char* deopt_reason, int location) {
-    DCHECK(!deopt_location_);
+  void set_deopt_info(const char* deopt_reason, SourcePosition position,
+                      size_t pc_offset) {
+    DCHECK(deopt_position_.IsUnknown());
     deopt_reason_ = deopt_reason;
-    deopt_location_ = location;
+    deopt_position_ = position;
+    pc_offset_ = pc_offset;
   }
+  DeoptInfo GetDeoptInfo();
   const char* deopt_reason() const { return deopt_reason_; }
-  int deopt_location() const { return deopt_location_; }
-  bool has_deopt_info() const { return deopt_location_; }
+  SourcePosition deopt_position() const { return deopt_position_; }
+  bool has_deopt_info() const { return !deopt_position_.IsUnknown(); }
   void clear_deopt_info() {
     deopt_reason_ = kNoDeoptReason;
-    deopt_location_ = 0;
+    deopt_position_ = SourcePosition::Unknown();
   }
 
+  void FillFunctionInfo(SharedFunctionInfo* shared);
+
   static inline bool is_js_function_tag(Logger::LogEventsAndTags tag);
 
   List<OffsetRange>* no_frame_ranges() const { return no_frame_ranges_; }
   void set_no_frame_ranges(List<OffsetRange>* ranges) {
     no_frame_ranges_ = ranges;
   }
+  void set_inlined_function_infos(
+      const std::vector<InlinedFunctionInfo>& infos) {
+    inlined_function_infos_ = infos;
+  }
+  const std::vector<InlinedFunctionInfo> inlined_function_infos() {
+    return inlined_function_infos_;
+  }
 
   void SetBuiltinId(Builtins::Name id);
   Builtins::Name builtin_id() const {
     return BuiltinIdField::decode(bit_field_);
   }
 
-  uint32_t GetCallUid() const;
-  bool IsSameAs(CodeEntry* entry) const;
+  uint32_t GetHash() const;
+  bool IsSameFunctionAs(CodeEntry* entry) const;
 
   int GetSourceLine(int pc_offset) const;
 
@@ -140,15 +136,18 @@ class CodeEntry {
   const char* resource_name_;
   int line_number_;
   int column_number_;
-  int shared_id_;
   int script_id_;
+  int position_;
   List<OffsetRange>* no_frame_ranges_;
   const char* bailout_reason_;
   const char* deopt_reason_;
-  int deopt_location_;
+  SourcePosition deopt_position_;
+  size_t pc_offset_;
   JITLineInfoTable* line_info_;
   Address instruction_start_;
 
+  std::vector<InlinedFunctionInfo> inlined_function_infos_;
+
   DISALLOW_COPY_AND_ASSIGN(CodeEntry);
 };
 
@@ -156,17 +155,6 @@ class CodeEntry {
 class ProfileTree;
 
 class ProfileNode {
- private:
-  struct DeoptInfo {
-    DeoptInfo(const char* deopt_reason, int deopt_location)
-        : deopt_reason(deopt_reason), deopt_location(deopt_location) {}
-    DeoptInfo(const DeoptInfo& info)
-        : deopt_reason(info.deopt_reason),
-          deopt_location(info.deopt_location) {}
-    const char* deopt_reason;
-    int deopt_location;
-  };
-
  public:
   inline ProfileNode(ProfileTree* tree, CodeEntry* entry);
 
@@ -180,23 +168,22 @@ class ProfileNode {
   unsigned self_ticks() const { return self_ticks_; }
   const List<ProfileNode*>* children() const { return &children_list_; }
   unsigned id() const { return id_; }
+  unsigned function_id() const;
   unsigned int GetHitLineCount() const { return line_ticks_.occupancy(); }
   bool GetLineTicks(v8::CpuProfileNode::LineTick* entries,
                     unsigned int length) const;
   void CollectDeoptInfo(CodeEntry* entry);
-  const List<DeoptInfo>& deopt_infos() const { return deopt_infos_; }
+  const std::vector<DeoptInfo>& deopt_infos() const { return deopt_infos_; }
 
   void Print(int indent);
 
- private:
   static bool CodeEntriesMatch(void* entry1, void* entry2) {
-    return reinterpret_cast<CodeEntry*>(entry1)->IsSameAs(
-        reinterpret_cast<CodeEntry*>(entry2));
+    return reinterpret_cast<CodeEntry*>(entry1)
+        ->IsSameFunctionAs(reinterpret_cast<CodeEntry*>(entry2));
   }
 
-  static uint32_t CodeEntryHash(CodeEntry* entry) {
-    return entry->GetCallUid();
-  }
+ private:
+  static uint32_t CodeEntryHash(CodeEntry* entry) { return entry->GetHash(); }
 
   static bool LineTickMatch(void* a, void* b) { return a == b; }
 
@@ -209,7 +196,8 @@ class ProfileNode {
   unsigned id_;
   HashMap line_ticks_;
 
-  List<DeoptInfo> deopt_infos_;
+  std::vector<DeoptInfo> deopt_infos_;
+
   DISALLOW_COPY_AND_ASSIGN(ProfileNode);
 };
 
@@ -224,6 +212,7 @@ class ProfileTree {
       int src_line = v8::CpuProfileNode::kNoLineNumberInfo);
   ProfileNode* root() const { return root_; }
   unsigned next_node_id() { return next_node_id_++; }
+  unsigned GetFunctionId(const ProfileNode* node);
 
   void Print() {
     root_->Print(0);
@@ -237,6 +226,9 @@ class ProfileTree {
   unsigned next_node_id_;
   ProfileNode* root_;
 
+  unsigned next_function_id_;
+  HashMap function_ids_;
+
   DISALLOW_COPY_AND_ASSIGN(ProfileTree);
 };
 
@@ -281,7 +273,7 @@ class CpuProfile {
 
 class CodeMap {
  public:
-  CodeMap() : next_shared_id_(1) { }
+  CodeMap() {}
   void AddCode(Address addr, CodeEntry* entry, unsigned size);
   void MoveCode(Address from, Address to);
   CodeEntry* FindEntry(Address addr, Address* start = NULL);
@@ -315,11 +307,7 @@ class CodeMap {
 
   void DeleteAllCoveredCode(Address start, Address end);
 
-  // Fake CodeEntry pointer to distinguish shared function entries.
-  static CodeEntry* const kSharedFunctionCodeEntry;
-
   CodeTree tree_;
-  int next_shared_id_;
 
   DISALLOW_COPY_AND_ASSIGN(CodeMap);
 };
index c096296..c7bd204 100644 (file)
@@ -44,7 +44,7 @@ var lastMicrotaskId = 0;
       throw MakeTypeError('resolver_not_a_function', [resolver]);
     var promise = PromiseInit(this);
     try {
-      %DebugPushPromise(promise);
+      %DebugPushPromise(promise, Promise);
       resolver(function(x) { PromiseResolve(promise, x) },
                function(r) { PromiseReject(promise, r) });
     } catch (e) {
@@ -110,7 +110,7 @@ var lastMicrotaskId = 0;
 
   function PromiseHandle(value, handler, deferred) {
     try {
-      %DebugPushPromise(deferred.promise);
+      %DebugPushPromise(deferred.promise, PromiseHandle);
       DEBUG_PREPARE_STEP_IN_IF_STEPPING(handler);
       var result = handler(value);
       if (result === deferred.promise)
@@ -301,51 +301,44 @@ var lastMicrotaskId = 0;
     return IsPromise(x) ? x : new this(function(resolve) { resolve(x) });
   }
 
-  function PromiseAll(values) {
+  function PromiseAll(iterable) {
     var deferred = %_CallFunction(this, PromiseDeferred);
     var resolutions = [];
-    if (!%_IsArray(values)) {
-      deferred.reject(MakeTypeError('invalid_argument'));
-      return deferred.promise;
-    }
     try {
-      var count = values.length;
-      if (count === 0) {
-        deferred.resolve(resolutions);
-      } else {
-        for (var i = 0; i < values.length; ++i) {
-          this.resolve(values[i]).then(
-            (function() {
-              // Nested scope to get closure over current i (and avoid .bind).
-              // TODO(rossberg): Use for-let instead once available.
-              var i_captured = i;
+      var count = 0;
+      var i = 0;
+      for (var value of iterable) {
+        this.resolve(value).then(
+            // Nested scope to get closure over current i.
+            // TODO(arv): Use an inner let binding once available.
+            (function(i) {
               return function(x) {
-                resolutions[i_captured] = x;
+                resolutions[i] = x;
                 if (--count === 0) deferred.resolve(resolutions);
-              };
-            })(),
-            function(r) { deferred.reject(r) }
-          );
-        }
+              }
+            })(i),
+            function(r) { deferred.reject(r); });
+        ++i;
+        ++count;
+      }
+
+      if (count === 0) {
+        deferred.resolve(resolutions);
       }
+
     } catch (e) {
       deferred.reject(e)
     }
     return deferred.promise;
   }
 
-  function PromiseOne(values) {
+  function PromiseRace(iterable) {
     var deferred = %_CallFunction(this, PromiseDeferred);
-    if (!%_IsArray(values)) {
-      deferred.reject(MakeTypeError('invalid_argument'));
-      return deferred.promise;
-    }
     try {
-      for (var i = 0; i < values.length; ++i) {
-        this.resolve(values[i]).then(
-          function(x) { deferred.resolve(x) },
-          function(r) { deferred.reject(r) }
-        );
+      for (var value of iterable) {
+        this.resolve(value).then(
+            function(x) { deferred.resolve(x) },
+            function(r) { deferred.reject(r) });
       }
     } catch (e) {
       deferred.reject(e)
@@ -388,7 +381,7 @@ var lastMicrotaskId = 0;
     "accept", PromiseResolved,
     "reject", PromiseRejected,
     "all", PromiseAll,
-    "race", PromiseOne,
+    "race", PromiseRace,
     "resolve", PromiseCast
   ]);
   InstallFunctions($Promise.prototype, DONT_ENUM, [
index 135a079..e71419a 100644 (file)
@@ -187,16 +187,25 @@ static const int kInvalidEnumCacheSentinel =
     (1 << kDescriptorIndexBitCount) - 1;
 
 
+enum class PropertyCellType {
+  kUninitialized,        // Cell is deleted or not yet defined.
+  kUndefined,            // The PREMONOMORPHIC of property cells.
+  kConstant,             // Cell has been assigned only once.
+  kMutable,              // Cell will no longer be tracked as constant.
+  kDeleted = kConstant,  // like kUninitialized, but for cells already deleted.
+  kInvalid = kMutable,   // For dictionaries not holding cells.
+};
+
+
 // PropertyDetails captures type and attributes for a property.
 // They are used both in property dictionaries and instance descriptors.
 class PropertyDetails BASE_EMBEDDED {
  public:
-  PropertyDetails(PropertyAttributes attributes,
-                  PropertyType type,
-                  int index) {
-    value_ = TypeField::encode(type)
-        | AttributesField::encode(attributes)
-        | DictionaryStorageField::encode(index);
+  PropertyDetails(PropertyAttributes attributes, PropertyType type, int index,
+                  PropertyCellType cell_type) {
+    value_ = TypeField::encode(type) | AttributesField::encode(attributes) |
+             DictionaryStorageField::encode(index) |
+             PropertyCellTypeField::encode(cell_type);
 
     DCHECK(type == this->type());
     DCHECK(attributes == this->attributes());
@@ -221,14 +230,32 @@ class PropertyDetails BASE_EMBEDDED {
              FieldIndexField::encode(field_index);
   }
 
+  static PropertyDetails Empty() {
+    return PropertyDetails(NONE, DATA, 0, PropertyCellType::kInvalid);
+  }
+
   int pointer() const { return DescriptorPointer::decode(value_); }
 
-  PropertyDetails set_pointer(int i) { return PropertyDetails(value_, i); }
+  PropertyDetails set_pointer(int i) const {
+    return PropertyDetails(value_, i);
+  }
+
+  PropertyDetails set_cell_type(PropertyCellType type) const {
+    PropertyDetails details = *this;
+    details.value_ = PropertyCellTypeField::update(details.value_, type);
+    return details;
+  }
+
+  PropertyDetails set_index(int index) const {
+    PropertyDetails details = *this;
+    details.value_ = DictionaryStorageField::update(details.value_, index);
+    return details;
+  }
 
   PropertyDetails CopyWithRepresentation(Representation representation) const {
     return PropertyDetails(value_, representation);
   }
-  PropertyDetails CopyAddAttributes(PropertyAttributes new_attributes) {
+  PropertyDetails CopyAddAttributes(PropertyAttributes new_attributes) const {
     new_attributes =
         static_cast<PropertyAttributes>(attributes() | new_attributes);
     return PropertyDetails(value_, new_attributes);
@@ -267,8 +294,6 @@ class PropertyDetails BASE_EMBEDDED {
 
   inline int field_width_in_words() const;
 
-  inline PropertyDetails AsDeleted() const;
-
   static bool IsValidIndex(int index) {
     return DictionaryStorageField::is_valid(index);
   }
@@ -276,7 +301,9 @@ class PropertyDetails BASE_EMBEDDED {
   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; }
+  PropertyCellType cell_type() const {
+    return PropertyCellTypeField::decode(value_);
+  }
 
   // Bit fields in value_ (type, shift, size). Must be public so the
   // constants can be embedded in generated code.
@@ -285,8 +312,8 @@ class PropertyDetails BASE_EMBEDDED {
   class AttributesField : public BitField<PropertyAttributes, 2, 3> {};
 
   // Bit fields for normalized objects.
-  class DeletedField : public BitField<uint32_t, 5, 1> {};
-  class DictionaryStorageField : public BitField<uint32_t, 6, 24> {};
+  class PropertyCellTypeField : public BitField<PropertyCellType, 5, 2> {};
+  class DictionaryStorageField : public BitField<uint32_t, 7, 24> {};
 
   // Bit fields for fast objects.
   class RepresentationField : public BitField<uint32_t, 5, 4> {};
index 5f8e6da..c6556b3 100644 (file)
@@ -79,10 +79,14 @@ class DataDescriptor FINAL : public Descriptor {
                  PropertyAttributes attributes, Representation representation)
       : Descriptor(key, HeapType::Any(key->GetIsolate()), attributes, DATA,
                    representation, field_index) {}
-  DataDescriptor(Handle<Name> key, int field_index, Handle<HeapType> field_type,
+  // The field type is either a simple type or a map wrapped in a weak cell.
+  DataDescriptor(Handle<Name> key, int field_index,
+                 Handle<Object> wrapped_field_type,
                  PropertyAttributes attributes, Representation representation)
-      : Descriptor(key, field_type, attributes, DATA, representation,
-                   field_index) {}
+      : Descriptor(key, wrapped_field_type, attributes, DATA, representation,
+                   field_index) {
+    DCHECK(wrapped_field_type->IsSmi() || wrapped_field_type->IsWeakCell());
+  }
 };
 
 
index 416f586..0f49c3f 100644 (file)
@@ -2,12 +2,39 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This file relies on the fact that the following declaration has been made
-// in runtime.js:
-// var $Object = global.Object;
-// var $Array = global.Array;
+var $regexpExec;
+var $regexpExecNoTests;
+var $regexpLastMatchInfo;
+var $regexpLastMatchInfoOverride;
+var harmony_regexps = false;
+var harmony_unicode_regexps = false;
 
-var $RegExp = global.RegExp;
+(function() {
+
+%CheckIsBootstrapping();
+
+var GlobalRegExp = global.RegExp;
+var GlobalArray = global.Array;
+
+// Property of the builtins object for recording the result of the last
+// regexp match.  The property $regexpLastMatchInfo includes the matchIndices
+// array of the last successful regexp match (an array of start/end index
+// pairs for the match and all the captured substrings), the invariant is
+// that there are at least two capture indeces.  The array also contains
+// the subject string for the last successful match.
+$regexpLastMatchInfo = new InternalPackedArray(
+ 2,                 // REGEXP_NUMBER_OF_CAPTURES
+ "",                // Last subject.
+ UNDEFINED,         // Last input - settable with RegExpSetInput.
+ 0,                 // REGEXP_FIRST_CAPTURE + 0
+ 0                  // REGEXP_FIRST_CAPTURE + 1
+);
+
+// Override last match info with an array of actual substrings.
+// Used internally by replace regexp with function.
+// The array has the format of an "apply" argument for a replacement
+// function.
+$regexpLastMatchInfoOverride = null;
 
 // -------------------------------------------------------------------
 
@@ -44,7 +71,7 @@ function RegExpConstructor(pattern, flags) {
     if (IS_REGEXP(pattern) && IS_UNDEFINED(flags)) {
       return pattern;
     }
-    return new $RegExp(pattern, flags);
+    return new GlobalRegExp(pattern, flags);
   }
 }
 
@@ -60,7 +87,7 @@ function RegExpCompileJS(pattern, flags) {
   // RegExp.prototype.compile and in the constructor, where they are
   // the empty string.  For compatibility with JSC, we match their
   // behavior.
-  if (this == $RegExp.prototype) {
+  if (this == GlobalRegExp.prototype) {
     // We don't allow recompiling RegExp.prototype.
     throw MakeTypeError('incompatible_method_receiver',
                         ['RegExp.prototype.compile', this]);
@@ -74,8 +101,8 @@ function RegExpCompileJS(pattern, flags) {
 
 
 function DoRegExpExec(regexp, string, index) {
-  var result = %_RegExpExec(regexp, string, index, lastMatchInfo);
-  if (result !== null) lastMatchInfoOverride = null;
+  var result = %_RegExpExec(regexp, string, index, $regexpLastMatchInfo);
+  if (result !== null) $regexpLastMatchInfoOverride = null;
   return result;
 }
 
@@ -108,9 +135,9 @@ endmacro
 
 function RegExpExecNoTests(regexp, string, start) {
   // Must be called with RegExp, string and positive integer as arguments.
-  var matchInfo = %_RegExpExec(regexp, string, start, lastMatchInfo);
+  var matchInfo = %_RegExpExec(regexp, string, start, $regexpLastMatchInfo);
   if (matchInfo !== null) {
-    lastMatchInfoOverride = null;
+    $regexpLastMatchInfoOverride = null;
     RETURN_NEW_RESULT_FROM_MATCH_INFO(matchInfo, string);
   }
   regexp.lastIndex = 0;
@@ -118,7 +145,7 @@ function RegExpExecNoTests(regexp, string, start) {
 }
 
 
-function RegExpExec(string) {
+function RegExpExecJS(string) {
   if (!IS_REGEXP(this)) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['RegExp.prototype.exec', this]);
@@ -141,8 +168,8 @@ function RegExpExec(string) {
     i = 0;
   }
 
-  // matchIndices is either null or the lastMatchInfo array.
-  var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo);
+  // matchIndices is either null or the $regexpLastMatchInfo array.
+  var matchIndices = %_RegExpExec(this, string, i, $regexpLastMatchInfo);
 
   if (IS_NULL(matchIndices)) {
     this.lastIndex = 0;
@@ -150,9 +177,9 @@ function RegExpExec(string) {
   }
 
   // Successful match.
-  lastMatchInfoOverride = null;
+  $regexpLastMatchInfoOverride = null;
   if (updateLastIndex) {
-    this.lastIndex = lastMatchInfo[CAPTURE1];
+    this.lastIndex = $regexpLastMatchInfo[CAPTURE1];
   }
   RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string);
 }
@@ -184,14 +211,14 @@ function RegExpTest(string) {
       this.lastIndex = 0;
       return false;
     }
-    // matchIndices is either null or the lastMatchInfo array.
-    var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo);
+    // matchIndices is either null or the $regexpLastMatchInfo array.
+    var matchIndices = %_RegExpExec(this, string, i, $regexpLastMatchInfo);
     if (IS_NULL(matchIndices)) {
       this.lastIndex = 0;
       return false;
     }
-    lastMatchInfoOverride = null;
-    this.lastIndex = lastMatchInfo[CAPTURE1];
+    $regexpLastMatchInfoOverride = null;
+    this.lastIndex = $regexpLastMatchInfo[CAPTURE1];
     return true;
   } else {
     // Non-global, non-sticky regexp.
@@ -205,13 +232,13 @@ function RegExpTest(string) {
         %_StringCharCodeAt(regexp.source, 2) != 63) {  // '?'
       regexp = TrimRegExp(regexp);
     }
-    // matchIndices is either null or the lastMatchInfo array.
-    var matchIndices = %_RegExpExec(regexp, string, 0, lastMatchInfo);
+    // matchIndices is either null or the $regexpLastMatchInfo array.
+    var matchIndices = %_RegExpExec(regexp, string, 0, $regexpLastMatchInfo);
     if (IS_NULL(matchIndices)) {
       this.lastIndex = 0;
       return false;
     }
-    lastMatchInfoOverride = null;
+    $regexpLastMatchInfoOverride = null;
     return true;
   }
 }
@@ -220,9 +247,9 @@ function TrimRegExp(regexp) {
   if (!%_ObjectEquals(regexp_key, regexp)) {
     regexp_key = regexp;
     regexp_val =
-      new $RegExp(%_SubString(regexp.source, 2, regexp.source.length),
-                  (regexp.ignoreCase ? regexp.multiline ? "im" : "i"
-                                     : regexp.multiline ? "m" : ""));
+      new GlobalRegExp(%_SubString(regexp.source, 2, regexp.source.length),
+                       (regexp.ignoreCase ? regexp.multiline ? "im" : "i"
+                                          : regexp.multiline ? "m" : ""));
   }
   return regexp_val;
 }
@@ -248,30 +275,30 @@ function RegExpToString() {
 // on the captures array of the last successful match and the subject string
 // of the last successful match.
 function RegExpGetLastMatch() {
-  if (lastMatchInfoOverride !== null) {
-    return OVERRIDE_MATCH(lastMatchInfoOverride);
+  if ($regexpLastMatchInfoOverride !== null) {
+    return OVERRIDE_MATCH($regexpLastMatchInfoOverride);
   }
-  var regExpSubject = LAST_SUBJECT(lastMatchInfo);
+  var regExpSubject = LAST_SUBJECT($regexpLastMatchInfo);
   return %_SubString(regExpSubject,
-                     lastMatchInfo[CAPTURE0],
-                     lastMatchInfo[CAPTURE1]);
+                     $regexpLastMatchInfo[CAPTURE0],
+                     $regexpLastMatchInfo[CAPTURE1]);
 }
 
 
 function RegExpGetLastParen() {
-  if (lastMatchInfoOverride) {
-    var override = lastMatchInfoOverride;
+  if ($regexpLastMatchInfoOverride) {
+    var override = $regexpLastMatchInfoOverride;
     if (override.length <= 3) return '';
     return override[override.length - 3];
   }
-  var length = NUMBER_OF_CAPTURES(lastMatchInfo);
+  var length = NUMBER_OF_CAPTURES($regexpLastMatchInfo);
   if (length <= 2) return '';  // There were no captures.
   // We match the SpiderMonkey behavior: return the substring defined by the
   // last pair (after the first pair) of elements of the capture array even if
   // it is empty.
-  var regExpSubject = LAST_SUBJECT(lastMatchInfo);
-  var start = lastMatchInfo[CAPTURE(length - 2)];
-  var end = lastMatchInfo[CAPTURE(length - 1)];
+  var regExpSubject = LAST_SUBJECT($regexpLastMatchInfo);
+  var start = $regexpLastMatchInfo[CAPTURE(length - 2)];
+  var end = $regexpLastMatchInfo[CAPTURE(length - 1)];
   if (start != -1 && end != -1) {
     return %_SubString(regExpSubject, start, end);
   }
@@ -282,11 +309,11 @@ function RegExpGetLastParen() {
 function RegExpGetLeftContext() {
   var start_index;
   var subject;
-  if (!lastMatchInfoOverride) {
-    start_index = lastMatchInfo[CAPTURE0];
-    subject = LAST_SUBJECT(lastMatchInfo);
+  if (!$regexpLastMatchInfoOverride) {
+    start_index = $regexpLastMatchInfo[CAPTURE0];
+    subject = LAST_SUBJECT($regexpLastMatchInfo);
   } else {
-    var override = lastMatchInfoOverride;
+    var override = $regexpLastMatchInfoOverride;
     start_index = OVERRIDE_POS(override);
     subject = OVERRIDE_SUBJECT(override);
   }
@@ -297,11 +324,11 @@ function RegExpGetLeftContext() {
 function RegExpGetRightContext() {
   var start_index;
   var subject;
-  if (!lastMatchInfoOverride) {
-    start_index = lastMatchInfo[CAPTURE1];
-    subject = LAST_SUBJECT(lastMatchInfo);
+  if (!$regexpLastMatchInfoOverride) {
+    start_index = $regexpLastMatchInfo[CAPTURE1];
+    subject = LAST_SUBJECT($regexpLastMatchInfo);
   } else {
-    var override = lastMatchInfoOverride;
+    var override = $regexpLastMatchInfoOverride;
     subject = OVERRIDE_SUBJECT(override);
     var match = OVERRIDE_MATCH(override);
     start_index = OVERRIDE_POS(override) + match.length;
@@ -314,126 +341,106 @@ function RegExpGetRightContext() {
 // successful match, or ''.  The function RegExpMakeCaptureGetter will be
 // called with indices from 1 to 9.
 function RegExpMakeCaptureGetter(n) {
-  return function() {
-    if (lastMatchInfoOverride) {
-      if (n < lastMatchInfoOverride.length - 2) {
-        return OVERRIDE_CAPTURE(lastMatchInfoOverride, n);
+  return function foo() {
+    if ($regexpLastMatchInfoOverride) {
+      if (n < $regexpLastMatchInfoOverride.length - 2) {
+        return OVERRIDE_CAPTURE($regexpLastMatchInfoOverride, n);
       }
       return '';
     }
     var index = n * 2;
-    if (index >= NUMBER_OF_CAPTURES(lastMatchInfo)) return '';
-    var matchStart = lastMatchInfo[CAPTURE(index)];
-    var matchEnd = lastMatchInfo[CAPTURE(index + 1)];
+    if (index >= NUMBER_OF_CAPTURES($regexpLastMatchInfo)) return '';
+    var matchStart = $regexpLastMatchInfo[CAPTURE(index)];
+    var matchEnd = $regexpLastMatchInfo[CAPTURE(index + 1)];
     if (matchStart == -1 || matchEnd == -1) return '';
-    return %_SubString(LAST_SUBJECT(lastMatchInfo), matchStart, matchEnd);
+    return %_SubString(LAST_SUBJECT($regexpLastMatchInfo), matchStart, matchEnd);
   };
 }
 
-
-// Property of the builtins object for recording the result of the last
-// regexp match.  The property lastMatchInfo includes the matchIndices
-// array of the last successful regexp match (an array of start/end index
-// pairs for the match and all the captured substrings), the invariant is
-// that there are at least two capture indeces.  The array also contains
-// the subject string for the last successful match.
-var lastMatchInfo = new InternalPackedArray(
-    2,                 // REGEXP_NUMBER_OF_CAPTURES
-    "",                // Last subject.
-    UNDEFINED,         // Last input - settable with RegExpSetInput.
-    0,                 // REGEXP_FIRST_CAPTURE + 0
-    0                  // REGEXP_FIRST_CAPTURE + 1
-);
-
-// Override last match info with an array of actual substrings.
-// Used internally by replace regexp with function.
-// The array has the format of an "apply" argument for a replacement
-// function.
-var lastMatchInfoOverride = null;
-
 // -------------------------------------------------------------------
 
-function SetUpRegExp() {
-  %CheckIsBootstrapping();
-  %FunctionSetInstanceClassName($RegExp, 'RegExp');
-  %AddNamedProperty($RegExp.prototype, 'constructor', $RegExp, DONT_ENUM);
-  %SetCode($RegExp, RegExpConstructor);
-
-  InstallFunctions($RegExp.prototype, DONT_ENUM, $Array(
-    "exec", RegExpExec,
-    "test", RegExpTest,
-    "toString", RegExpToString,
-    "compile", RegExpCompileJS
-  ));
-
-  // The length of compile is 1 in SpiderMonkey.
-  %FunctionSetLength($RegExp.prototype.compile, 1);
-
-  // The properties `input` and `$_` are aliases for each other.  When this
-  // value is set the value it is set to is coerced to a string.
-  // Getter and setter for the input.
-  var RegExpGetInput = function() {
-    var regExpInput = LAST_INPUT(lastMatchInfo);
-    return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
-  };
-  var RegExpSetInput = function(string) {
-    LAST_INPUT(lastMatchInfo) = ToString(string);
-  };
-
-  %OptimizeObjectForAddingMultipleProperties($RegExp, 22);
-  %DefineAccessorPropertyUnchecked($RegExp, 'input', RegExpGetInput,
-                                   RegExpSetInput, DONT_DELETE);
-  %DefineAccessorPropertyUnchecked($RegExp, '$_', RegExpGetInput,
-                                   RegExpSetInput, DONT_ENUM | DONT_DELETE);
-
-  // The properties multiline and $* are aliases for each other.  When this
-  // value is set in SpiderMonkey, the value it is set to is coerced to a
-  // boolean.  We mimic that behavior with a slight difference: in SpiderMonkey
-  // the value of the expression 'RegExp.multiline = null' (for instance) is the
-  // boolean false (i.e., the value after coercion), while in V8 it is the value
-  // null (i.e., the value before coercion).
-
-  // Getter and setter for multiline.
-  var multiline = false;
-  var RegExpGetMultiline = function() { return multiline; };
-  var RegExpSetMultiline = function(flag) { multiline = flag ? true : false; };
-
-  %DefineAccessorPropertyUnchecked($RegExp, 'multiline', RegExpGetMultiline,
-                                   RegExpSetMultiline, DONT_DELETE);
-  %DefineAccessorPropertyUnchecked($RegExp, '$*', RegExpGetMultiline,
-                                   RegExpSetMultiline,
-                                   DONT_ENUM | DONT_DELETE);
-
-
-  var NoOpSetter = function(ignored) {};
-
-
-  // Static properties set by a successful match.
-  %DefineAccessorPropertyUnchecked($RegExp, 'lastMatch', RegExpGetLastMatch,
-                                   NoOpSetter, DONT_DELETE);
-  %DefineAccessorPropertyUnchecked($RegExp, '$&', RegExpGetLastMatch,
-                                   NoOpSetter, DONT_ENUM | DONT_DELETE);
-  %DefineAccessorPropertyUnchecked($RegExp, 'lastParen', RegExpGetLastParen,
-                                   NoOpSetter, DONT_DELETE);
-  %DefineAccessorPropertyUnchecked($RegExp, '$+', RegExpGetLastParen,
-                                   NoOpSetter, DONT_ENUM | DONT_DELETE);
-  %DefineAccessorPropertyUnchecked($RegExp, 'leftContext',
-                                   RegExpGetLeftContext, NoOpSetter,
+%FunctionSetInstanceClassName(GlobalRegExp, 'RegExp');
+%AddNamedProperty(
+    GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM);
+%SetCode(GlobalRegExp, RegExpConstructor);
+
+InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, GlobalArray(
+  "exec", RegExpExecJS,
+  "test", RegExpTest,
+  "toString", RegExpToString,
+  "compile", RegExpCompileJS
+));
+
+// The length of compile is 1 in SpiderMonkey.
+%FunctionSetLength(GlobalRegExp.prototype.compile, 1);
+
+// The properties `input` and `$_` are aliases for each other.  When this
+// value is set the value it is set to is coerced to a string.
+// Getter and setter for the input.
+var RegExpGetInput = function() {
+  var regExpInput = LAST_INPUT($regexpLastMatchInfo);
+  return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
+};
+var RegExpSetInput = function(string) {
+  LAST_INPUT($regexpLastMatchInfo) = ToString(string);
+};
+
+%OptimizeObjectForAddingMultipleProperties(GlobalRegExp, 22);
+%DefineAccessorPropertyUnchecked(GlobalRegExp, 'input', RegExpGetInput,
+                                 RegExpSetInput, DONT_DELETE);
+%DefineAccessorPropertyUnchecked(GlobalRegExp, '$_', RegExpGetInput,
+                                 RegExpSetInput, DONT_ENUM | DONT_DELETE);
+
+// The properties multiline and $* are aliases for each other.  When this
+// value is set in SpiderMonkey, the value it is set to is coerced to a
+// boolean.  We mimic that behavior with a slight difference: in SpiderMonkey
+// the value of the expression 'RegExp.multiline = null' (for instance) is the
+// boolean false (i.e., the value after coercion), while in V8 it is the value
+// null (i.e., the value before coercion).
+
+// Getter and setter for multiline.
+var multiline = false;
+var RegExpGetMultiline = function() { return multiline; };
+var RegExpSetMultiline = function(flag) { multiline = flag ? true : false; };
+
+%DefineAccessorPropertyUnchecked(GlobalRegExp, 'multiline', RegExpGetMultiline,
+                                 RegExpSetMultiline, DONT_DELETE);
+%DefineAccessorPropertyUnchecked(GlobalRegExp, '$*', RegExpGetMultiline,
+                                 RegExpSetMultiline,
+                                 DONT_ENUM | DONT_DELETE);
+
+
+var NoOpSetter = function(ignored) {};
+
+
+// Static properties set by a successful match.
+%DefineAccessorPropertyUnchecked(GlobalRegExp, 'lastMatch', RegExpGetLastMatch,
+                                 NoOpSetter, DONT_DELETE);
+%DefineAccessorPropertyUnchecked(GlobalRegExp, '$&', RegExpGetLastMatch,
+                                 NoOpSetter, DONT_ENUM | DONT_DELETE);
+%DefineAccessorPropertyUnchecked(GlobalRegExp, 'lastParen', RegExpGetLastParen,
+                                 NoOpSetter, DONT_DELETE);
+%DefineAccessorPropertyUnchecked(GlobalRegExp, '$+', RegExpGetLastParen,
+                                 NoOpSetter, DONT_ENUM | DONT_DELETE);
+%DefineAccessorPropertyUnchecked(GlobalRegExp, 'leftContext',
+                                 RegExpGetLeftContext, NoOpSetter,
+                                 DONT_DELETE);
+%DefineAccessorPropertyUnchecked(GlobalRegExp, '$`', RegExpGetLeftContext,
+                                 NoOpSetter, DONT_ENUM | DONT_DELETE);
+%DefineAccessorPropertyUnchecked(GlobalRegExp, 'rightContext',
+                                 RegExpGetRightContext, NoOpSetter,
+                                 DONT_DELETE);
+%DefineAccessorPropertyUnchecked(GlobalRegExp, "$'", RegExpGetRightContext,
+                                 NoOpSetter, DONT_ENUM | DONT_DELETE);
+
+for (var i = 1; i < 10; ++i) {
+  %DefineAccessorPropertyUnchecked(GlobalRegExp, '$' + i,
+                                   RegExpMakeCaptureGetter(i), NoOpSetter,
                                    DONT_DELETE);
-  %DefineAccessorPropertyUnchecked($RegExp, '$`', RegExpGetLeftContext,
-                                   NoOpSetter, DONT_ENUM | DONT_DELETE);
-  %DefineAccessorPropertyUnchecked($RegExp, 'rightContext',
-                                   RegExpGetRightContext, NoOpSetter,
-                                   DONT_DELETE);
-  %DefineAccessorPropertyUnchecked($RegExp, "$'", RegExpGetRightContext,
-                                   NoOpSetter, DONT_ENUM | DONT_DELETE);
-
-  for (var i = 1; i < 10; ++i) {
-    %DefineAccessorPropertyUnchecked($RegExp, '$' + i,
-                                     RegExpMakeCaptureGetter(i), NoOpSetter,
-                                     DONT_DELETE);
-  }
-  %ToFastProperties($RegExp);
 }
+%ToFastProperties(GlobalRegExp);
+
+$regexpExecNoTests = RegExpExecNoTests;
+$regexpExec = DoRegExpExec;
 
-SetUpRegExp();
+})();
index c81950e..9a5a870 100644 (file)
@@ -4,10 +4,9 @@
 
 #include "src/v8.h"
 
-#include "src/rewriter.h"
-
 #include "src/ast.h"
-#include "src/compiler.h"
+#include "src/parser.h"
+#include "src/rewriter.h"
 #include "src/scopes.h"
 
 namespace v8 {
@@ -222,7 +221,7 @@ EXPRESSION_NODE_LIST(DEF_VISIT)
 
 // Assumes code has been parsed.  Mutates the AST, so the AST should not
 // continue to be used in the case of failure.
-bool Rewriter::Rewrite(CompilationInfo* info) {
+bool Rewriter::Rewrite(ParseInfo* info) {
   FunctionLiteral* function = info->function();
   DCHECK(function != NULL);
   Scope* scope = function->scope();
index 0423802..b283a55 100644 (file)
@@ -8,7 +8,7 @@
 namespace v8 {
 namespace internal {
 
-class CompilationInfo;
+class ParseInfo;
 
 class Rewriter {
  public:
@@ -18,7 +18,7 @@ class Rewriter {
   //
   // Assumes code has been parsed and scopes have been analyzed.  Mutates the
   // AST, so the AST should not continue to be used in the case of failure.
-  static bool Rewrite(CompilationInfo* info);
+  static bool Rewrite(ParseInfo* info);
 };
 
 
index 7d82dfa..e4cb4ff 100644 (file)
@@ -418,7 +418,7 @@ function APPLY_PREPARE(args) {
   // that takes care of more eventualities.
   if (IS_ARRAY(args)) {
     length = args.length;
-    if (%_IsSmi(length) && length >= 0 && length < 0x800000 &&
+    if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength &&
         IS_SPEC_FUNCTION(this)) {
       return length;
     }
@@ -429,7 +429,7 @@ function APPLY_PREPARE(args) {
   // We can handle any number of apply arguments if the stack is
   // big enough, but sanity check the value to avoid overflow when
   // multiplying with pointer size.
-  if (length > 0x800000) {
+  if (length > kSafeArgumentsLength) {
     throw %MakeRangeError('stack_overflow', []);
   }
 
@@ -449,6 +449,93 @@ function APPLY_PREPARE(args) {
 }
 
 
+function REFLECT_APPLY_PREPARE(args) {
+  var length;
+  // First check whether length is a positive Smi and args is an
+  // array. This is the fast case. If this fails, we do the slow case
+  // that takes care of more eventualities.
+  if (IS_ARRAY(args)) {
+    length = args.length;
+    if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength &&
+        IS_SPEC_FUNCTION(this)) {
+      return length;
+    }
+  }
+
+  if (!IS_SPEC_FUNCTION(this)) {
+    throw %MakeTypeError('called_non_callable', [ %ToString(this) ]);
+  }
+
+  if (!IS_SPEC_OBJECT(args)) {
+    throw %MakeTypeError('reflect_apply_wrong_args', [ ]);
+  }
+
+  length = %ToLength(args.length);
+
+  // We can handle any number of apply arguments if the stack is
+  // big enough, but sanity check the value to avoid overflow when
+  // multiplying with pointer size.
+  if (length > kSafeArgumentsLength) {
+    throw %MakeRangeError('stack_overflow', []);
+  }
+
+  // Return the length which is the number of arguments to copy to the
+  // stack. It is guaranteed to be a small integer at this point.
+  return length;
+}
+
+
+function REFLECT_CONSTRUCT_PREPARE(args, newTarget) {
+  var length;
+  var ctorOk = IS_SPEC_FUNCTION(this) && %IsConstructor(this);
+  var newTargetOk = IS_SPEC_FUNCTION(newTarget) && %IsConstructor(newTarget);
+
+  // First check whether length is a positive Smi and args is an
+  // array. This is the fast case. If this fails, we do the slow case
+  // that takes care of more eventualities.
+  if (IS_ARRAY(args)) {
+    length = args.length;
+    if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength &&
+        ctorOk && newTargetOk) {
+      return length;
+    }
+  }
+
+  if (!ctorOk) {
+    if (!IS_SPEC_FUNCTION(this)) {
+      throw %MakeTypeError('called_non_callable', [ %ToString(this) ]);
+    } else {
+      throw %MakeTypeError('not_constructor', [ %ToString(this) ]);
+    }
+  }
+
+  if (!newTargetOk) {
+    if (!IS_SPEC_FUNCTION(newTarget)) {
+      throw %MakeTypeError('called_non_callable', [ %ToString(newTarget) ]);
+    } else {
+      throw %MakeTypeError('not_constructor', [ %ToString(newTarget) ]);
+    }
+  }
+
+  if (!IS_SPEC_OBJECT(args)) {
+    throw %MakeTypeError('reflect_construct_wrong_args', [ ]);
+  }
+
+  length = %ToLength(args.length);
+
+  // We can handle any number of apply arguments if the stack is
+  // big enough, but sanity check the value to avoid overflow when
+  // multiplying with pointer size.
+  if (length > kSafeArgumentsLength) {
+    throw %MakeRangeError('stack_overflow', []);
+  }
+
+  // Return the length which is the number of arguments to copy to the
+  // stack. It is guaranteed to be a small integer at this point.
+  return length;
+}
+
+
 function STACK_OVERFLOW(length) {
   throw %MakeRangeError('stack_overflow', []);
 }
@@ -694,3 +781,14 @@ function ToPositiveInteger(x, rangeErrorName) {
 // that is cloned when running the code.  It is essential that the
 // boilerplate gets the right prototype.
 %FunctionSetPrototype($Array, new $Array(0));
+
+
+/* -----------------------------------------------
+   - - -   J a v a S c r i p t   S t u b s   - - -
+   -----------------------------------------------
+*/
+
+function STRING_LENGTH_STUB(name) {
+  var receiver = this;  // implicit first parameter
+  return %_StringGetLength(%_JSValueGetValue(receiver));
+}
index 6814385..010c186 100644 (file)
@@ -444,8 +444,8 @@ static bool IterateElementsSlow(Isolate* isolate, Handle<JSObject> receiver,
   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) {
+    if (!maybe.IsJust()) return false;
+    if (maybe.FromJust()) {
       Handle<Object> element_value;
       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
           isolate, element_value,
@@ -511,8 +511,8 @@ static bool IterateElements(Isolate* isolate, Handle<JSObject> receiver,
           visitor->visit(j, element_value);
         } else {
           Maybe<bool> maybe = JSReceiver::HasElement(receiver, j);
-          if (!maybe.has_value) return false;
-          if (maybe.value) {
+          if (!maybe.IsJust()) return false;
+          if (maybe.FromJust()) {
             // Call GetElement on receiver, not its prototype, or getters won't
             // have the correct receiver.
             ASSIGN_RETURN_ON_EXCEPTION_VALUE(
@@ -547,8 +547,8 @@ static bool IterateElements(Isolate* isolate, Handle<JSObject> receiver,
           visitor->visit(j, element_value);
         } else {
           Maybe<bool> maybe = JSReceiver::HasElement(receiver, j);
-          if (!maybe.has_value) return false;
-          if (maybe.value) {
+          if (!maybe.IsJust()) return false;
+          if (maybe.FromJust()) {
             // Call GetElement on receiver, not its prototype, or getters won't
             // have the correct receiver.
             Handle<Object> element_value;
@@ -1228,7 +1228,8 @@ RUNTIME_FUNCTION(Runtime_HasComplexElements) {
       return isolate->heap()->true_value();
     }
     if (!current->HasDictionaryElements()) continue;
-    if (current->element_dictionary()->HasComplexElements()) {
+    if (current->element_dictionary()
+            ->HasComplexElements<DictionaryEntryType::kObjects>()) {
       return isolate->heap()->true_value();
     }
   }
@@ -1322,7 +1323,7 @@ RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ForInNext) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_IsArray) {
+RUNTIME_FUNCTION(Runtime_IsArray) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
   CONVERT_ARG_CHECKED(Object, obj, 0);
@@ -1330,23 +1331,26 @@ RUNTIME_FUNCTION(RuntimeReference_IsArray) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_HasCachedArrayIndex) {
+RUNTIME_FUNCTION(Runtime_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(Runtime_GetCachedArrayIndex) {
+  // This can never be reached, because Runtime_HasCachedArrayIndex always
+  // returns false.
+  UNIMPLEMENTED();
+  return nullptr;
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_FastOneByteArrayJoin) {
+RUNTIME_FUNCTION(Runtime_FastOneByteArrayJoin) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 2);
+  // Returning undefined means that this fast path fails and one has to resort
+  // to a slow path.
   return isolate->heap()->undefined_value();
 }
 }
index e88a76a..67d7e69 100644 (file)
@@ -56,6 +56,30 @@ RUNTIME_FUNCTION(Runtime_ThrowArrayNotSubclassableError) {
 }
 
 
+static Object* ThrowStaticPrototypeError(Isolate* isolate) {
+  THROW_NEW_ERROR_RETURN_FAILURE(
+      isolate, NewTypeError("static_prototype", HandleVector<Object>(NULL, 0)));
+}
+
+
+RUNTIME_FUNCTION(Runtime_ThrowStaticPrototypeError) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+  return ThrowStaticPrototypeError(isolate);
+}
+
+
+RUNTIME_FUNCTION(Runtime_ThrowIfStaticPrototype) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 0);
+  if (Name::Equals(name, isolate->factory()->prototype_string())) {
+    return ThrowStaticPrototypeError(isolate);
+  }
+  return *name;
+}
+
+
 RUNTIME_FUNCTION(Runtime_ToMethod) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 2);
@@ -117,7 +141,7 @@ RUNTIME_FUNCTION(Runtime_DefineClass) {
   Handle<Map> map =
       isolate->factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
   map->SetPrototype(prototype_parent);
-  map->set_constructor(*constructor);
+  map->SetConstructor(*constructor);
   Handle<JSObject> prototype = isolate->factory()->NewJSObjectFromMap(map);
 
   Handle<String> name_string = name->IsString()
@@ -232,9 +256,8 @@ RUNTIME_FUNCTION(Runtime_ClassGetSourceCode) {
 
 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);
+  if (home_object->IsAccessCheckNeeded() && !isolate->MayAccess(home_object)) {
+    isolate->ReportFailedAccessCheck(home_object);
     RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
   }
 
@@ -252,9 +275,8 @@ static Object* LoadFromSuper(Isolate* isolate, Handle<Object> receiver,
 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);
+  if (home_object->IsAccessCheckNeeded() && !isolate->MayAccess(home_object)) {
+    isolate->ReportFailedAccessCheck(home_object);
     RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
   }
 
@@ -306,9 +328,8 @@ RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) {
 static Object* StoreToSuper(Isolate* isolate, Handle<JSObject> home_object,
                             Handle<Object> receiver, Handle<Name> name,
                             Handle<Object> value, LanguageMode language_mode) {
-  if (home_object->IsAccessCheckNeeded() &&
-      !isolate->MayNamedAccess(home_object, name, v8::ACCESS_SET)) {
-    isolate->ReportFailedAccessCheck(home_object, v8::ACCESS_SET);
+  if (home_object->IsAccessCheckNeeded() && !isolate->MayAccess(home_object)) {
+    isolate->ReportFailedAccessCheck(home_object);
     RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
   }
 
@@ -331,9 +352,8 @@ static Object* StoreElementToSuper(Isolate* isolate,
                                    Handle<Object> receiver, uint32_t index,
                                    Handle<Object> value,
                                    LanguageMode language_mode) {
-  if (home_object->IsAccessCheckNeeded() &&
-      !isolate->MayIndexedAccess(home_object, index, v8::ACCESS_SET)) {
-    isolate->ReportFailedAccessCheck(home_object, v8::ACCESS_SET);
+  if (home_object->IsAccessCheckNeeded() && !isolate->MayAccess(home_object)) {
+    isolate->ReportFailedAccessCheck(home_object);
     RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
   }
 
@@ -433,8 +453,8 @@ RUNTIME_FUNCTION(Runtime_HandleStepInForDerivedConstructors) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_DefaultConstructorCallSuper) {
-  UNREACHABLE();
+RUNTIME_FUNCTION(Runtime_DefaultConstructorCallSuper) {
+  UNIMPLEMENTED();
   return nullptr;
 }
 }
index 0958da1..52fe1e7 100644 (file)
@@ -47,7 +47,6 @@ RUNTIME_FUNCTION(Runtime_CompileOptimized) {
   DCHECK(args.length() == 2);
   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
   CONVERT_BOOLEAN_ARG_CHECKED(concurrent, 1);
-  DCHECK(isolate->use_crankshaft());
 
   Compiler::ConcurrencyMode mode =
       concurrent ? Compiler::CONCURRENT : Compiler::NOT_CONCURRENT;
index 4caf27d..844ca25 100644 (file)
@@ -152,6 +152,7 @@ RUNTIME_FUNCTION(Runtime_DateToUTC) {
 RUNTIME_FUNCTION(Runtime_DateCacheVersion) {
   HandleScope hs(isolate);
   DCHECK(args.length() == 0);
+  if (isolate->serializer_enabled()) return isolate->heap()->undefined_value();
   if (!isolate->eternal_handles()->Exists(EternalHandles::DATE_CACHE_VERSION)) {
     Handle<FixedArray> date_cache_version =
         isolate->factory()->NewFixedArray(1, TENURED);
@@ -170,7 +171,7 @@ RUNTIME_FUNCTION(Runtime_DateCacheVersion) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_DateField) {
+RUNTIME_FUNCTION(Runtime_DateField) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 2);
   CONVERT_ARG_CHECKED(Object, obj, 0);
index 563e808..b4e1fe9 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "src/accessors.h"
 #include "src/arguments.h"
+#include "src/compiler.h"
 #include "src/debug.h"
 #include "src/deoptimizer.h"
 #include "src/isolate-inl.h"
@@ -53,7 +54,7 @@ RUNTIME_FUNCTION(Runtime_SetDebugEventListener) {
 }
 
 
-RUNTIME_FUNCTION(Runtime_Break) {
+RUNTIME_FUNCTION(Runtime_ScheduleBreak) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 0);
   isolate->stack_guard()->RequestDebugBreak();
@@ -71,6 +72,7 @@ static Handle<Object> DebugGetProperty(LookupIterator* it,
       case LookupIterator::ACCESS_CHECK:
         // Ignore access checks.
         break;
+      case LookupIterator::INTEGER_INDEXED_EXOTIC:
       case LookupIterator::INTERCEPTOR:
       case LookupIterator::JSPROXY:
         return it->isolate()->factory()->undefined_value();
@@ -136,7 +138,7 @@ RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) {
         isolate, element_or_char,
         Runtime::GetElementOrCharAt(isolate, obj, index));
     details->set(0, *element_or_char);
-    details->set(1, PropertyDetails(NONE, DATA, 0).AsSmi());
+    details->set(1, PropertyDetails::Empty().AsSmi());
     return *isolate->factory()->NewJSArrayWithElements(details);
   }
 
@@ -158,7 +160,7 @@ RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) {
   details->set(0, *value);
   // TODO(verwaest): Get rid of this random way of handling interceptors.
   PropertyDetails d = it.state() == LookupIterator::INTERCEPTOR
-                          ? PropertyDetails(NONE, DATA, 0)
+                          ? PropertyDetails::Empty()
                           : it.property_details();
   details->set(1, d.AsSmi());
   details->set(
@@ -913,8 +915,8 @@ static bool SetLocalVariableValue(Isolate* isolate, JavaScriptFrame* frame,
         Handle<JSObject> ext(JSObject::cast(function_context->extension()));
 
         Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
-        DCHECK(maybe.has_value);
-        if (maybe.value) {
+        DCHECK(maybe.IsJust());
+        if (maybe.FromJust()) {
           // We don't expect this to do anything except replacing
           // property value.
           Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
@@ -996,8 +998,8 @@ static bool SetClosureVariableValue(Isolate* isolate, Handle<Context> context,
   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) {
+    DCHECK(maybe.IsJust());
+    if (maybe.FromJust()) {
       // We don't expect this to do anything except replacing property value.
       Runtime::DefineObjectProperty(ext, variable_name, new_value, NONE)
           .Assert();
@@ -1164,18 +1166,19 @@ class ScopeIterator {
     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
+      // 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);
+      Address call_pc = frame->pc() - 1;
+
+      // Find the break point where execution has stopped.
+      BreakLocation location =
+          BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc);
 
       // 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();
+      ignore_nested_scopes = location.IsExit();
     }
 
     if (ignore_nested_scopes) {
@@ -1197,16 +1200,17 @@ class ScopeIterator {
 
       // Check whether we are in global, eval or function code.
       Handle<ScopeInfo> scope_info(shared_info->scope_info());
+      Zone zone;
       if (scope_info->scope_type() != FUNCTION_SCOPE &&
           scope_info->scope_type() != ARROW_SCOPE) {
         // Global or eval code.
-        CompilationInfoWithZone info(script);
+        ParseInfo info(&zone, script);
         if (scope_info->scope_type() == SCRIPT_SCOPE) {
-          info.MarkAsGlobal();
+          info.set_global();
         } else {
           DCHECK(scope_info->scope_type() == EVAL_SCOPE);
-          info.MarkAsEval();
-          info.SetContext(Handle<Context>(function_->context()));
+          info.set_eval();
+          info.set_context(Handle<Context>(function_->context()));
         }
         if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) {
           scope = info.function()->scope();
@@ -1214,7 +1218,7 @@ class ScopeIterator {
         RetrieveScopeChain(scope, shared_info);
       } else {
         // Function code
-        CompilationInfoWithZone info(shared_info);
+        ParseInfo info(&zone, function_);
         if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) {
           scope = info.function()->scope();
         }
@@ -1548,9 +1552,11 @@ RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
   JavaScriptFrameIterator frame_it(isolate, id);
   RUNTIME_ASSERT(!frame_it.done());
 
-  JavaScriptFrame* frame = frame_it.frame();
+  List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
+  frame_it.frame()->Summarize(&frames);
+  FrameSummary summary = frames.first();
 
-  Handle<JSFunction> fun = Handle<JSFunction>(frame->function());
+  Handle<JSFunction> fun = Handle<JSFunction>(summary.function());
   Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(fun->shared());
 
   if (!isolate->debug()->EnsureDebugInfo(shared, fun)) {
@@ -1559,18 +1565,19 @@ RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
 
   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);
+  // Find range of break points starting from the break point where execution
+  // has stopped.
+  Address call_pc = summary.pc() - 1;
+  List<BreakLocation> locations;
+  BreakLocation::FromAddressSameStatement(debug_info, ALL_BREAK_LOCATIONS,
+                                          call_pc, &locations);
 
-  break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
-  int current_statement_pos = break_location_iterator.statement_position();
+  Handle<JSArray> array = isolate->factory()->NewJSArray(locations.length());
 
-  while (!break_location_iterator.Done()) {
+  int index = 0;
+  for (BreakLocation location : locations) {
     bool accept;
-    if (break_location_iterator.pc() > frame->pc()) {
+    if (location.pc() > summary.pc()) {
       accept = true;
     } else {
       StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
@@ -1587,20 +1594,15 @@ RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
       }
     }
     if (accept) {
-      if (break_location_iterator.IsStepInLocation(isolate)) {
-        Smi* position_value = Smi::FromInt(break_location_iterator.position());
+      if (location.IsStepInLocation()) {
+        Smi* position_value = Smi::FromInt(location.position());
         RETURN_FAILURE_ON_EXCEPTION(
             isolate, JSObject::SetElement(
-                         array, len, Handle<Object>(position_value, isolate),
+                         array, index, Handle<Object>(position_value, isolate),
                          NONE, SLOPPY));
-        len++;
+        index++;
       }
     }
-    // Advance iterator.
-    break_location_iterator.Next();
-    if (current_statement_pos != break_location_iterator.statement_position()) {
-      break;
-    }
   }
   return *array;
 }
@@ -2113,8 +2115,8 @@ MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeArgumentsObject(
   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;
+  if (!maybe.IsJust()) return MaybeHandle<JSObject>();
+  if (maybe.FromJust()) return target;
 
   // FunctionGetArguments can't throw an exception.
   Handle<JSObject> arguments =
@@ -2204,9 +2206,6 @@ RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
   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.
@@ -2216,16 +2215,29 @@ RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
   isolate->set_context(*(save->context()));
 
   // Materialize stack locals and the arguments object.
-  Handle<JSObject> materialized = NewJSObjectWithNullProto(isolate);
+  Handle<JSObject> materialized;
+  Handle<JSFunction> function;
+  Handle<SharedFunctionInfo> outer_info;
+  Handle<Context> eval_context;
 
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, materialized,
-      MaterializeStackLocalsWithFrameInspector(isolate, materialized, function,
-                                               &frame_inspector));
+  // We need to limit the lifetime of the FrameInspector because evaluation can
+  // call arbitrary code and only one FrameInspector can be active at a time.
+  {
+    FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
+    materialized = NewJSObjectWithNullProto(isolate);
+    function = handle(JSFunction::cast(frame_inspector.GetFunction()));
+    outer_info = handle(function->shared());
+    eval_context = handle(Context::cast(frame_inspector.GetContext()));
 
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, materialized,
-      MaterializeArgumentsObject(isolate, materialized, function));
+    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]
@@ -2242,7 +2254,6 @@ RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
   // 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);
@@ -2372,7 +2383,7 @@ static int DebugReferencedBy(HeapIterator* iterator, JSObject* target,
       // checked in the context of functions using them.
       JSObject* obj = JSObject::cast(heap_obj);
       if (obj->IsJSContextExtensionObject() ||
-          obj->map()->constructor() == arguments_function) {
+          obj->map()->GetConstructor() == arguments_function) {
         continue;
       }
 
@@ -2435,7 +2446,7 @@ RUNTIME_FUNCTION(Runtime_DebugReferencedBy) {
 
   // Get the constructor function for context extension and arguments array.
   Handle<JSFunction> arguments_function(
-      JSFunction::cast(isolate->sloppy_arguments_map()->constructor()));
+      JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor()));
 
   // Get the number of referencing objects.
   int count;
@@ -2483,7 +2494,7 @@ static int DebugConstructedBy(HeapIterator* iterator, JSFunction* constructor,
     // Only look at all JSObjects.
     if (heap_obj->IsJSObject()) {
       JSObject* obj = JSObject::cast(heap_obj);
-      if (obj->map()->constructor() == constructor) {
+      if (obj->map()->GetConstructor() == constructor) {
         // Valid reference found add to instance array if supplied an update
         // count.
         if (instances != NULL && count < instances_size) {
@@ -2571,46 +2582,21 @@ RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) {
 }
 
 
-RUNTIME_FUNCTION(Runtime_DebugDisassembleFunction) {
-  HandleScope scope(isolate);
-#ifdef DEBUG
+RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
+  SealHandleScope shs(isolate);
   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();
+  CONVERT_ARG_CHECKED(JSFunction, f, 0);
+  return f->shared()->inferred_name();
 }
 
 
-RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
-  SealHandleScope shs(isolate);
+RUNTIME_FUNCTION(Runtime_FunctionGetDebugName) {
+  HandleScope scope(isolate);
   DCHECK(args.length() == 1);
 
-  CONVERT_ARG_CHECKED(JSFunction, f, 0);
-  return f->shared()->inferred_name();
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
+  return *JSFunction::GetDebugName(f);
 }
 
 
@@ -2656,21 +2642,15 @@ RUNTIME_FUNCTION(Runtime_GetFunctionCodePositionFromSource) {
 // to have a stack with C++ frame in the middle.
 RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) {
   HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
+  DCHECK(args.length() == 1);
   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);
-  }
+  DebugScope debug_scope(isolate->debug());
   Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Execution::Call(isolate, function, handle(function->global_proxy()), 0,
+                      NULL));
   return *result;
 }
 
@@ -2739,7 +2719,7 @@ RUNTIME_FUNCTION(Runtime_GetScript) {
 }
 
 
-// Check whether debugger and is about to step into the callback that is passed
+// Check whether debugger 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);
@@ -2749,9 +2729,12 @@ RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) {
     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());
+  // We do not step into the callback if it's a builtin other than a bound,
+  // or not even a function.
+  return isolate->heap()->ToBoolean(
+      callback->IsJSFunction() &&
+      (!JSFunction::cast(callback)->IsBuiltin() ||
+       JSFunction::cast(callback)->shared()->bound()));
 }
 
 
@@ -2776,16 +2759,17 @@ RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) {
   // 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);
+  debug->FloodWithOneShotGeneric(fun);
   return isolate->heap()->undefined_value();
 }
 
 
 RUNTIME_FUNCTION(Runtime_DebugPushPromise) {
-  DCHECK(args.length() == 1);
+  DCHECK(args.length() == 2);
   HandleScope scope(isolate);
   CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
-  isolate->PushPromise(promise);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 1);
+  isolate->PushPromise(promise, function);
   return isolate->heap()->undefined_value();
 }
 
@@ -2816,13 +2800,13 @@ RUNTIME_FUNCTION(Runtime_DebugAsyncTaskEvent) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_DebugIsActive) {
+RUNTIME_FUNCTION(Runtime_DebugIsActive) {
   SealHandleScope shs(isolate);
   return Smi::FromInt(isolate->debug()->is_active());
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_DebugBreakInOptimizedCode) {
+RUNTIME_FUNCTION(Runtime_DebugBreakInOptimizedCode) {
   UNIMPLEMENTED();
   return NULL;
 }
index 5d49b23..c211e18 100644 (file)
@@ -7,6 +7,7 @@
 #include "src/accessors.h"
 #include "src/arguments.h"
 #include "src/compiler.h"
+#include "src/cpu-profiler.h"
 #include "src/deoptimizer.h"
 #include "src/frames.h"
 #include "src/runtime/runtime-utils.h"
@@ -294,10 +295,6 @@ RUNTIME_FUNCTION(Runtime_SetCode) {
   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);
 
@@ -629,13 +626,13 @@ RUNTIME_FUNCTION(Runtime_GetConstructorDelegate) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_CallFunction) {
+RUNTIME_FUNCTION(Runtime_CallFunction) {
   SealHandleScope shs(isolate);
   return __RT_impl_Runtime_Call(args, isolate);
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_IsConstructCall) {
+RUNTIME_FUNCTION(Runtime_IsConstructCall) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 0);
   JavaScriptFrameIterator it(isolate);
@@ -644,7 +641,7 @@ RUNTIME_FUNCTION(RuntimeReference_IsConstructCall) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_IsFunction) {
+RUNTIME_FUNCTION(Runtime_IsFunction) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
   CONVERT_ARG_CHECKED(Object, obj, 0);
index ff07acd..d8b0844 100644 (file)
@@ -31,7 +31,6 @@ RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) {
   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;
 }
@@ -39,7 +38,7 @@ RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) {
 
 RUNTIME_FUNCTION(Runtime_SuspendJSGeneratorObject) {
   HandleScope handle_scope(isolate);
-  DCHECK(args.length() == 1);
+  DCHECK(args.length() == 1 || args.length() == 2);
   CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0);
 
   JavaScriptFrameIterator stack_iterator(isolate);
@@ -52,28 +51,34 @@ RUNTIME_FUNCTION(Runtime_SuspendJSGeneratorObject) {
   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.
+  // value of the yield expression, and the arguments to this runtime call.
   // Neither of those should be saved.
   int operands_count = frame->ComputeOperandsCount();
-  DCHECK_GE(operands_count, 2);
-  operands_count -= 2;
+  DCHECK_GE(operands_count, 1 + args.length());
+  operands_count -= 1 + args.length();
+
+  // Second argument indicates that we need to patch the handler table because
+  // a delegating yield introduced a try-catch statement at expression level,
+  // hence the operand count was off when we statically computed it.
+  // TODO(mstarzinger): This special case disappears with do-expressions.
+  if (args.length() == 2) {
+    CONVERT_SMI_ARG_CHECKED(handler_index, 1);
+    Handle<Code> code(frame->unchecked_code());
+    Handle<HandlerTable> table(HandlerTable::cast(code->handler_table()));
+    int handler_depth = operands_count - TryBlockConstant::kElementCount;
+    table->SetRangeDepth(handler_index, handler_depth);
+  }
 
   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);
+    frame->SaveOperandStack(*operand_stack);
     generator_object->set_operand_stack(*operand_stack);
-    generator_object->set_stack_handler_index(stack_handler_index);
   }
 
   return isolate->heap()->undefined_value();
@@ -115,10 +120,8 @@ RUNTIME_FUNCTION(Runtime_ResumeJSGeneratorObject) {
   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());
+    frame->RestoreOperandStack(operand_stack);
     generator_object->set_operand_stack(isolate->heap()->empty_fixed_array());
-    generator_object->set_stack_handler_index(-1);
   }
 
   JSGeneratorObject::ResumeMode resume_mode =
@@ -213,13 +216,13 @@ RUNTIME_FUNCTION(Runtime_FunctionIsGenerator) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_GeneratorNext) {
+RUNTIME_FUNCTION(Runtime_GeneratorNext) {
   UNREACHABLE();  // Optimization disabled in SetUpGenerators().
   return NULL;
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_GeneratorThrow) {
+RUNTIME_FUNCTION(Runtime_GeneratorThrow) {
   UNREACHABLE();  // Optimization disabled in SetUpGenerators().
   return NULL;
 }
index 50b6192..973c204 100644 (file)
@@ -26,7 +26,6 @@ RUNTIME_FUNCTION(Runtime_CheckIsBootstrapping) {
 RUNTIME_FUNCTION(Runtime_Throw) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 1);
-
   return isolate->Throw(args[0]);
 }
 
@@ -34,11 +33,17 @@ RUNTIME_FUNCTION(Runtime_Throw) {
 RUNTIME_FUNCTION(Runtime_ReThrow) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 1);
-
   return isolate->ReThrow(args[0]);
 }
 
 
+RUNTIME_FUNCTION(Runtime_FindExceptionHandler) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  return isolate->FindHandler();
+}
+
+
 RUNTIME_FUNCTION(Runtime_PromoteScheduledException) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 0);
@@ -55,6 +60,16 @@ RUNTIME_FUNCTION(Runtime_ThrowReferenceError) {
 }
 
 
+RUNTIME_FUNCTION(Runtime_ThrowIteratorResultNotAnObject) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
+  THROW_NEW_ERROR_RETURN_FAILURE(
+      isolate,
+      NewTypeError("iterator_result_not_an_object", HandleVector(&value, 1)));
+}
+
+
 RUNTIME_FUNCTION(Runtime_PromiseRejectEvent) {
   DCHECK(args.length() == 3);
   HandleScope scope(isolate);
@@ -164,29 +179,21 @@ RUNTIME_FUNCTION(Runtime_RenderCallSite) {
   if (location.start_pos() == -1) return isolate->heap()->empty_string();
 
   Zone zone;
-  if (location.function()->shared()->is_function()) {
-    CompilationInfo info(location.function(), &zone);
-    if (!Parser::ParseStatic(&info)) {
-      isolate->clear_pending_exception();
-      return isolate->heap()->empty_string();
-    }
-    CallPrinter printer(isolate, &zone);
-    const char* string = printer.Print(info.function(), location.start_pos());
-    return *isolate->factory()->NewStringFromAsciiChecked(string);
-  }
+  SmartPointer<ParseInfo> info(location.function()->shared()->is_function()
+                                   ? new ParseInfo(&zone, location.function())
+                                   : new ParseInfo(&zone, location.script()));
 
-  CompilationInfo info(location.script(), &zone);
-  if (!Parser::ParseStatic(&info)) {
+  if (!Parser::ParseStatic(info.get())) {
     isolate->clear_pending_exception();
     return isolate->heap()->empty_string();
   }
   CallPrinter printer(isolate, &zone);
-  const char* string = printer.Print(info.function(), location.start_pos());
+  const char* string = printer.Print(info->function(), location.start_pos());
   return *isolate->factory()->NewStringFromAsciiChecked(string);
 }
 
 
-RUNTIME_FUNCTION(Runtime_GetFromCache) {
+RUNTIME_FUNCTION(Runtime_GetFromCacheRT) {
   SealHandleScope shs(isolate);
   // This is only called from codegen, so checks might be more lax.
   CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
@@ -304,12 +311,24 @@ RUNTIME_FUNCTION(Runtime_IS_VAR) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_GetFromCache) {
+RUNTIME_FUNCTION(Runtime_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);
+  return __RT_impl_Runtime_GetFromCacheRT(args, isolate);
+}
+
+
+RUNTIME_FUNCTION(Runtime_IncrementStatsCounter) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(String, name, 0);
+
+  if (FLAG_native_code_counters) {
+    StatsCounter(isolate, name->ToCString().get()).Increment();
+  }
+  return isolate->heap()->undefined_value();
 }
 }
 }  // namespace v8::internal
index 1ea9c81..76226d6 100644 (file)
@@ -42,14 +42,7 @@ 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));
+  Handle<Context> context = isolate->native_context();
 
   // 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
@@ -146,8 +139,7 @@ MaybeHandle<Object> Runtime::CreateArrayLiteralBoilerplate(
     Isolate* isolate, Handle<FixedArray> literals,
     Handle<FixedArray> elements) {
   // Create the JSArray.
-  Handle<JSFunction> constructor(
-      JSFunction::NativeContextFromLiterals(*literals)->array_function());
+  Handle<JSFunction> constructor = isolate->array_function();
 
   PretenureFlag pretenure_flag =
       isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
index b453d15..e4c644e 100644 (file)
@@ -234,8 +234,9 @@ RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) {
   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();
+    Handle<Object> element;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, element, Object::GetElement(isolate, shared_array, i));
     RUNTIME_ASSERT(
         element->IsJSValue() &&
         Handle<JSValue>::cast(element)->value()->IsSharedFunctionInfo());
index 68dfa49..2941b58 100644 (file)
@@ -34,9 +34,10 @@ 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));
+  uint64_t unsigned64 = double_to_uint64(x);
+  uint32_t unsigned32 = static_cast<uint32_t>(unsigned64 >> 32);
+  int32_t signed32 = bit_cast<int32_t, uint32_t>(unsigned32);
+  return *isolate->factory()->NewNumber(signed32);
 }
 
 
@@ -44,8 +45,10 @@ 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));
+  uint64_t unsigned64 = double_to_uint64(x);
+  uint32_t unsigned32 = static_cast<uint32_t>(unsigned64);
+  int32_t signed32 = bit_cast<int32_t, uint32_t>(unsigned32);
+  return *isolate->factory()->NewNumber(signed32);
 }
 
 
@@ -109,7 +112,18 @@ RUNTIME_FUNCTION(Runtime_MathExpRT) {
 }
 
 
-RUNTIME_FUNCTION(Runtime_MathFloorRT) {
+RUNTIME_FUNCTION(Runtime_MathClz32) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  isolate->counters()->math_clz32()->Increment();
+
+  CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
+  return *isolate->factory()->NewNumberFromUint(
+      base::bits::CountLeadingZeros32(x));
+}
+
+
+RUNTIME_FUNCTION(Runtime_MathFloor) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 1);
   isolate->counters()->math_floor()->Increment();
@@ -204,7 +218,7 @@ RUNTIME_FUNCTION(Runtime_RoundNumber) {
 }
 
 
-RUNTIME_FUNCTION(Runtime_MathSqrtRT) {
+RUNTIME_FUNCTION(Runtime_MathSqrt) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 1);
   isolate->counters()->math_sqrt()->Increment();
@@ -224,13 +238,13 @@ RUNTIME_FUNCTION(Runtime_MathFround) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_MathPow) {
+RUNTIME_FUNCTION(Runtime_MathPow) {
   SealHandleScope shs(isolate);
   return __RT_impl_Runtime_MathPowSlow(args, isolate);
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_IsMinusZero) {
+RUNTIME_FUNCTION(Runtime_IsMinusZero) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
   CONVERT_ARG_CHECKED(Object, obj, 0);
index a7a15e4..36ca87b 100644 (file)
@@ -572,13 +572,13 @@ RUNTIME_FUNCTION(Runtime_MaxSmi) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_NumberToString) {
+RUNTIME_FUNCTION(Runtime_NumberToString) {
   SealHandleScope shs(isolate);
   return __RT_impl_Runtime_NumberToStringRT(args, isolate);
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_IsSmi) {
+RUNTIME_FUNCTION(Runtime_IsSmi) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
   CONVERT_ARG_CHECKED(Object, obj, 0);
@@ -586,7 +586,7 @@ RUNTIME_FUNCTION(RuntimeReference_IsSmi) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_IsNonNegativeSmi) {
+RUNTIME_FUNCTION(Runtime_IsNonNegativeSmi) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
   CONVERT_ARG_CHECKED(Object, obj, 0);
index 96d9331..c387b37 100644 (file)
@@ -249,12 +249,10 @@ MaybeHandle<Object> Runtime::GetPrototype(Isolate* isolate,
   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->MayAccess(
+            Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)))) {
       isolate->ReportFailedAccessCheck(
-          Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
-          v8::ACCESS_GET);
+          Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
       return isolate->factory()->undefined_value();
     }
@@ -297,10 +295,8 @@ RUNTIME_FUNCTION(Runtime_SetPrototype) {
   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);
+  if (obj->IsAccessCheckNeeded() && !isolate->MayAccess(obj)) {
+    isolate->ReportFailedAccessCheck(obj);
     RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
     return isolate->heap()->undefined_value();
   }
@@ -372,8 +368,8 @@ MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate,
     // Get attributes.
     Maybe<PropertyAttributes> maybe =
         JSReceiver::GetOwnElementAttribute(obj, index);
-    if (!maybe.has_value) return MaybeHandle<Object>();
-    attrs = maybe.value;
+    if (!maybe.IsJust()) return MaybeHandle<Object>();
+    attrs = maybe.FromJust();
     if (attrs == ABSENT) return factory->undefined_value();
 
     // Get AccessorPair if present.
@@ -389,8 +385,8 @@ MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate,
     // 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 (!maybe.IsJust()) return MaybeHandle<Object>();
+    attrs = maybe.FromJust();
     if (attrs == ABSENT) return factory->undefined_value();
 
     // Get AccessorPair if present.
@@ -609,6 +605,7 @@ RUNTIME_FUNCTION(Runtime_KeyedGetProperty) {
             (dictionary->DetailsAt(entry).type() == DATA)) {
           Object* value = dictionary->ValueAt(entry);
           if (!receiver->IsGlobalObject()) return value;
+          DCHECK(value->IsPropertyCell());
           value = PropertyCell::cast(value)->value();
           if (!value->IsTheHole()) return value;
           // If value is the hole (meaning, absent) do the general lookup.
@@ -671,7 +668,7 @@ RUNTIME_FUNCTION(Runtime_AddNamedProperty) {
   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();
+  if (!maybe.IsJust()) return isolate->heap()->exception();
   RUNTIME_ASSERT(!it.IsFound());
 #endif
 
@@ -740,8 +737,8 @@ 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();
+  if (!maybe.IsJust()) return isolate->heap()->exception();
+  if (maybe.FromJust()) 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.
@@ -776,15 +773,15 @@ RUNTIME_FUNCTION(Runtime_HasOwnProperty) {
     // 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;
+    Maybe<bool> maybe = Nothing<bool>();
     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();
+    if (!maybe.IsJust()) return isolate->heap()->exception();
     DCHECK(!isolate->has_pending_exception());
-    if (maybe.value) {
+    if (maybe.FromJust()) {
       return isolate->heap()->true_value();
     }
     Map* map = js_obj->map();
@@ -813,8 +810,8 @@ RUNTIME_FUNCTION(Runtime_HasProperty) {
   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);
+  if (!maybe.IsJust()) return isolate->heap()->exception();
+  return isolate->heap()->ToBoolean(maybe.FromJust());
 }
 
 
@@ -825,8 +822,8 @@ RUNTIME_FUNCTION(Runtime_HasElement) {
   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);
+  if (!maybe.IsJust()) return isolate->heap()->exception();
+  return isolate->heap()->ToBoolean(maybe.FromJust());
 }
 
 
@@ -839,9 +836,9 @@ RUNTIME_FUNCTION(Runtime_IsPropertyEnumerable) {
 
   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);
+  if (!maybe.IsJust()) return isolate->heap()->exception();
+  if (maybe.FromJust() == ABSENT) maybe = Just(DONT_ENUM);
+  return isolate->heap()->ToBoolean((maybe.FromJust() & DONT_ENUM) == 0);
 }
 
 
@@ -917,10 +914,8 @@ RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) {
   // 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);
+    if (obj->IsAccessCheckNeeded() && !isolate->MayAccess(obj)) {
+      isolate->ReportFailedAccessCheck(obj);
       RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
       return *isolate->factory()->NewJSArray(0);
     }
@@ -941,11 +936,8 @@ RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) {
       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);
+      if (jsproto->IsAccessCheckNeeded() && !isolate->MayAccess(jsproto)) {
+        isolate->ReportFailedAccessCheck(jsproto);
         RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
         return *isolate->factory()->NewJSArray(0);
       }
@@ -1094,10 +1086,8 @@ RUNTIME_FUNCTION(Runtime_OwnKeys) {
 
   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);
+    if (object->IsAccessCheckNeeded() && !isolate->MayAccess(object)) {
+      isolate->ReportFailedAccessCheck(object);
       RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
       return *isolate->factory()->NewJSArray(0);
     }
@@ -1442,7 +1432,7 @@ RUNTIME_FUNCTION(Runtime_DefineDataPropertyUnchecked) {
 
   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)) {
+    if (!isolate->MayAccess(js_object)) {
       return isolate->heap()->undefined_value();
     }
     it.Next();
@@ -1488,7 +1478,7 @@ RUNTIME_FUNCTION(Runtime_HasFastPackedElements) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_ValueOf) {
+RUNTIME_FUNCTION(Runtime_ValueOf) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
   CONVERT_ARG_CHECKED(Object, obj, 0);
@@ -1497,7 +1487,7 @@ RUNTIME_FUNCTION(RuntimeReference_ValueOf) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_SetValueOf) {
+RUNTIME_FUNCTION(Runtime_SetValueOf) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 2);
   CONVERT_ARG_CHECKED(Object, obj, 0);
@@ -1508,7 +1498,31 @@ RUNTIME_FUNCTION(RuntimeReference_SetValueOf) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_ObjectEquals) {
+RUNTIME_FUNCTION(Runtime_JSValueGetValue) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSValue, obj, 0);
+  return JSValue::cast(obj)->value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_HeapObjectGetMap) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(HeapObject, obj, 0);
+  return obj->map();
+}
+
+
+RUNTIME_FUNCTION(Runtime_MapGetInstanceType) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Map, map, 0);
+  return Smi::FromInt(map->instance_type());
+}
+
+
+RUNTIME_FUNCTION(Runtime_ObjectEquals) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 2);
   CONVERT_ARG_CHECKED(Object, obj1, 0);
@@ -1517,7 +1531,7 @@ RUNTIME_FUNCTION(RuntimeReference_ObjectEquals) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_IsObject) {
+RUNTIME_FUNCTION(Runtime_IsObject) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
   CONVERT_ARG_CHECKED(Object, obj, 0);
@@ -1532,7 +1546,7 @@ RUNTIME_FUNCTION(RuntimeReference_IsObject) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_IsUndetectableObject) {
+RUNTIME_FUNCTION(Runtime_IsUndetectableObject) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
   CONVERT_ARG_CHECKED(Object, obj, 0);
@@ -1540,7 +1554,7 @@ RUNTIME_FUNCTION(RuntimeReference_IsUndetectableObject) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_IsSpecObject) {
+RUNTIME_FUNCTION(Runtime_IsSpecObject) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
   CONVERT_ARG_CHECKED(Object, obj, 0);
@@ -1548,7 +1562,7 @@ RUNTIME_FUNCTION(RuntimeReference_IsSpecObject) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_ClassOf) {
+RUNTIME_FUNCTION(Runtime_ClassOf) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
   CONVERT_ARG_CHECKED(Object, obj, 0);
index baf7cdb..703d72b 100644 (file)
@@ -34,7 +34,7 @@ RUNTIME_FUNCTION(Runtime_CreateJSFunctionProxy) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_IsJSProxy) {
+RUNTIME_FUNCTION(Runtime_IsJSProxy) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
   CONVERT_ARG_CHECKED(Object, obj, 0);
index 57ff1b2..5846881 100644 (file)
@@ -759,7 +759,7 @@ RUNTIME_FUNCTION(Runtime_StringSplit) {
 }
 
 
-RUNTIME_FUNCTION(Runtime_RegExpExecRT) {
+RUNTIME_FUNCTION(Runtime_RegExpExec) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 4);
   CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
@@ -779,7 +779,7 @@ RUNTIME_FUNCTION(Runtime_RegExpExecRT) {
 }
 
 
-RUNTIME_FUNCTION(Runtime_RegExpConstructResult) {
+RUNTIME_FUNCTION(Runtime_RegExpConstructResultRT) {
   HandleScope handle_scope(isolate);
   DCHECK(args.length() == 3);
   CONVERT_SMI_ARG_CHECKED(size, 0);
@@ -800,6 +800,12 @@ RUNTIME_FUNCTION(Runtime_RegExpConstructResult) {
 }
 
 
+RUNTIME_FUNCTION(Runtime_RegExpConstructResult) {
+  SealHandleScope shs(isolate);
+  return __RT_impl_Runtime_RegExpConstructResultRT(args, isolate);
+}
+
+
 static JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags,
                                              bool* success) {
   uint32_t value = JSRegExp::NONE;
@@ -866,7 +872,7 @@ RUNTIME_FUNCTION(Runtime_RegExpInitializeAndCompile) {
   Handle<Object> unicode = factory->ToBoolean(flags.is_unicode());
 
   Map* map = regexp->map();
-  Object* constructor = map->constructor();
+  Object* constructor = map->GetConstructor();
   if (!FLAG_harmony_regexps && !FLAG_harmony_unicode_regexps &&
       constructor->IsJSFunction() &&
       JSFunction::cast(constructor)->initial_map() == map) {
@@ -925,13 +931,7 @@ RUNTIME_FUNCTION(Runtime_MaterializeRegExpLiteral) {
   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());
+  Handle<JSFunction> constructor = isolate->regexp_function();
   // Compute the regular expression literal.
   Handle<Object> regexp;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
@@ -1110,19 +1110,16 @@ RUNTIME_FUNCTION(Runtime_RegExpExecMultiple) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_RegExpConstructResult) {
+RUNTIME_FUNCTION(Runtime_RegExpExecReThrow) {
   SealHandleScope shs(isolate);
-  return __RT_impl_Runtime_RegExpConstructResult(args, isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_RegExpExec) {
-  SealHandleScope shs(isolate);
-  return __RT_impl_Runtime_RegExpExecRT(args, isolate);
+  DCHECK(args.length() == 4);
+  Object* exception = isolate->pending_exception();
+  isolate->clear_pending_exception();
+  return isolate->ReThrow(exception);
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_IsRegExp) {
+RUNTIME_FUNCTION(Runtime_IsRegExp) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 1);
   CONVERT_ARG_CHECKED(Object, obj, 0);
index 7eb2e0c..2a2ab16 100644 (file)
@@ -26,7 +26,7 @@ RUNTIME_FUNCTION(Runtime_ThrowConstAssignError) {
   HandleScope scope(isolate);
   THROW_NEW_ERROR_RETURN_FAILURE(
       isolate,
-      NewTypeError("harmony_const_assign", HandleVector<Object>(NULL, 0)));
+      NewTypeError("const_assign", HandleVector<Object>(NULL, 0)));
 }
 
 
@@ -46,10 +46,10 @@ static Object* DeclareGlobals(Isolate* isolate, Handle<GlobalObject> global,
   // 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 (!maybe.IsJust()) return isolate->heap()->exception();
 
   if (it.IsFound()) {
-    PropertyAttributes old_attributes = maybe.value;
+    PropertyAttributes old_attributes = maybe.FromJust();
     // The name was declared before; check for conflicting re-declarations.
     if (is_const) return ThrowRedeclarationError(isolate, name);
 
@@ -178,8 +178,8 @@ RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) {
   // 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;
+  DCHECK(maybe.IsJust());
+  PropertyAttributes old_attributes = maybe.FromJust();
 
   PropertyAttributes attr =
       static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
@@ -331,8 +331,8 @@ RUNTIME_FUNCTION(Runtime_InitializeLegacyConstLookupSlot) {
 
     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;
+    if (!maybe.IsJust()) return isolate->heap()->exception();
+    PropertyAttributes old_attributes = maybe.FromJust();
 
     // Ignore if we can't reconfigure the value.
     if ((old_attributes & DONT_DELETE) != 0) {
@@ -596,8 +596,8 @@ static Object* FindNameClash(Handle<ScopeInfo> scope_info,
       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) {
+      if (!maybe.IsJust()) return isolate->heap()->exception();
+      if ((maybe.FromJust() & DONT_DELETE) != 0) {
         return ThrowRedeclarationError(isolate, name);
       }
 
@@ -790,7 +790,8 @@ RUNTIME_FUNCTION(Runtime_DeclareModules) {
         case VAR:
         case LET:
         case CONST:
-        case CONST_LEGACY: {
+        case CONST_LEGACY:
+        case IMPORT: {
           PropertyAttributes attr =
               IsImmutableVariableMode(mode) ? FROZEN : SEALED;
           Handle<AccessorInfo> info =
@@ -855,16 +856,14 @@ RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
 
 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;
+  if (holder->map()->instance_type() != JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
+    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.
@@ -905,11 +904,9 @@ static ObjectPair LoadLookupSlotHelper(Arguments args, Isolate* isolate,
       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);
+          Handle<Object> error = isolate->factory()->NewReferenceError(
+              "not_defined", HandleVector(&name, 1));
+          isolate->Throw(*error);
           return MakePair(isolate->heap()->exception(), NULL);
         }
       // FALLTHROUGH
@@ -935,13 +932,6 @@ static ObjectPair LoadLookupSlotHelper(Arguments args, Isolate* isolate,
   // 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()
@@ -962,10 +952,9 @@ static ObjectPair LoadLookupSlotHelper(Arguments args, Isolate* isolate,
 
   if (throw_error) {
     // The property doesn't exist - throw exception.
-    Handle<Object> error;
-    MaybeHandle<Object> maybe_error = isolate->factory()->NewReferenceError(
+    Handle<Object> error = isolate->factory()->NewReferenceError(
         "not_defined", HandleVector(&name, 1));
-    if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
+    isolate->Throw(*error);
     return MakePair(isolate->heap()->exception(), NULL);
   } else {
     // The property doesn't exist - return undefined.
@@ -1117,7 +1106,7 @@ RUNTIME_FUNCTION(Runtime_GetArgumentsProperty) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_ArgumentsLength) {
+RUNTIME_FUNCTION(Runtime_ArgumentsLength) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 0);
   JavaScriptFrameIterator it(isolate);
@@ -1126,7 +1115,7 @@ RUNTIME_FUNCTION(RuntimeReference_ArgumentsLength) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_Arguments) {
+RUNTIME_FUNCTION(Runtime_Arguments) {
   SealHandleScope shs(isolate);
   return __RT_impl_Runtime_GetArgumentsProperty(args, isolate);
 }
index df2210c..8bfde94 100644 (file)
@@ -279,7 +279,7 @@ RUNTIME_FUNCTION(Runtime_StringLocaleCompare) {
 }
 
 
-RUNTIME_FUNCTION(Runtime_SubString) {
+RUNTIME_FUNCTION(Runtime_SubStringRT) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 3);
 
@@ -307,7 +307,13 @@ RUNTIME_FUNCTION(Runtime_SubString) {
 }
 
 
-RUNTIME_FUNCTION(Runtime_StringAdd) {
+RUNTIME_FUNCTION(Runtime_SubString) {
+  SealHandleScope shs(isolate);
+  return __RT_impl_Runtime_SubStringRT(args, isolate);
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringAddRT) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 2);
   CONVERT_ARG_HANDLE_CHECKED(String, str1, 0);
@@ -320,6 +326,12 @@ RUNTIME_FUNCTION(Runtime_StringAdd) {
 }
 
 
+RUNTIME_FUNCTION(Runtime_StringAdd) {
+  SealHandleScope shs(isolate);
+  return __RT_impl_Runtime_StringAddRT(args, isolate);
+}
+
+
 RUNTIME_FUNCTION(Runtime_InternalizeString) {
   HandleScope handles(isolate);
   RUNTIME_ASSERT(args.length() == 1);
@@ -414,7 +426,7 @@ RUNTIME_FUNCTION(Runtime_CharFromCode) {
 }
 
 
-RUNTIME_FUNCTION(Runtime_StringCompare) {
+RUNTIME_FUNCTION(Runtime_StringCompareRT) {
   HandleScope handle_scope(isolate);
   DCHECK(args.length() == 2);
 
@@ -483,6 +495,12 @@ RUNTIME_FUNCTION(Runtime_StringCompare) {
 }
 
 
+RUNTIME_FUNCTION(Runtime_StringCompare) {
+  SealHandleScope shs(isolate);
+  return __RT_impl_Runtime_StringCompareRT(args, isolate);
+}
+
+
 RUNTIME_FUNCTION(Runtime_StringBuilderConcat) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 3);
@@ -1203,6 +1221,28 @@ RUNTIME_FUNCTION(Runtime_NewString) {
 }
 
 
+RUNTIME_FUNCTION(Runtime_NewConsString) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_INT32_ARG_CHECKED(length, 0);
+  CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, left, 2);
+  CONVERT_ARG_HANDLE_CHECKED(String, right, 3);
+
+  Handle<String> result;
+  if (is_one_byte) {
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, result,
+        isolate->factory()->NewOneByteConsString(length, left, right));
+  } else {
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, result,
+        isolate->factory()->NewTwoByteConsString(length, left, right));
+  }
+  return *result;
+}
+
+
 RUNTIME_FUNCTION(Runtime_StringEquals) {
   HandleScope handle_scope(isolate);
   DCHECK(args.length() == 2);
@@ -1229,13 +1269,13 @@ RUNTIME_FUNCTION(Runtime_FlattenString) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_StringCharFromCode) {
+RUNTIME_FUNCTION(Runtime_StringCharFromCode) {
   SealHandleScope shs(isolate);
   return __RT_impl_Runtime_CharFromCode(args, isolate);
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_StringCharAt) {
+RUNTIME_FUNCTION(Runtime_StringCharAt) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 2);
   if (!args[0]->IsString()) return Smi::FromInt(0);
@@ -1247,7 +1287,16 @@ RUNTIME_FUNCTION(RuntimeReference_StringCharAt) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_OneByteSeqStringSetChar) {
+RUNTIME_FUNCTION(Runtime_OneByteSeqStringGetChar) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_CHECKED(SeqOneByteString, string, 0);
+  CONVERT_INT32_ARG_CHECKED(index, 1);
+  return Smi::FromInt(string->SeqOneByteStringGet(index));
+}
+
+
+RUNTIME_FUNCTION(Runtime_OneByteSeqStringSetChar) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 3);
   CONVERT_INT32_ARG_CHECKED(index, 0);
@@ -1258,7 +1307,16 @@ RUNTIME_FUNCTION(RuntimeReference_OneByteSeqStringSetChar) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_TwoByteSeqStringSetChar) {
+RUNTIME_FUNCTION(Runtime_TwoByteSeqStringGetChar) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_CHECKED(SeqTwoByteString, string, 0);
+  CONVERT_INT32_ARG_CHECKED(index, 1);
+  return Smi::FromInt(string->SeqTwoByteStringGet(index));
+}
+
+
+RUNTIME_FUNCTION(Runtime_TwoByteSeqStringSetChar) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 3);
   CONVERT_INT32_ARG_CHECKED(index, 0);
@@ -1269,13 +1327,7 @@ RUNTIME_FUNCTION(RuntimeReference_TwoByteSeqStringSetChar) {
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_StringCompare) {
-  SealHandleScope shs(isolate);
-  return __RT_impl_Runtime_StringCompare(args, isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_StringCharCodeAt) {
+RUNTIME_FUNCTION(Runtime_StringCharCodeAt) {
   SealHandleScope shs(isolate);
   DCHECK(args.length() == 2);
   if (!args[0]->IsString()) return isolate->heap()->undefined_value();
@@ -1285,21 +1337,17 @@ RUNTIME_FUNCTION(RuntimeReference_StringCharCodeAt) {
 }
 
 
-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(Runtime_IsStringWrapperSafeForDefaultValueOf) {
+  UNIMPLEMENTED();
+  return NULL;
 }
 
 
-RUNTIME_FUNCTION(RuntimeReference_IsStringWrapperSafeForDefaultValueOf) {
-  UNIMPLEMENTED();
-  return NULL;
+RUNTIME_FUNCTION(Runtime_StringGetLength) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
+  return Smi::FromInt(s->length());
 }
 }
 }  // namespace v8::internal
index 89e1f2a..6a812da 100644 (file)
@@ -7,8 +7,8 @@
 #include "src/arguments.h"
 #include "src/deoptimizer.h"
 #include "src/full-codegen.h"
-#include "src/natives.h"
 #include "src/runtime/runtime-utils.h"
+#include "src/snapshot/natives.h"
 
 namespace v8 {
 namespace internal {
@@ -30,6 +30,36 @@ RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) {
 }
 
 
+RUNTIME_FUNCTION(Runtime_DeoptimizeNow) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+
+  Handle<JSFunction> function;
+
+  // If the argument is 'undefined', deoptimize the topmost
+  // function.
+  JavaScriptFrameIterator it(isolate);
+  while (!it.done()) {
+    if (it.frame()->is_java_script()) {
+      function = Handle<JSFunction>(it.frame()->function());
+      break;
+    }
+  }
+  if (function.is_null()) return isolate->heap()->undefined_value();
+
+  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);
@@ -59,8 +89,6 @@ RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
                  (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();
 
@@ -81,10 +109,10 @@ RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
 
 RUNTIME_FUNCTION(Runtime_OptimizeOsr) {
   HandleScope scope(isolate);
-  RUNTIME_ASSERT(args.length() == 0);
+  RUNTIME_ASSERT(args.length() == 0 || args.length() == 1);
   Handle<JSFunction> function = Handle<JSFunction>::null();
 
-  {
+  if (args.length() == 0) {
     // Find the JavaScript function on the top of the stack.
     JavaScriptFrameIterator it(isolate);
     while (!it.done()) {
@@ -94,6 +122,10 @@ RUNTIME_FUNCTION(Runtime_OptimizeOsr) {
       }
     }
     if (function.is_null()) return isolate->heap()->undefined_value();
+  } else {
+    // Function was passed as an argument.
+    CONVERT_ARG_HANDLE_CHECKED(JSFunction, arg, 0);
+    function = arg;
   }
 
   // The following assertion was lifted from the DCHECK inside
@@ -102,8 +134,6 @@ RUNTIME_FUNCTION(Runtime_OptimizeOsr) {
                  (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();
 
@@ -346,6 +376,23 @@ RUNTIME_FUNCTION(Runtime_GetV8Version) {
 }
 
 
+RUNTIME_FUNCTION(Runtime_DisassembleFunction) {
+  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();
+}
+
+
 static int StackSize(Isolate* isolate) {
   int n = 0;
   for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
index 82224bc..59c417f 100644 (file)
@@ -88,6 +88,8 @@ bool Runtime::SetupArrayBufferAllocatingData(Isolate* isolate,
 
 void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) {
   Isolate* isolate = array_buffer->GetIsolate();
+  // Firstly, iterate over the views which are referenced directly by the array
+  // buffer.
   for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate);
        !view_obj->IsUndefined();) {
     Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj));
@@ -100,6 +102,24 @@ void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) {
     }
     view_obj = handle(view->weak_next(), isolate);
   }
+
+  // Secondly, iterate over the global list of new space views to find views
+  // that belong to the neutered array buffer.
+  Heap* heap = isolate->heap();
+  for (Handle<Object> view_obj(heap->new_array_buffer_views_list(), isolate);
+       !view_obj->IsUndefined();) {
+    Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj));
+    if (view->buffer() == *array_buffer) {
+      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();
 }
 
@@ -265,11 +285,18 @@ RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) {
   holder->set_byte_offset(*byte_offset_object);
   holder->set_byte_length(*byte_length_object);
 
+  Heap* heap = isolate->heap();
   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);
+
+    if (heap->InNewSpace(*holder)) {
+      holder->set_weak_next(heap->new_array_buffer_views_list());
+      heap->set_new_array_buffer_views_list(*holder);
+    } else {
+      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,
@@ -367,8 +394,15 @@ RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
       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);
+
+  Heap* heap = isolate->heap();
+  if (heap->InNewSpace(*holder)) {
+    holder->set_weak_next(heap->new_array_buffer_views_list());
+    heap->set_new_array_buffer_views_list(*holder);
+  } else {
+    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,
@@ -542,8 +576,14 @@ RUNTIME_FUNCTION(Runtime_DataViewInitialize) {
   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);
+  Heap* heap = isolate->heap();
+  if (heap->InNewSpace(*holder)) {
+    holder->set_weak_next(heap->new_array_buffer_views_list());
+    heap->set_new_array_buffer_views_list(*holder);
+  } else {
+    holder->set_weak_next(buffer->weak_first_view());
+    buffer->set_weak_first_view(*holder);
+  }
 
   return isolate->heap()->undefined_value();
 }
index d01c141..674f117 100644 (file)
@@ -14,25 +14,13 @@ namespace internal {
 #define F(name, number_of_args, result_size)                    \
   Object* Runtime_##name(int args_length, Object** args_object, \
                          Isolate* isolate);
+FOR_EACH_INTRINSIC_RETURN_OBJECT(F)
+#undef F
 
 #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.
-#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
+FOR_EACH_INTRINSIC_RETURN_PAIR(P)
 #undef P
 
 
@@ -44,27 +32,17 @@ INLINE_FUNCTION_LIST(I)
   ,
 
 
-#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         \
-  }                                                                        \
+#define I(name, number_of_args, result_size)                       \
+  {                                                                \
+    Runtime::kInline##name, Runtime::INLINE, "_" #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)};
+    FOR_EACH_INTRINSIC(F) FOR_EACH_INTRINSIC(I)};
 
-#undef IO
 #undef I
 #undef F
 
@@ -78,7 +56,7 @@ void Runtime::InitializeIntrinsicFunctionNames(Isolate* isolate,
     if (name == NULL) continue;
     Handle<NameDictionary> new_dict = NameDictionary::Add(
         dict, isolate->factory()->InternalizeUtf8String(name),
-        Handle<Smi>(Smi::FromInt(i), isolate), PropertyDetails(NONE, DATA, 0));
+        Handle<Smi>(Smi::FromInt(i), isolate), PropertyDetails::Empty());
     // The dictionary does not need to grow.
     CHECK(new_dict.is_identical_to(dict));
   }
index 12f7af4..e2ee5bf 100644 (file)
@@ -15,190 +15,192 @@ 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(OptimizeOsr, 0, 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(IsConstructor, 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(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, 2, 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(ClassGetSourceCode, 1, 1)                              \
-  F(LoadFromSuper, 3, 1)                                   \
-  F(LoadKeyedFromSuper, 3, 1)                              \
-  F(ThrowConstructorNonCallableError, 0, 1)                \
-  F(ThrowArrayNotSubclassableError, 0, 1)                  \
-  F(ThrowNonMethodError, 0, 1)                             \
-  F(ThrowUnsupportedSuperError, 0, 1)                      \
-  F(HandleStepInForDerivedConstructors, 1, 1)              \
-  F(StoreToSuper_Strict, 4, 1)                             \
-  F(StoreToSuper_Sloppy, 4, 1)                             \
-  F(StoreKeyedToSuper_Strict, 4, 1)                        \
-  F(StoreKeyedToSuper_Sloppy, 4, 1)
+#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(DeoptimizeNow, 0, 1)                       \
+  F(ClearFunctionTypeFeedback, 1, 1)           \
+  F(RunningInSimulator, 0, 1)                  \
+  F(IsConcurrentRecompilationSupported, 0, 1)  \
+  F(OptimizeFunctionOnNextCall, -1, 1)         \
+  F(OptimizeOsr, -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(IsConstructor, 1, 1)                       \
+  F(SetInlineBuiltinFlag, 1, 1)                \
+  F(StoreArrayLiteralElement, 5, 1)            \
+  F(DebugPrepareStepInIfStepping, 1, 1)        \
+  F(DebugPushPromise, 2, 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)               \
+  F(ThrowIteratorResultNotAnObject, 1, 1)      \
+  F(IncrementStatsCounter, 1, 1)               \
+                                               \
+  /* Array join support */                     \
+  F(PushIfAbsent, 2, 1)                        \
+  F(ArrayConcat, 1, 1)                         \
+                                               \
+  /* Conversions */                            \
+  F(ToBool, 1, 1)                              \
+  F(Typeof, 1, 1)                              \
+                                               \
+  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(MathAtan2, 2, 1)                           \
+  F(MathExpRT, 1, 1)                           \
+  F(RoundNumber, 1, 1)                         \
+  F(MathFround, 1, 1)                          \
+  F(RemPiO2, 2, 1)                             \
+                                               \
+  /* Regular expressions */                    \
+  F(RegExpInitializeAndCompile, 3, 1)          \
+  F(RegExpExecMultiple, 4, 1)                  \
+  F(RegExpExecReThrow, 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(NewConsString, 4, 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(ClassGetSourceCode, 1, 1)                  \
+  F(DefineClass, 6, 1)                         \
+  F(DefineClassMethod, 3, 1)                   \
+  F(HandleStepInForDerivedConstructors, 1, 1)  \
+  F(HomeObjectSymbol, 0, 1)                    \
+  F(LoadFromSuper, 3, 1)                       \
+  F(LoadKeyedFromSuper, 3, 1)                  \
+  F(StoreKeyedToSuper_Sloppy, 4, 1)            \
+  F(StoreKeyedToSuper_Strict, 4, 1)            \
+  F(StoreToSuper_Sloppy, 4, 1)                 \
+  F(StoreToSuper_Strict, 4, 1)                 \
+  F(ThrowArrayNotSubclassableError, 0, 1)      \
+  F(ThrowConstructorNonCallableError, 0, 1)    \
+  F(ThrowIfStaticPrototype, 1, 1)              \
+  F(ThrowNonMethodError, 0, 1)                 \
+  F(ThrowStaticPrototypeError, 0, 1)           \
+  F(ThrowUnsupportedSuperError, 0, 1)          \
+  F(ToMethod, 2, 1)
 
 
 #define RUNTIME_FUNCTION_LIST_ALWAYS_2(F)              \
@@ -420,6 +422,7 @@ namespace internal {
   F(HasFastProperties, 1, 1)                           \
   F(TransitionElementsKind, 2, 1)                      \
   F(HaveSameMap, 2, 1)                                 \
+  F(DisassembleFunction, 1, 1)                         \
   F(IsJSGlobalProxy, 1, 1)                             \
   F(ForInCacheArrayLength, 2, 1) /* TODO(turbofan): Only temporary */
 
@@ -427,14 +430,13 @@ namespace internal {
 #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(RegExpConstructResultRT, 3, 1)                           \
+  F(StringAddRT, 2, 1)                                       \
+  F(SubStringRT, 3, 1)                                       \
   F(InternalizeString, 1, 1)                                 \
-  F(StringCompare, 2, 1)                                     \
+  F(StringCompareRT, 2, 1)                                   \
   F(StringCharCodeAtRT, 2, 1)                                \
-  F(GetFromCache, 2, 1)                                      \
+  F(GetFromCacheRT, 2, 1)                                    \
                                                              \
   /* Compilation */                                          \
   F(CompileLazy, 1, 1)                                       \
@@ -458,7 +460,7 @@ namespace internal {
                                                              \
   /* Harmony generators */                                   \
   F(CreateJSGeneratorObject, 0, 1)                           \
-  F(SuspendJSGeneratorObject, 1, 1)                          \
+  F(SuspendJSGeneratorObject, -1, 1)                         \
   F(ResumeJSGeneratorObject, 3, 1)                           \
   F(GeneratorClose, 1, 1)                                    \
                                                              \
@@ -486,6 +488,7 @@ namespace internal {
   F(ThrowConstAssignError, 0, 1)                             \
   F(StackGuard, 0, 1)                                        \
   F(Interrupt, 0, 1)                                         \
+  F(FindExceptionHandler, 0, 1)                              \
   F(PromoteScheduledException, 0, 1)                         \
                                                              \
   /* Contexts */                                             \
@@ -510,7 +513,7 @@ namespace internal {
   F(MathPowRT, 2, 1)
 
 
-#define RUNTIME_FUNCTION_LIST_RETURN_PAIR(F)              \
+#define FOR_EACH_INTRINSIC_RETURN_PAIR(F)                 \
   F(LoadLookupSlot, 2, 2)                                 \
   F(LoadLookupSlotNoReferenceError, 2, 2)                 \
   F(ResolvePossiblyDirectEval, 6, 2)                      \
@@ -522,7 +525,7 @@ namespace internal {
   /* Debugger support*/                             \
   F(DebugBreak, 0, 1)                               \
   F(SetDebugEventListener, 2, 1)                    \
-  F(Break, 0, 1)                                    \
+  F(ScheduleBreak, 0, 1)                            \
   F(DebugGetPropertyDetails, 2, 1)                  \
   F(DebugGetProperty, 2, 1)                         \
   F(DebugPropertyTypeFromDetails, 1, 1)             \
@@ -561,9 +564,8 @@ namespace internal {
   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(FunctionGetDebugName, 1, 1)                     \
   F(LiveEditFindSharedFunctionInfosForScript, 1, 1) \
   F(LiveEditGatherCompileInfo, 2, 1)                \
   F(LiveEditReplaceScript, 3, 1)                    \
@@ -576,7 +578,7 @@ namespace internal {
   F(LiveEditCompareStrings, 2, 1)                   \
   F(LiveEditRestartFrame, 2, 1)                     \
   F(GetFunctionCodePositionFromSource, 2, 1)        \
-  F(ExecuteInDebugContext, 2, 1)                    \
+  F(ExecuteInDebugContext, 1, 1)                    \
   F(GetDebugContext, 0, 1)                          \
   F(SetFlags, 1, 1)                                 \
   F(CollectGarbage, 1, 1)                           \
@@ -627,26 +629,8 @@ namespace internal {
 
 
 // ----------------------------------------------------------------------------
-// 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.
+// INLINE_FUNCTION_LIST defines the intrinsics typically handled specially by
+// the various compilers.
 // Entries have the form F(name, number of arguments, number of return values).
 #define INLINE_FUNCTION_LIST(F)                             \
   F(IsSmi, 1, 1)                                            \
@@ -664,7 +648,9 @@ namespace internal {
   F(DateField, 2 /* date object, field index */, 1)         \
   F(StringCharFromCode, 1, 1)                               \
   F(StringCharAt, 2, 1)                                     \
+  F(OneByteSeqStringGetChar, 2, 1)                          \
   F(OneByteSeqStringSetChar, 3, 1)                          \
+  F(TwoByteSeqStringGetChar, 2, 1)                          \
   F(TwoByteSeqStringSetChar, 3, 1)                          \
   F(ObjectEquals, 2, 1)                                     \
   F(IsObject, 1, 1)                                         \
@@ -693,11 +679,8 @@ namespace internal {
 
 
 // ----------------------------------------------------------------------------
-// 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).
+// INLINE_OPTIMIZED_FUNCTION_LIST defines the intrinsics typically handled
+// specially by Crankshaft.
 // Entries have the form F(name, number of arguments, number of return values).
 #define INLINE_OPTIMIZED_FUNCTION_LIST(F) \
   /* Typed Arrays */                      \
@@ -714,7 +697,9 @@ namespace internal {
   F(ConstructDouble, 2, 1)                \
   F(DoubleHi, 1, 1)                       \
   F(DoubleLo, 1, 1)                       \
-  F(MathSqrtRT, 1, 1)                     \
+  F(MathClz32, 1, 1)                      \
+  F(MathFloor, 1, 1)                      \
+  F(MathSqrt, 1, 1)                       \
   F(MathLogRT, 1, 1)                      \
   /* ES6 Collections */                   \
   F(MapClear, 1, 1)                       \
@@ -732,7 +717,33 @@ namespace internal {
   F(SetInitialize, 1, 1)                  \
   /* Arrays */                            \
   F(HasFastPackedElements, 1, 1)          \
-  F(GetPrototype, 1, 1)
+  F(GetPrototype, 1, 1)                   \
+  /* Strings */                           \
+  F(StringGetLength, 1, 1)                \
+  /* JSValue */                           \
+  F(JSValueGetValue, 1, 1)                \
+  /* HeapObject */                        \
+  F(HeapObjectGetMap, 1, 1)               \
+  /* Map */                               \
+  F(MapGetInstanceType, 1, 1)
+
+
+#define FOR_EACH_INTRINSIC_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)     \
+  INLINE_FUNCTION_LIST(F)                   \
+  INLINE_OPTIMIZED_FUNCTION_LIST(F)
+
+
+// FOR_EACH_INTRINSIC defines the list of all intrinsics, coming in 2 flavors,
+// either returning an object or a pair.
+// Entries have the form F(name, number of arguments, number of values).
+#define FOR_EACH_INTRINSIC(F)       \
+  FOR_EACH_INTRINSIC_RETURN_PAIR(F) \
+  FOR_EACH_INTRINSIC_RETURN_OBJECT(F)
 
 
 //---------------------------------------------------------------------------
@@ -766,19 +777,14 @@ 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)
+#define I(name, nargs, ressize) kInline##name,
+    FOR_EACH_INTRINSIC(F) FOR_EACH_INTRINSIC(I)
+#undef I
 #undef F
-    kNumFunctions,
-    kFirstInlineFunction = kInlineIsSmi
+        kNumFunctions,
   };
 
-  enum IntrinsicType { RUNTIME, INLINE, INLINE_OPTIMIZED };
+  enum IntrinsicType { RUNTIME, INLINE };
 
   // Intrinsic function descriptor.
   struct Function {
index de1b8e8..a40688f 100644 (file)
@@ -35,11 +35,9 @@ Handle<String> LiteralBuffer::Internalize(Isolate* isolate) const {
 Scanner::Scanner(UnicodeCache* unicode_cache)
     : unicode_cache_(unicode_cache),
       octal_pos_(Location::invalid()),
-      harmony_scoping_(false),
       harmony_modules_(false),
       harmony_numeric_literals_(false),
       harmony_classes_(false),
-      harmony_templates_(false),
       harmony_unicode_(false) {}
 
 
@@ -656,10 +654,8 @@ void Scanner::Scan() {
         break;
 
       case '`':
-        if (HarmonyTemplates()) {
-          token = ScanTemplateStart();
-          break;
-        }
+        token = ScanTemplateStart();
+        break;
 
       default:
         if (c0_ < 0) {
@@ -788,11 +784,31 @@ uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
 }
 
 
+const int kMaxAscii = 127;
+
+
 Token::Value Scanner::ScanString() {
   uc32 quote = c0_;
-  Advance();  // consume quote
+  Advance<false, false>();  // consume quote
 
   LiteralScope literal(this);
+  while (true) {
+    if (c0_ > kMaxAscii) {
+      HandleLeadSurrogate();
+      break;
+    }
+    if (c0_ < 0 || c0_ == '\n' || c0_ == '\r') return Token::ILLEGAL;
+    if (c0_ == quote) {
+      literal.Complete();
+      Advance<false, false>();
+      return Token::STRING;
+    }
+    uc32 c = c0_;
+    if (c == '\\') break;
+    Advance<false, false>();
+    AddLiteralChar(c);
+  }
+
   while (c0_ != quote && c0_ >= 0
          && !unicode_cache_->IsLineTerminator(c0_)) {
     uc32 c = c0_;
@@ -913,6 +929,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
   enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL;
 
   LiteralScope literal(this);
+  bool at_start = !seen_period;
   if (seen_period) {
     // we have already seen a decimal point of the float
     AddLiteralChar('.');
@@ -962,6 +979,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
         kind = IMPLICIT_OCTAL;
         while (true) {
           if (c0_ == '8' || c0_ == '9') {
+            at_start = false;
             kind = DECIMAL;
             break;
           }
@@ -977,6 +995,27 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
 
     // Parse decimal digits and allow trailing fractional part.
     if (kind == DECIMAL) {
+      if (at_start) {
+        uint64_t value = 0;
+        while (IsDecimalDigit(c0_)) {
+          value = 10 * value + (c0_ - '0');
+
+          uc32 first_char = c0_;
+          Advance<false, false>();
+          AddLiteralChar(first_char);
+        }
+
+        if (next_.literal_chars->one_byte_literal().length() <= 10 &&
+            value <= Smi::kMaxValue && c0_ != '.' && c0_ != 'e' && c0_ != 'E') {
+          smi_value_ = static_cast<int>(value);
+          literal.Complete();
+          HandleLeadSurrogate();
+
+          return Token::SMI;
+        }
+        HandleLeadSurrogate();
+      }
+
       ScanDecimalDigits();  // optional
       if (c0_ == '.') {
         AddLiteralCharAdvance();
@@ -1046,79 +1085,77 @@ uc32 Scanner::ScanUnicodeEscape() {
 // ----------------------------------------------------------------------------
 // Keyword Matcher
 
-#define KEYWORDS(KEYWORD_GROUP, KEYWORD)                                     \
-  KEYWORD_GROUP('b')                                                         \
-  KEYWORD("break", Token::BREAK)                                             \
-  KEYWORD_GROUP('c')                                                         \
-  KEYWORD("case", Token::CASE)                                               \
-  KEYWORD("catch", Token::CATCH)                                             \
-  KEYWORD("class",                                                           \
-          harmony_classes ? Token::CLASS : Token::FUTURE_RESERVED_WORD)      \
-  KEYWORD("const", Token::CONST)                                             \
-  KEYWORD("continue", Token::CONTINUE)                                       \
-  KEYWORD_GROUP('d')                                                         \
-  KEYWORD("debugger", Token::DEBUGGER)                                       \
-  KEYWORD("default", Token::DEFAULT)                                         \
-  KEYWORD("delete", Token::DELETE)                                           \
-  KEYWORD("do", Token::DO)                                                   \
-  KEYWORD_GROUP('e')                                                         \
-  KEYWORD("else", Token::ELSE)                                               \
-  KEYWORD("enum", Token::FUTURE_RESERVED_WORD)                               \
-  KEYWORD("export",                                                          \
-          harmony_modules ? Token::EXPORT : Token::FUTURE_RESERVED_WORD)     \
-  KEYWORD("extends",                                                         \
-          harmony_classes ? Token::EXTENDS : Token::FUTURE_RESERVED_WORD)    \
-  KEYWORD_GROUP('f')                                                         \
-  KEYWORD("false", Token::FALSE_LITERAL)                                     \
-  KEYWORD("finally", Token::FINALLY)                                         \
-  KEYWORD("for", Token::FOR)                                                 \
-  KEYWORD("function", Token::FUNCTION)                                       \
-  KEYWORD_GROUP('i')                                                         \
-  KEYWORD("if", Token::IF)                                                   \
-  KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD)                  \
-  KEYWORD("import",                                                          \
-          harmony_modules ? Token::IMPORT : Token::FUTURE_RESERVED_WORD)     \
-  KEYWORD("in", Token::IN)                                                   \
-  KEYWORD("instanceof", Token::INSTANCEOF)                                   \
-  KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD)                   \
-  KEYWORD_GROUP('l')                                                         \
-  KEYWORD("let",                                                             \
-          harmony_scoping ? Token::LET : Token::FUTURE_STRICT_RESERVED_WORD) \
-  KEYWORD_GROUP('n')                                                         \
-  KEYWORD("new", Token::NEW)                                                 \
-  KEYWORD("null", Token::NULL_LITERAL)                                       \
-  KEYWORD_GROUP('p')                                                         \
-  KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD)                     \
-  KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD)                     \
-  KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD)                   \
-  KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD)                      \
-  KEYWORD_GROUP('r')                                                         \
-  KEYWORD("return", Token::RETURN)                                           \
-  KEYWORD_GROUP('s')                                                         \
-  KEYWORD("static", harmony_classes ? Token::STATIC                          \
-                                    : Token::FUTURE_STRICT_RESERVED_WORD)    \
-  KEYWORD("super",                                                           \
-          harmony_classes ? Token::SUPER : Token::FUTURE_RESERVED_WORD)      \
-  KEYWORD("switch", Token::SWITCH)                                           \
-  KEYWORD_GROUP('t')                                                         \
-  KEYWORD("this", Token::THIS)                                               \
-  KEYWORD("throw", Token::THROW)                                             \
-  KEYWORD("true", Token::TRUE_LITERAL)                                       \
-  KEYWORD("try", Token::TRY)                                                 \
-  KEYWORD("typeof", Token::TYPEOF)                                           \
-  KEYWORD_GROUP('v')                                                         \
-  KEYWORD("var", Token::VAR)                                                 \
-  KEYWORD("void", Token::VOID)                                               \
-  KEYWORD_GROUP('w')                                                         \
-  KEYWORD("while", Token::WHILE)                                             \
-  KEYWORD("with", Token::WITH)                                               \
-  KEYWORD_GROUP('y')                                                         \
+#define KEYWORDS(KEYWORD_GROUP, KEYWORD)                                  \
+  KEYWORD_GROUP('b')                                                      \
+  KEYWORD("break", Token::BREAK)                                          \
+  KEYWORD_GROUP('c')                                                      \
+  KEYWORD("case", Token::CASE)                                            \
+  KEYWORD("catch", Token::CATCH)                                          \
+  KEYWORD("class",                                                        \
+          harmony_classes ? Token::CLASS : Token::FUTURE_RESERVED_WORD)   \
+  KEYWORD("const", Token::CONST)                                          \
+  KEYWORD("continue", Token::CONTINUE)                                    \
+  KEYWORD_GROUP('d')                                                      \
+  KEYWORD("debugger", Token::DEBUGGER)                                    \
+  KEYWORD("default", Token::DEFAULT)                                      \
+  KEYWORD("delete", Token::DELETE)                                        \
+  KEYWORD("do", Token::DO)                                                \
+  KEYWORD_GROUP('e')                                                      \
+  KEYWORD("else", Token::ELSE)                                            \
+  KEYWORD("enum", Token::FUTURE_RESERVED_WORD)                            \
+  KEYWORD("export",                                                       \
+          harmony_modules ? Token::EXPORT : Token::FUTURE_RESERVED_WORD)  \
+  KEYWORD("extends",                                                      \
+          harmony_classes ? Token::EXTENDS : Token::FUTURE_RESERVED_WORD) \
+  KEYWORD_GROUP('f')                                                      \
+  KEYWORD("false", Token::FALSE_LITERAL)                                  \
+  KEYWORD("finally", Token::FINALLY)                                      \
+  KEYWORD("for", Token::FOR)                                              \
+  KEYWORD("function", Token::FUNCTION)                                    \
+  KEYWORD_GROUP('i')                                                      \
+  KEYWORD("if", Token::IF)                                                \
+  KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD)               \
+  KEYWORD("import",                                                       \
+          harmony_modules ? Token::IMPORT : Token::FUTURE_RESERVED_WORD)  \
+  KEYWORD("in", Token::IN)                                                \
+  KEYWORD("instanceof", Token::INSTANCEOF)                                \
+  KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD)                \
+  KEYWORD_GROUP('l')                                                      \
+  KEYWORD("let", Token::LET)                                              \
+  KEYWORD_GROUP('n')                                                      \
+  KEYWORD("new", Token::NEW)                                              \
+  KEYWORD("null", Token::NULL_LITERAL)                                    \
+  KEYWORD_GROUP('p')                                                      \
+  KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD)                  \
+  KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD)                  \
+  KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD)                \
+  KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD)                   \
+  KEYWORD_GROUP('r')                                                      \
+  KEYWORD("return", Token::RETURN)                                        \
+  KEYWORD_GROUP('s')                                                      \
+  KEYWORD("static", harmony_classes ? Token::STATIC                       \
+                                    : Token::FUTURE_STRICT_RESERVED_WORD) \
+  KEYWORD("super",                                                        \
+          harmony_classes ? Token::SUPER : Token::FUTURE_RESERVED_WORD)   \
+  KEYWORD("switch", Token::SWITCH)                                        \
+  KEYWORD_GROUP('t')                                                      \
+  KEYWORD("this", Token::THIS)                                            \
+  KEYWORD("throw", Token::THROW)                                          \
+  KEYWORD("true", Token::TRUE_LITERAL)                                    \
+  KEYWORD("try", Token::TRY)                                              \
+  KEYWORD("typeof", Token::TYPEOF)                                        \
+  KEYWORD_GROUP('v')                                                      \
+  KEYWORD("var", Token::VAR)                                              \
+  KEYWORD("void", Token::VOID)                                            \
+  KEYWORD_GROUP('w')                                                      \
+  KEYWORD("while", Token::WHILE)                                          \
+  KEYWORD("with", Token::WITH)                                            \
+  KEYWORD_GROUP('y')                                                      \
   KEYWORD("yield", Token::YIELD)
 
 
 static Token::Value KeywordOrIdentifierToken(const uint8_t* input,
                                              int input_length,
-                                             bool harmony_scoping,
                                              bool harmony_modules,
                                              bool harmony_classes) {
   DCHECK(input_length >= 1);
@@ -1168,16 +1205,59 @@ bool Scanner::IdentifierIsFutureStrictReserved(
   }
   return Token::FUTURE_STRICT_RESERVED_WORD ==
          KeywordOrIdentifierToken(string->raw_data(), string->length(),
-                                  harmony_scoping_, harmony_modules_,
-                                  harmony_classes_);
+                                  harmony_modules_, harmony_classes_);
 }
 
 
 Token::Value Scanner::ScanIdentifierOrKeyword() {
   DCHECK(unicode_cache_->IsIdentifierStart(c0_));
   LiteralScope literal(this);
-  // Scan identifier start character.
-  if (c0_ == '\\') {
+  if (IsInRange(c0_, 'a', 'z')) {
+    do {
+      uc32 first_char = c0_;
+      Advance<false, false>();
+      AddLiteralChar(first_char);
+    } while (IsInRange(c0_, 'a', 'z'));
+
+    if (IsDecimalDigit(c0_) || IsInRange(c0_, 'A', 'Z') || c0_ == '_' ||
+        c0_ == '$') {
+      // Identifier starting with lowercase.
+      uc32 first_char = c0_;
+      Advance<false, false>();
+      AddLiteralChar(first_char);
+      while (IsAsciiIdentifier(c0_)) {
+        uc32 first_char = c0_;
+        Advance<false, false>();
+        AddLiteralChar(first_char);
+      }
+      if (c0_ <= kMaxAscii && c0_ != '\\') {
+        literal.Complete();
+        return Token::IDENTIFIER;
+      }
+    } else if (c0_ <= kMaxAscii && c0_ != '\\') {
+      // Only a-z+: could be a keyword or identifier.
+      literal.Complete();
+      Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal();
+      return KeywordOrIdentifierToken(chars.start(), chars.length(),
+                                      harmony_modules_, harmony_classes_);
+    }
+
+    HandleLeadSurrogate();
+  } else if (IsInRange(c0_, 'A', 'Z') || c0_ == '_' || c0_ == '$') {
+    do {
+      uc32 first_char = c0_;
+      Advance<false, false>();
+      AddLiteralChar(first_char);
+    } while (IsAsciiIdentifier(c0_));
+
+    if (c0_ <= kMaxAscii && c0_ != '\\') {
+      literal.Complete();
+      return Token::IDENTIFIER;
+    }
+
+    HandleLeadSurrogate();
+  } else if (c0_ == '\\') {
+    // Scan identifier start character.
     uc32 c = ScanIdentifierUnicodeEscape();
     // Only allow legal identifier start characters.
     if (c < 0 ||
@@ -1187,12 +1267,12 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
     }
     AddLiteralChar(c);
     return ScanIdentifierSuffix(&literal);
+  } else {
+    uc32 first_char = c0_;
+    Advance();
+    AddLiteralChar(first_char);
   }
 
-  uc32 first_char = c0_;
-  Advance();
-  AddLiteralChar(first_char);
-
   // Scan the rest of the identifier characters.
   while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) {
     if (c0_ != '\\') {
@@ -1211,11 +1291,9 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
     Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal();
     return KeywordOrIdentifierToken(chars.start(),
                                     chars.length(),
-                                    harmony_scoping_,
                                     harmony_modules_,
                                     harmony_classes_);
   }
-
   return Token::IDENTIFIER;
 }
 
@@ -1341,11 +1419,6 @@ double Scanner::DoubleValue() {
 }
 
 
-int Scanner::FindNumber(DuplicateFinder* finder, int value) {
-  return finder->AddNumber(literal_one_byte_string(), value);
-}
-
-
 int Scanner::FindSymbol(DuplicateFinder* finder, int value) {
   if (is_literal_one_byte()) {
     return finder->AddOneByteSymbol(literal_one_byte_string(), value);
index 86a0098..8040825 100644 (file)
@@ -427,7 +427,6 @@ class Scanner {
     }
   }
 
-  int FindNumber(DuplicateFinder* finder, int value);
   int FindSymbol(DuplicateFinder* finder, int value);
 
   UnicodeCache* unicode_cache() { return unicode_cache_; }
@@ -436,18 +435,15 @@ class Scanner {
   Location octal_position() const { return octal_pos_; }
   void clear_octal_position() { octal_pos_ = Location::invalid(); }
 
+  // Returns the value of the last smi that was scanned.
+  int smi_value() const { return smi_value_; }
+
   // Seek forward to the given position.  This operation does not
   // work in general, for instance when there are pushed back
   // characters, but works for seeking forward until simple delimiter
   // tokens, which is what it is used for.
   void SeekForward(int pos);
 
-  bool HarmonyScoping() const {
-    return harmony_scoping_;
-  }
-  void SetHarmonyScoping(bool scoping) {
-    harmony_scoping_ = scoping;
-  }
   bool HarmonyModules() const {
     return harmony_modules_;
   }
@@ -466,8 +462,6 @@ class Scanner {
   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; }
 
@@ -530,8 +524,11 @@ class Scanner {
   }
 
   inline void StartRawLiteral() {
-    raw_literal_buffer_.Reset();
-    next_.raw_literal_chars = &raw_literal_buffer_;
+    LiteralBuffer* free_buffer =
+        (current_.raw_literal_chars == &raw_literal_buffer1_) ?
+            &raw_literal_buffer2_ : &raw_literal_buffer1_;
+    free_buffer->Reset();
+    next_.raw_literal_chars = free_buffer;
   }
 
   INLINE(void AddLiteralChar(uc32 c)) {
@@ -562,12 +559,16 @@ class Scanner {
   }
 
   // Low-level scanning support.
-  template <bool capture_raw = false>
+  template <bool capture_raw = false, bool check_surrogate = true>
   void Advance() {
     if (capture_raw) {
       AddRawLiteralChar(c0_);
     }
     c0_ = source_->Advance();
+    if (check_surrogate) HandleLeadSurrogate();
+  }
+
+  void HandleLeadSurrogate() {
     if (unibrow::Utf16::IsLeadSurrogate(c0_)) {
       uc32 c1 = source_->Advance();
       if (!unibrow::Utf16::IsTrailSurrogate(c1)) {
@@ -710,7 +711,8 @@ class Scanner {
   LiteralBuffer source_mapping_url_;
 
   // Buffer to store raw string values
-  LiteralBuffer raw_literal_buffer_;
+  LiteralBuffer raw_literal_buffer1_;
+  LiteralBuffer raw_literal_buffer2_;
 
   TokenDesc current_;  // desc for current token (as returned by Next())
   TokenDesc next_;     // desc for next token (one token look-ahead)
@@ -722,6 +724,9 @@ class Scanner {
   // Start position of the octal literal last scanned.
   Location octal_pos_;
 
+  // Value of the last smi that was scanned.
+  int smi_value_;
+
   // One Unicode character look-ahead; c0_ < 0 at the end of the input.
   uc32 c0_;
 
@@ -732,16 +737,12 @@ class Scanner {
   // Whether there is a multi-line comment that contains a
   // line-terminator after the current token, and before the next.
   bool has_multiline_comment_before_next_;
-  // Whether we scan 'let' as a keyword for harmony block-scoped let bindings.
-  bool harmony_scoping_;
   // Whether we scan 'module', 'import', 'export' as keywords.
   bool harmony_modules_;
   // Whether we scan 0o777 and 0b111 as numbers.
   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_;
 };
index 74aefdb..99d4c38 100644 (file)
@@ -18,9 +18,14 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
   // Collect stack and context locals.
   ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone);
   ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone);
-  scope->CollectStackAndContextLocals(&stack_locals, &context_locals);
+  ZoneList<Variable*> strong_mode_free_variables(0, zone);
+
+  scope->CollectStackAndContextLocals(&stack_locals, &context_locals,
+                                      &strong_mode_free_variables);
   const int stack_local_count = stack_locals.length();
   const int context_local_count = context_locals.length();
+  const int strong_mode_free_variable_count =
+      strong_mode_free_variables.length();
   // Make sure we allocate the correct amount.
   DCHECK(scope->StackLocalCount() == stack_local_count);
   DCHECK(scope->ContextLocalCount() == context_local_count);
@@ -49,9 +54,10 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
 
   const bool has_function_name = function_name_info != NONE;
   const int parameter_count = scope->num_parameters();
-  const int length = kVariablePartIndex
-      + parameter_count + stack_local_count + 2 * context_local_count
-      + (has_function_name ? 2 : 0);
+  const int length = kVariablePartIndex + parameter_count + stack_local_count +
+                     2 * context_local_count +
+                     3 * strong_mode_free_variable_count +
+                     (has_function_name ? 2 : 0);
 
   Factory* factory = isolate->factory();
   Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
@@ -64,11 +70,14 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
               FunctionVariableMode::encode(function_variable_mode) |
               AsmModuleField::encode(scope->asm_module()) |
               AsmFunctionField::encode(scope->asm_function()) |
-              IsSimpleParameterListField::encode(simple_parameter_list);
+              IsSimpleParameterListField::encode(simple_parameter_list) |
+              BlockScopeIsClassScopeField::encode(scope->is_class_scope()) |
+              FunctionKindField::encode(scope->function_kind());
   scope_info->SetFlags(flags);
   scope_info->SetParameterCount(parameter_count);
   scope_info->SetStackLocalCount(stack_local_count);
   scope_info->SetContextLocalCount(context_local_count);
+  scope_info->SetStrongModeFreeVariableCount(strong_mode_free_variable_count);
 
   int index = kVariablePartIndex;
   // Add parameters.
@@ -111,6 +120,25 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
     scope_info->set(index++, Smi::FromInt(value));
   }
 
+  DCHECK(index == scope_info->StrongModeFreeVariableNameEntriesIndex());
+  for (int i = 0; i < strong_mode_free_variable_count; ++i) {
+    scope_info->set(index++, *strong_mode_free_variables[i]->name());
+  }
+
+  DCHECK(index == scope_info->StrongModeFreeVariablePositionEntriesIndex());
+  for (int i = 0; i < strong_mode_free_variable_count; ++i) {
+    // Unfortunately, the source code positions are stored as int even though
+    // int32_t would be enough (given the maximum source code length).
+    Handle<Object> start_position = factory->NewNumberFromInt(
+        static_cast<int32_t>(strong_mode_free_variables[i]
+                                 ->strong_mode_reference_start_position()));
+    scope_info->set(index++, *start_position);
+    Handle<Object> end_position = factory->NewNumberFromInt(
+        static_cast<int32_t>(strong_mode_free_variables[i]
+                                 ->strong_mode_reference_end_position()));
+    scope_info->set(index++, *end_position);
+  }
+
   // If present, add the function variable name and its index.
   DCHECK(index == scope_info->FunctionNameEntryIndex());
   if (has_function_name) {
@@ -283,6 +311,35 @@ bool ScopeInfo::LocalIsSynthetic(int var) {
 }
 
 
+String* ScopeInfo::StrongModeFreeVariableName(int var) {
+  DCHECK(0 <= var && var < StrongModeFreeVariableCount());
+  int info_index = StrongModeFreeVariableNameEntriesIndex() + var;
+  return String::cast(get(info_index));
+}
+
+
+int ScopeInfo::StrongModeFreeVariableStartPosition(int var) {
+  DCHECK(0 <= var && var < StrongModeFreeVariableCount());
+  int info_index = StrongModeFreeVariablePositionEntriesIndex() + var * 2;
+  int32_t value = 0;
+  bool ok = get(info_index)->ToInt32(&value);
+  USE(ok);
+  DCHECK(ok);
+  return value;
+}
+
+
+int ScopeInfo::StrongModeFreeVariableEndPosition(int var) {
+  DCHECK(0 <= var && var < StrongModeFreeVariableCount());
+  int info_index = StrongModeFreeVariablePositionEntriesIndex() + var * 2 + 1;
+  int32_t value = 0;
+  bool ok = get(info_index)->ToInt32(&value);
+  USE(ok);
+  DCHECK(ok);
+  return value;
+}
+
+
 int ScopeInfo::StackSlotIndex(String* name) {
   DCHECK(name->IsInternalizedString());
   if (length() > 0) {
@@ -373,6 +430,16 @@ int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
 }
 
 
+bool ScopeInfo::block_scope_is_class_scope() {
+  return BlockScopeIsClassScopeField::decode(Flags());
+}
+
+
+FunctionKind ScopeInfo::function_kind() {
+  return FunctionKindField::decode(Flags());
+}
+
+
 bool ScopeInfo::CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
                                                Handle<Context> context,
                                                Handle<JSObject> scope_object) {
@@ -420,11 +487,23 @@ int ScopeInfo::ContextLocalInfoEntriesIndex() {
 }
 
 
-int ScopeInfo::FunctionNameEntryIndex() {
+int ScopeInfo::StrongModeFreeVariableNameEntriesIndex() {
   return ContextLocalInfoEntriesIndex() + ContextLocalCount();
 }
 
 
+int ScopeInfo::StrongModeFreeVariablePositionEntriesIndex() {
+  return StrongModeFreeVariableNameEntriesIndex() +
+         StrongModeFreeVariableCount();
+}
+
+
+int ScopeInfo::FunctionNameEntryIndex() {
+  return StrongModeFreeVariablePositionEntriesIndex() +
+         2 * StrongModeFreeVariableCount();
+}
+
+
 int ContextSlotCache::Hash(Object* data, String* name) {
   // Uses only lower 32 bits if pointers are larger.
   uintptr_t addr_hash =
@@ -560,8 +639,8 @@ Handle<ModuleInfo> ModuleInfo::Create(Isolate* isolate,
   int i = 0;
   for (ModuleDescriptor::Iterator it = descriptor->iterator(); !it.done();
        it.Advance(), ++i) {
-    Variable* var = scope->LookupLocal(it.name());
-    info->set_name(i, *(it.name()->string()));
+    Variable* var = scope->LookupLocal(it.local_name());
+    info->set_name(i, *(it.export_name()->string()));
     info->set_mode(i, var->mode());
     DCHECK(var->index() >= 0);
     info->set_index(i, var->index());
index 3544964..3d46d15 100644 (file)
@@ -4,13 +4,12 @@
 
 #include "src/v8.h"
 
-#include "src/scopes.h"
-
 #include "src/accessors.h"
 #include "src/bootstrapper.h"
-#include "src/compiler.h"
 #include "src/messages.h"
+#include "src/parser.h"
 #include "src/scopeinfo.h"
+#include "src/scopes.h"
 
 namespace v8 {
 namespace internal {
@@ -31,8 +30,7 @@ VariableMap::~VariableMap() {}
 
 
 Variable* VariableMap::Declare(Scope* scope, const AstRawString* name,
-                               VariableMode mode, bool is_valid_lhs,
-                               Variable::Kind kind,
+                               VariableMode mode, Variable::Kind kind,
                                InitializationFlag initialization_flag,
                                MaybeAssignedFlag maybe_assigned_flag) {
   // AstRawStrings are unambiguous, i.e., the same string is always represented
@@ -43,7 +41,7 @@ Variable* VariableMap::Declare(Scope* scope, const AstRawString* name,
   if (p->value == NULL) {
     // The variable has not been declared yet -> insert it.
     DCHECK(p->key == name);
-    p->value = new (zone()) Variable(scope, name, mode, is_valid_lhs, kind,
+    p->value = new (zone()) Variable(scope, name, mode, kind,
                                      initialization_flag, maybe_assigned_flag);
   }
   return reinterpret_cast<Variable*>(p->value);
@@ -66,7 +64,7 @@ Variable* VariableMap::Lookup(const AstRawString* name) {
 // Implementation of Scope
 
 Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type,
-             AstValueFactory* ast_value_factory)
+             AstValueFactory* ast_value_factory, FunctionKind function_kind)
     : inner_scopes_(4, zone),
       variables_(zone),
       internals_(4, zone),
@@ -79,7 +77,8 @@ Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type,
       already_resolved_(false),
       ast_value_factory_(ast_value_factory),
       zone_(zone) {
-  SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null());
+  SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null(),
+              function_kind);
   // The outermost scope must be a script scope.
   DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL);
   DCHECK(!HasIllegalRedeclaration());
@@ -131,18 +130,19 @@ Scope::Scope(Zone* zone, Scope* inner_scope,
   Variable* variable = variables_.Declare(this,
                                           catch_variable_name,
                                           VAR,
-                                          true,  // Valid left-hand side.
                                           Variable::NORMAL,
                                           kCreatedInitialized);
   AllocateHeapSlot(variable);
 }
 
 
-void Scope::SetDefaults(ScopeType scope_type,
-                        Scope* outer_scope,
-                        Handle<ScopeInfo> scope_info) {
+void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope,
+                        Handle<ScopeInfo> scope_info,
+                        FunctionKind function_kind) {
   outer_scope_ = outer_scope;
   scope_type_ = scope_type;
+  function_kind_ = function_kind;
+  block_scope_is_class_scope_ = false;
   scope_name_ = ast_value_factory_->empty_string();
   dynamics_ = NULL;
   receiver_ = NULL;
@@ -181,6 +181,8 @@ void Scope::SetDefaults(ScopeType scope_type,
   if (!scope_info.is_null()) {
     scope_calls_eval_ = scope_info->CallsEval();
     language_mode_ = scope_info->language_mode();
+    block_scope_is_class_scope_ = scope_info->block_scope_is_class_scope();
+    function_kind_ = scope_info->function_kind();
   }
 }
 
@@ -248,8 +250,9 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
 }
 
 
-bool Scope::Analyze(CompilationInfo* info) {
+bool Scope::Analyze(ParseInfo* info) {
   DCHECK(info->function() != NULL);
+  DCHECK(info->scope() == NULL);
   Scope* scope = info->function()->scope();
   Scope* top = scope;
 
@@ -263,7 +266,12 @@ bool Scope::Analyze(CompilationInfo* info) {
   // Allocate the variables.
   {
     AstNodeFactory ast_node_factory(info->ast_value_factory());
-    if (!top->AllocateVariables(info, &ast_node_factory)) return false;
+    if (!top->AllocateVariables(info, &ast_node_factory)) {
+      DCHECK(top->pending_error_handler_.has_pending_error());
+      top->pending_error_handler_.ThrowPendingError(info->isolate(),
+                                                    info->script());
+      return false;
+    }
   }
 
 #ifdef DEBUG
@@ -274,12 +282,13 @@ bool Scope::Analyze(CompilationInfo* info) {
   }
 #endif
 
-  info->PrepareForCompilation(scope);
+  info->set_scope(scope);
   return true;
 }
 
 
-void Scope::Initialize(bool subclass_constructor) {
+void Scope::Initialize() {
+  bool subclass_constructor = IsSubclassConstructor(function_kind_);
   DCHECK(!already_resolved());
 
   // Add this scope as a new inner scope of the outer scope.
@@ -302,15 +311,15 @@ void Scope::Initialize(bool subclass_constructor) {
     DCHECK(!subclass_constructor || is_function_scope());
     Variable* var = variables_.Declare(
         this, ast_value_factory_->this_string(),
-        subclass_constructor ? CONST : VAR, false, Variable::THIS,
+        subclass_constructor ? CONST : VAR, Variable::THIS,
         subclass_constructor ? kNeedsInitialization : kCreatedInitialized);
     var->AllocateTo(Variable::PARAMETER, -1);
     receiver_ = var;
 
     if (subclass_constructor) {
-      new_target_ = variables_.Declare(
-          this, ast_value_factory_->new_target_string(), CONST, false,
-          Variable::NEW_TARGET, kCreatedInitialized);
+      new_target_ =
+          variables_.Declare(this, ast_value_factory_->new_target_string(),
+                             CONST, Variable::NEW_TARGET, kCreatedInitialized);
       new_target_->AllocateTo(Variable::PARAMETER, -2);
       new_target_->set_is_used();
     }
@@ -326,7 +335,6 @@ void Scope::Initialize(bool subclass_constructor) {
     variables_.Declare(this,
                        ast_value_factory_->arguments_string(),
                        VAR,
-                       true,
                        Variable::ARGUMENTS,
                        kCreatedInitialized);
   }
@@ -402,7 +410,7 @@ Variable* Scope::LookupLocal(const AstRawString* name) {
     maybe_assigned_flag = kMaybeAssigned;
   }
 
-  Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL,
+  Variable* var = variables_.Declare(this, name, mode, Variable::NORMAL,
                                      init_flag, maybe_assigned_flag);
   var->AllocateTo(location, index);
   return var;
@@ -418,9 +426,8 @@ Variable* Scope::LookupFunctionVar(const AstRawString* name,
     VariableMode mode;
     int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode);
     if (index < 0) return NULL;
-    Variable* var = new(zone()) Variable(
-        this, name, mode, true /* is valid LHS */,
-        Variable::NORMAL, kCreatedInitialized);
+    Variable* var = new (zone())
+        Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized);
     VariableProxy* proxy = factory->NewVariableProxy(var);
     VariableDeclaration* declaration = factory->NewVariableDeclaration(
         proxy, mode, this, RelocInfo::kNoPosition);
@@ -448,7 +455,7 @@ Variable* Scope::DeclareParameter(const AstRawString* name, VariableMode mode,
                                   bool is_rest) {
   DCHECK(!already_resolved());
   DCHECK(is_function_scope());
-  Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL,
+  Variable* var = variables_.Declare(this, name, mode, Variable::NORMAL,
                                      kCreatedInitialized);
   if (is_rest) {
     DCHECK_NULL(rest_parameter_);
@@ -461,7 +468,7 @@ Variable* Scope::DeclareParameter(const AstRawString* name, VariableMode mode,
 
 
 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
-                              InitializationFlag init_flag,
+                              InitializationFlag init_flag, Variable::Kind kind,
                               MaybeAssignedFlag maybe_assigned_flag) {
   DCHECK(!already_resolved());
   // This function handles VAR, LET, and CONST modes.  DYNAMIC variables are
@@ -469,7 +476,7 @@ Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
   // explicitly, and TEMPORARY variables are allocated via NewTemporary().
   DCHECK(IsDeclaredVariableMode(mode));
   ++num_var_or_const_;
-  return variables_.Declare(this, name, mode, true, Variable::NORMAL, init_flag,
+  return variables_.Declare(this, name, mode, kind, init_flag,
                             maybe_assigned_flag);
 }
 
@@ -479,7 +486,6 @@ Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) {
   return variables_.Declare(this,
                             name,
                             DYNAMIC_GLOBAL,
-                            true,
                             Variable::NORMAL,
                             kCreatedInitialized);
 }
@@ -502,7 +508,6 @@ Variable* Scope::NewInternal(const AstRawString* name) {
   Variable* var = new(zone()) Variable(this,
                                        name,
                                        INTERNAL,
-                                       false,
                                        Variable::NORMAL,
                                        kCreatedInitialized);
   internals_.Add(var, zone());
@@ -515,7 +520,6 @@ Variable* Scope::NewTemporary(const AstRawString* name) {
   Variable* var = new(zone()) Variable(this,
                                        name,
                                        TEMPORARY,
-                                       true,
                                        Variable::NORMAL,
                                        kCreatedInitialized);
   temps_.Add(var, zone());
@@ -582,8 +586,9 @@ class VarAndOrder {
 };
 
 
-void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals,
-                                         ZoneList<Variable*>* context_locals) {
+void Scope::CollectStackAndContextLocals(
+    ZoneList<Variable*>* stack_locals, ZoneList<Variable*>* context_locals,
+    ZoneList<Variable*>* strong_mode_free_variables) {
   DCHECK(stack_locals != NULL);
   DCHECK(context_locals != NULL);
 
@@ -617,6 +622,11 @@ void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals,
        p != NULL;
        p = variables_.Next(p)) {
     Variable* var = reinterpret_cast<Variable*>(p->value);
+    if (strong_mode_free_variables && var->has_strong_mode_reference() &&
+        var->mode() == DYNAMIC_GLOBAL) {
+      strong_mode_free_variables->Add(var, zone());
+    }
+
     if (var->is_used()) {
       vars.Add(VarAndOrder(var, p->order), zone());
     }
@@ -634,7 +644,7 @@ void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals,
 }
 
 
-bool Scope::AllocateVariables(CompilationInfo* info, AstNodeFactory* factory) {
+bool Scope::AllocateVariables(ParseInfo* info, AstNodeFactory* factory) {
   // 1) Propagate scope information.
   bool outer_scope_calls_sloppy_eval = false;
   if (outer_scope_ != NULL) {
@@ -645,9 +655,9 @@ bool Scope::AllocateVariables(CompilationInfo* info, AstNodeFactory* factory) {
   PropagateScopeInfo(outer_scope_calls_sloppy_eval);
 
   // 2) Allocate module instances.
-  if (FLAG_harmony_modules && (is_script_scope() || is_module_scope())) {
+  if (FLAG_harmony_modules && is_script_scope()) {
     DCHECK(num_modules_ == 0);
-    AllocateModulesRecursively(this);
+    AllocateModules();
   }
 
   // 3) Resolve variables.
@@ -768,6 +778,20 @@ void Scope::GetNestedScopeChain(Isolate* isolate,
 }
 
 
+void Scope::ReportMessage(int start_position, int end_position,
+                          const char* message, const AstRawString* arg) {
+  // Propagate the error to the topmost scope targeted by this scope analysis
+  // phase.
+  Scope* top = this;
+  while (!top->is_script_scope() && !top->outer_scope()->already_resolved()) {
+    top = top->outer_scope();
+  }
+
+  top->pending_error_handler_.ReportMessageAt(start_position, end_position,
+                                              message, arg, kReferenceError);
+}
+
+
 #ifdef DEBUG
 static const char* Header(ScopeType scope_type) {
   switch (scope_type) {
@@ -962,7 +986,6 @@ Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) {
     var = map->Declare(NULL,
                        name,
                        mode,
-                       true,
                        Variable::NORMAL,
                        init_flag);
     // Allocate it by giving it a dynamic lookup.
@@ -1036,7 +1059,7 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy,
 }
 
 
-bool Scope::ResolveVariable(CompilationInfo* info, VariableProxy* proxy,
+bool Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy,
                             AstNodeFactory* factory) {
   DCHECK(info->script_scope()->is_script_scope());
 
@@ -1050,6 +1073,9 @@ bool Scope::ResolveVariable(CompilationInfo* info, VariableProxy* proxy,
   switch (binding_kind) {
     case BOUND:
       // We found a variable binding.
+      if (is_strong(language_mode())) {
+        if (!CheckStrongModeDeclaration(proxy, var)) return false;
+      }
       break;
 
     case BOUND_EVAL_SHADOWED:
@@ -1087,13 +1113,70 @@ bool Scope::ResolveVariable(CompilationInfo* info, VariableProxy* proxy,
   DCHECK(var != NULL);
   if (proxy->is_assigned()) var->set_maybe_assigned();
 
+  if (is_strong(language_mode())) {
+    // Record that the variable is referred to from strong mode. Also, record
+    // the position.
+    var->RecordStrongModeReference(proxy->position(), proxy->end_position());
+  }
+
   proxy->BindTo(var);
 
   return true;
 }
 
 
-bool Scope::ResolveVariablesRecursively(CompilationInfo* info,
+bool Scope::CheckStrongModeDeclaration(VariableProxy* proxy, Variable* var) {
+  // Check for declaration-after use (for variables) in strong mode. Note that
+  // we can only do this in the case where we have seen the declaration. And we
+  // always allow referencing functions (for now).
+
+  // Allow referencing the class name from methods of that class, even though
+  // the initializer position for class names is only after the body.
+  Scope* scope = this;
+  while (scope) {
+    if (scope->ClassVariableForMethod() == var) return true;
+    scope = scope->outer_scope();
+  }
+
+  // If both the use and the declaration are inside an eval scope (possibly
+  // indirectly), or one of them is, we need to check whether they are inside
+  // the same eval scope or different ones.
+
+  // TODO(marja,rossberg): Detect errors across different evals (depends on the
+  // future of eval in strong mode).
+  const Scope* eval_for_use = NearestOuterEvalScope();
+  const Scope* eval_for_declaration = var->scope()->NearestOuterEvalScope();
+
+  if (proxy->position() != RelocInfo::kNoPosition &&
+      proxy->position() < var->initializer_position() && !var->is_function() &&
+      eval_for_use == eval_for_declaration) {
+    DCHECK(proxy->end_position() != RelocInfo::kNoPosition);
+    ReportMessage(proxy->position(), proxy->end_position(),
+                  "strong_use_before_declaration", proxy->raw_name());
+    return false;
+  }
+  return true;
+}
+
+
+Variable* Scope::ClassVariableForMethod() const {
+  if (!is_function_scope()) return nullptr;
+  if (IsInObjectLiteral(function_kind_)) return nullptr;
+  if (!IsConciseMethod(function_kind_) && !IsConstructor(function_kind_) &&
+      !IsAccessorFunction(function_kind_)) {
+    return nullptr;
+  }
+  DCHECK_NOT_NULL(outer_scope_);
+  DCHECK(outer_scope_->is_class_scope());
+  // The class scope contains at most one variable, the class name.
+  DCHECK(outer_scope_->variables_.occupancy() <= 1);
+  if (outer_scope_->variables_.occupancy() == 0) return nullptr;
+  VariableMap::Entry* p = outer_scope_->variables_.Start();
+  return reinterpret_cast<Variable*>(p->value);
+}
+
+
+bool Scope::ResolveVariablesRecursively(ParseInfo* info,
                                         AstNodeFactory* factory) {
   DCHECK(info->script_scope()->is_script_scope());
 
@@ -1358,19 +1441,18 @@ void Scope::AllocateVariablesRecursively(Isolate* isolate) {
 }
 
 
-void Scope::AllocateModulesRecursively(Scope* host_scope) {
-  if (already_resolved()) return;
-  if (is_module_scope()) {
-    DCHECK(module_descriptor_->IsFrozen());
-    DCHECK(module_var_ == NULL);
-    module_var_ =
-        host_scope->NewInternal(ast_value_factory_->dot_module_string());
-    ++host_scope->num_modules_;
-  }
-
+void Scope::AllocateModules() {
+  DCHECK(is_script_scope());
+  DCHECK(!already_resolved());
   for (int i = 0; i < inner_scopes_.length(); i++) {
-    Scope* inner_scope = inner_scopes_.at(i);
-    inner_scope->AllocateModulesRecursively(host_scope);
+    Scope* scope = inner_scopes_.at(i);
+    if (scope->is_module_scope()) {
+      DCHECK(!scope->already_resolved());
+      DCHECK(scope->module_descriptor_->IsFrozen());
+      DCHECK_NULL(scope->module_var_);
+      scope->module_var_ = NewInternal(ast_value_factory_->dot_module_string());
+      ++num_modules_;
+    }
   }
 }
 
@@ -1386,5 +1468,4 @@ int Scope::ContextLocalCount() const {
   return num_heap_slots() - Context::MIN_CONTEXT_SLOTS -
       (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0);
 }
-
 } }  // namespace v8::internal
index c58d124..cce8c3c 100644 (file)
@@ -6,13 +6,13 @@
 #define V8_SCOPES_H_
 
 #include "src/ast.h"
+#include "src/pending-compilation-error-handler.h"
 #include "src/zone.h"
 
 namespace v8 {
 namespace internal {
 
-class CompilationInfo;
-
+class ParseInfo;
 
 // A hash map to support fast variable declaration and lookup.
 class VariableMap: public ZoneHashMap {
@@ -22,8 +22,7 @@ class VariableMap: public ZoneHashMap {
   virtual ~VariableMap();
 
   Variable* Declare(Scope* scope, const AstRawString* name, VariableMode mode,
-                    bool is_valid_lhs, Variable::Kind kind,
-                    InitializationFlag initialization_flag,
+                    Variable::Kind kind, InitializationFlag initialization_flag,
                     MaybeAssignedFlag maybe_assigned_flag = kNotAssigned);
 
   Variable* Lookup(const AstRawString* name);
@@ -72,12 +71,13 @@ class Scope: public ZoneObject {
   // Construction
 
   Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type,
-        AstValueFactory* value_factory);
+        AstValueFactory* value_factory,
+        FunctionKind function_kind = kNormalFunction);
 
   // Compute top scope and allocate variables. For lazy compilation the top
   // scope only contains the single lazily compiled function, so this
   // doesn't re-allocate variables repeatedly.
-  static bool Analyze(CompilationInfo* info);
+  static bool Analyze(ParseInfo* info);
 
   static Scope* DeserializeScopeChain(Isolate* isolate, Zone* zone,
                                       Context* context, Scope* script_scope);
@@ -87,7 +87,7 @@ class Scope: public ZoneObject {
     scope_name_ = scope_name;
   }
 
-  void Initialize(bool subclass_constructor = false);
+  void Initialize();
 
   // Checks if the block scope is redundant, i.e. it does not contain any
   // block scoped declarations. In that case it is removed from the scope
@@ -130,7 +130,7 @@ class Scope: public ZoneObject {
   // Declare a local variable in this scope. If the variable has been
   // declared before, the previously declared variable is returned.
   Variable* DeclareLocal(const AstRawString* name, VariableMode mode,
-                         InitializationFlag init_flag,
+                         InitializationFlag init_flag, Variable::Kind kind,
                          MaybeAssignedFlag maybe_assigned_flag = kNotAssigned);
 
   // Declare an implicit global variable in this scope which must be a
@@ -142,12 +142,14 @@ class Scope: public ZoneObject {
   // Create a new unresolved variable.
   VariableProxy* NewUnresolved(AstNodeFactory* factory,
                                const AstRawString* name,
-                               int position = RelocInfo::kNoPosition) {
+                               int start_position = RelocInfo::kNoPosition,
+                               int end_position = RelocInfo::kNoPosition) {
     // Note that we must not share the unresolved variables with
     // the same name because they may be removed selectively via
     // RemoveUnresolved().
     DCHECK(!already_resolved());
-    VariableProxy* proxy = factory->NewVariableProxy(name, false, position);
+    VariableProxy* proxy = factory->NewVariableProxy(
+        name, Variable::NORMAL, start_position, end_position);
     unresolved_.Add(proxy, zone_);
     return proxy;
   }
@@ -278,6 +280,13 @@ class Scope: public ZoneObject {
   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; }
+  void tag_as_class_scope() {
+    DCHECK(is_block_scope());
+    block_scope_is_class_scope_ = true;
+  }
+  bool is_class_scope() const {
+    return is_block_scope() && block_scope_is_class_scope_;
+  }
   bool is_declaration_scope() const {
     return is_eval_scope() || is_function_scope() ||
         is_module_scope() || is_script_scope();
@@ -317,12 +326,20 @@ class Scope: public ZoneObject {
   // Does any inner scope access "this".
   bool inner_uses_this() const { return inner_scope_uses_this_; }
 
+  const Scope* NearestOuterEvalScope() const {
+    if (is_eval_scope()) return this;
+    if (outer_scope() == nullptr) return nullptr;
+    return outer_scope()->NearestOuterEvalScope();
+  }
+
   // ---------------------------------------------------------------------------
   // Accessors.
 
   // The type of this scope.
   ScopeType scope_type() const { return scope_type_; }
 
+  FunctionKind function_kind() const { return function_kind_; }
+
   // The language mode of this scope.
   LanguageMode language_mode() const { return language_mode_; }
 
@@ -397,8 +414,9 @@ class Scope: public ZoneObject {
   // Collect stack and context allocated local variables in this scope. Note
   // that the function variable - if present - is not collected and should be
   // handled separately.
-  void CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals,
-                                    ZoneList<Variable*>* context_locals);
+  void CollectStackAndContextLocals(
+      ZoneList<Variable*>* stack_locals, ZoneList<Variable*>* context_locals,
+      ZoneList<Variable*>* strong_mode_free_variables = nullptr);
 
   // Current number of var or const locals.
   int num_var_or_const() { return num_var_or_const_; }
@@ -470,6 +488,10 @@ class Scope: public ZoneObject {
     return params_.Contains(variables_.Lookup(name));
   }
 
+  // Error handling.
+  void ReportMessage(int start_position, int end_position, const char* message,
+                     const AstRawString* arg);
+
   // ---------------------------------------------------------------------------
   // Debugging.
 
@@ -488,6 +510,10 @@ class Scope: public ZoneObject {
 
   // The scope type.
   ScopeType scope_type_;
+  // Some block scopes are tagged as class scopes.
+  bool block_scope_is_class_scope_;
+  // If the scope is a function scope, this is the function kind.
+  FunctionKind function_kind_;
 
   // Debugging support.
   const AstRawString* scope_name_;
@@ -639,11 +665,16 @@ class Scope: public ZoneObject {
   Variable* LookupRecursive(VariableProxy* proxy, BindingKind* binding_kind,
                             AstNodeFactory* factory);
   MUST_USE_RESULT
-  bool ResolveVariable(CompilationInfo* info, VariableProxy* proxy,
+  bool ResolveVariable(ParseInfo* info, VariableProxy* proxy,
                        AstNodeFactory* factory);
   MUST_USE_RESULT
-  bool ResolveVariablesRecursively(CompilationInfo* info,
-                                   AstNodeFactory* factory);
+  bool ResolveVariablesRecursively(ParseInfo* info, AstNodeFactory* factory);
+
+  bool CheckStrongModeDeclaration(VariableProxy* proxy, Variable* var);
+
+  // If this scope is a method scope of a class, return the corresponding
+  // class variable, otherwise nullptr.
+  Variable* ClassVariableForMethod() const;
 
   // Scope analysis.
   void PropagateScopeInfo(bool outer_scope_calls_sloppy_eval);
@@ -661,7 +692,7 @@ class Scope: public ZoneObject {
   void AllocateNonParameterLocal(Isolate* isolate, Variable* var);
   void AllocateNonParameterLocals(Isolate* isolate);
   void AllocateVariablesRecursively(Isolate* isolate);
-  void AllocateModulesRecursively(Scope* host_scope);
+  void AllocateModules();
 
   // Resolve and fill in the allocation information for all variables
   // in this scopes. Must be called *after* all scopes have been
@@ -672,7 +703,7 @@ class Scope: public ZoneObject {
   // 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* factory);
+  bool AllocateVariables(ParseInfo* info, AstNodeFactory* factory);
 
  private:
   // Construct a scope based on the scope info.
@@ -690,12 +721,14 @@ class Scope: public ZoneObject {
     }
   }
 
-  void SetDefaults(ScopeType type,
-                   Scope* outer_scope,
-                   Handle<ScopeInfo> scope_info);
+  void SetDefaults(ScopeType type, Scope* outer_scope,
+                   Handle<ScopeInfo> scope_info,
+                   FunctionKind function_kind = kNormalFunction);
 
   AstValueFactory* ast_value_factory_;
   Zone* zone_;
+
+  PendingCompilationErrorHandler pending_error_handler_;
 };
 
 } }  // namespace v8::internal
diff --git a/deps/v8/src/snapshot/DEPS b/deps/v8/src/snapshot/DEPS
new file mode 100644 (file)
index 0000000..810dfd6
--- /dev/null
@@ -0,0 +1,5 @@
+specific_include_rules = {
+  "mksnapshot\.cc": [
+    "+include/libplatform/libplatform.h",
+  ],
+}
similarity index 89%
rename from deps/v8/src/mksnapshot.cc
rename to deps/v8/src/snapshot/mksnapshot.cc
index bc18aeb..79c1643 100644 (file)
@@ -14,8 +14,8 @@
 #include "src/bootstrapper.h"
 #include "src/flags.h"
 #include "src/list.h"
-#include "src/natives.h"
-#include "src/serialize.h"
+#include "src/snapshot/natives.h"
+#include "src/snapshot/serialize.h"
 
 
 using namespace v8;
@@ -64,17 +64,14 @@ class SnapshotWriter {
     fprintf(fp_, "// Autogenerated snapshot file. Do not edit.\n\n");
     fprintf(fp_, "#include \"src/v8.h\"\n");
     fprintf(fp_, "#include \"src/base/platform/platform.h\"\n\n");
-    fprintf(fp_, "#include \"src/snapshot.h\"\n\n");
+    fprintf(fp_, "#include \"src/snapshot/snapshot.h\"\n\n");
     fprintf(fp_, "namespace v8 {\n");
     fprintf(fp_, "namespace internal {\n\n");
   }
 
   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_, "const v8::StartupData* Snapshot::DefaultSnapshotBlob() {\n");
+    fprintf(fp_, "  return &blob;\n");
     fprintf(fp_, "}\n\n");
     fprintf(fp_, "}  // namespace internal\n");
     fprintf(fp_, "}  // namespace v8\n");
@@ -85,7 +82,8 @@ class SnapshotWriter {
     WriteSnapshotData(blob);
     fprintf(fp_, "};\n");
     fprintf(fp_, "static const int blob_size = %d;\n", blob.length());
-    fprintf(fp_, "\n");
+    fprintf(fp_, "static const v8::StartupData blob =\n");
+    fprintf(fp_, "{ (const char*) blob_data, blob_size };\n");
   }
 
   void WriteSnapshotData(const i::Vector<const i::byte>& blob) const {
@@ -140,11 +138,6 @@ char* GetExtraCode(char* filename) {
 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
similarity index 84%
rename from deps/v8/src/natives-external.cc
rename to deps/v8/src/snapshot/natives-external.cc
index e601808..14def47 100644 (file)
@@ -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/natives.h"
+#include "src/snapshot/natives.h"
 
 #include "src/base/logging.h"
 #include "src/list.h"
 #include "src/list-inl.h"
-#include "src/snapshot-source-sink.h"
+#include "src/snapshot/snapshot-source-sink.h"
 #include "src/vector.h"
 
 #ifndef V8_USE_EXTERNAL_STARTUP_DATA
@@ -132,6 +132,11 @@ class NativesHolder {
     DCHECK(store);
     holder_ = store;
   }
+  static bool empty() { return holder_ == NULL; }
+  static void Dispose() {
+    delete holder_;
+    holder_ = NULL;
+  }
 
  private:
   static NativesStore* holder_;
@@ -141,19 +146,45 @@ template<NativeType type>
 NativesStore* NativesHolder<type>::holder_ = NULL;
 
 
+// The natives blob. Memory is owned by caller.
+static StartupData* natives_blob_ = NULL;
+
+
+/**
+ * Read the Natives blob, as previously set by SetNativesFromFile.
+ */
+void ReadNatives() {
+  if (natives_blob_ && NativesHolder<CORE>::empty()) {
+    SnapshotByteSource bytes(natives_blob_->data, natives_blob_->raw_size);
+    NativesHolder<CORE>::set(NativesStore::MakeFromScriptsSource(&bytes));
+    NativesHolder<EXPERIMENTAL>::set(
+        NativesStore::MakeFromScriptsSource(&bytes));
+    DCHECK(!bytes.HasMore());
+  }
+}
+
+
 /**
- * Read the Natives (library sources) blob, as generated by js2c + the build
+ * Set the Natives (library sources) blob, as generated by js2c + the build
  * system.
  */
 void SetNativesFromFile(StartupData* natives_blob) {
+  DCHECK(!natives_blob_);
   DCHECK(natives_blob);
   DCHECK(natives_blob->data);
   DCHECK(natives_blob->raw_size > 0);
 
-  SnapshotByteSource bytes(natives_blob->data, natives_blob->raw_size);
-  NativesHolder<CORE>::set(NativesStore::MakeFromScriptsSource(&bytes));
-  NativesHolder<EXPERIMENTAL>::set(NativesStore::MakeFromScriptsSource(&bytes));
-  DCHECK(!bytes.HasMore());
+  natives_blob_ = natives_blob;
+  ReadNatives();
+}
+
+
+/**
+ * Release memory allocated by SetNativesFromFile.
+ */
+void DisposeNatives() {
+  NativesHolder<CORE>::Dispose();
+  NativesHolder<EXPERIMENTAL>::Dispose();
 }
 
 
similarity index 96%
rename from deps/v8/src/natives.h
rename to deps/v8/src/snapshot/natives.h
index 7ce7213..357faad 100644 (file)
@@ -40,6 +40,8 @@ typedef NativesCollection<EXPERIMENTAL> ExperimentalNatives;
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
 // Used for reading the natives at runtime. Implementation in natives-empty.cc
 void SetNativesFromFile(StartupData* natives_blob);
+void ReadNatives();
+void DisposeNatives();
 #endif
 
 } }  // namespace v8::internal
similarity index 82%
rename from deps/v8/src/serialize.cc
rename to deps/v8/src/snapshot/serialize.cc
index 8048f41..13ac04d 100644 (file)
@@ -9,18 +9,19 @@
 #include "src/base/platform/platform.h"
 #include "src/bootstrapper.h"
 #include "src/code-stubs.h"
-#include "src/compiler.h"
+#include "src/cpu-profiler.h"
 #include "src/deoptimizer.h"
 #include "src/execution.h"
 #include "src/global-handles.h"
 #include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
-#include "src/natives.h"
 #include "src/objects.h"
+#include "src/parser.h"
 #include "src/runtime/runtime.h"
-#include "src/serialize.h"
-#include "src/snapshot.h"
-#include "src/snapshot-source-sink.h"
+#include "src/snapshot/natives.h"
+#include "src/snapshot/serialize.h"
+#include "src/snapshot/snapshot.h"
+#include "src/snapshot/snapshot-source-sink.h"
 #include "src/v8threads.h"
 #include "src/version.h"
 
@@ -31,20 +32,6 @@ namespace internal {
 // -----------------------------------------------------------------------------
 // Coding of external references.
 
-// The encoding of an external reference. The type is in the high word.
-// The id is in the low word.
-static uint32_t EncodeExternal(TypeCode type, uint16_t id) {
-  return static_cast<uint32_t>(type) << 16 | id;
-}
-
-
-static int* GetInternalPointer(StatsCounter* counter) {
-  // All counters refer to dummy_counter, if deserializing happens without
-  // setting up counters.
-  static int dummy_counter = 0;
-  return counter->Enabled() ? counter->GetInternalPointer() : &dummy_counter;
-}
-
 
 ExternalReferenceTable* ExternalReferenceTable::instance(Isolate* isolate) {
   ExternalReferenceTable* external_reference_table =
@@ -57,63 +44,7 @@ ExternalReferenceTable* ExternalReferenceTable::instance(Isolate* isolate) {
 }
 
 
-void ExternalReferenceTable::AddFromId(TypeCode type,
-                                       uint16_t id,
-                                       const char* name,
-                                       Isolate* isolate) {
-  Address address;
-  switch (type) {
-    case C_BUILTIN: {
-      ExternalReference ref(static_cast<Builtins::CFunctionId>(id), isolate);
-      address = ref.address();
-      break;
-    }
-    case BUILTIN: {
-      ExternalReference ref(static_cast<Builtins::Name>(id), isolate);
-      address = ref.address();
-      break;
-    }
-    case RUNTIME_FUNCTION: {
-      ExternalReference ref(static_cast<Runtime::FunctionId>(id), isolate);
-      address = ref.address();
-      break;
-    }
-    case IC_UTILITY: {
-      ExternalReference ref(IC_Utility(static_cast<IC::UtilityId>(id)),
-                            isolate);
-      address = ref.address();
-      break;
-    }
-    default:
-      UNREACHABLE();
-      return;
-  }
-  Add(address, type, id, name);
-}
-
-
-void ExternalReferenceTable::Add(Address address,
-                                 TypeCode type,
-                                 uint16_t id,
-                                 const char* name) {
-  DCHECK_NOT_NULL(address);
-  ExternalReferenceEntry entry;
-  entry.address = address;
-  entry.code = EncodeExternal(type, id);
-  entry.name = name;
-  DCHECK_NE(0u, entry.code);
-  // Assert that the code is added in ascending order to rule out duplicates.
-  DCHECK((size() == 0) || (code(size() - 1) < entry.code));
-  refs_.Add(entry);
-  if (id > max_id_[type]) max_id_[type] = id;
-}
-
-
-void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
-  for (int type_code = 0; type_code < kTypeCodeCount; type_code++) {
-    max_id_[type_code] = 0;
-  }
-
+ExternalReferenceTable::ExternalReferenceTable(Isolate* isolate) {
   // Miscellaneous
   Add(ExternalReference::roots_array_start(isolate).address(),
       "Heap::roots_array_start()");
@@ -171,17 +102,9 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
       "date_cache_stamp");
   Add(ExternalReference::address_of_pending_message_obj(isolate).address(),
       "address_of_pending_message_obj");
-  Add(ExternalReference::address_of_has_pending_message(isolate).address(),
-      "address_of_has_pending_message");
-  Add(ExternalReference::address_of_pending_message_script(isolate).address(),
-      "pending_message_script");
   Add(ExternalReference::get_make_code_young_function(isolate).address(),
       "Code::MakeCodeYoung");
   Add(ExternalReference::cpu_features().address(), "cpu_features");
-  Add(ExternalReference(Runtime::kAllocateInNewSpace, isolate).address(),
-      "Runtime::AllocateInNewSpace");
-  Add(ExternalReference(Runtime::kAllocateInTargetSpace, isolate).address(),
-      "Runtime::AllocateInTargetSpace");
   Add(ExternalReference::old_pointer_space_allocation_top_address(isolate)
           .address(),
       "Heap::OldPointerSpaceAllocationTopAddress");
@@ -217,9 +140,6 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
       "double_constants.minus_one_half");
   Add(ExternalReference::stress_deopt_count(isolate).address(),
       "Isolate::stress_deopt_count_address()");
-  Add(ExternalReference::incremental_marking_record_write_function(isolate)
-          .address(),
-      "IncrementalMarking::RecordWriteFromCode");
 
   // Debug addresses
   Add(ExternalReference::debug_after_break_target_address(isolate).address(),
@@ -259,143 +179,150 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
   // new references.
 
   struct RefTableEntry {
-    TypeCode type;
     uint16_t id;
     const char* name;
   };
 
-  static const RefTableEntry ref_table[] = {
-  // Builtins
-#define DEF_ENTRY_C(name, ignored) \
-  { C_BUILTIN, \
-    Builtins::c_##name, \
-    "Builtins::" #name },
-
-  BUILTIN_LIST_C(DEF_ENTRY_C)
+  static const RefTableEntry c_builtins[] = {
+#define DEF_ENTRY_C(name, ignored)           \
+  { Builtins::c_##name, "Builtins::" #name } \
+  ,
+      BUILTIN_LIST_C(DEF_ENTRY_C)
 #undef DEF_ENTRY_C
+  };
 
-#define DEF_ENTRY_C(name, ignored) \
-  { BUILTIN, \
-    Builtins::k##name, \
-    "Builtins::" #name },
-#define DEF_ENTRY_A(name, kind, state, extra) DEF_ENTRY_C(name, ignored)
-
-  BUILTIN_LIST_C(DEF_ENTRY_C)
-  BUILTIN_LIST_A(DEF_ENTRY_A)
-  BUILTIN_LIST_DEBUG_A(DEF_ENTRY_A)
+  for (unsigned i = 0; i < arraysize(c_builtins); ++i) {
+    ExternalReference ref(static_cast<Builtins::CFunctionId>(c_builtins[i].id),
+                          isolate);
+    Add(ref.address(), c_builtins[i].name);
+  }
+
+  static const RefTableEntry builtins[] = {
+#define DEF_ENTRY_C(name, ignored)          \
+  { Builtins::k##name, "Builtins::" #name } \
+  ,
+#define DEF_ENTRY_A(name, i1, i2, i3)       \
+  { Builtins::k##name, "Builtins::" #name } \
+  ,
+      BUILTIN_LIST_C(DEF_ENTRY_C) BUILTIN_LIST_A(DEF_ENTRY_A)
+          BUILTIN_LIST_DEBUG_A(DEF_ENTRY_A)
 #undef DEF_ENTRY_C
 #undef DEF_ENTRY_A
+  };
 
-  // Runtime functions
-#define RUNTIME_ENTRY(name, nargs, ressize) \
-  { RUNTIME_FUNCTION, \
-    Runtime::k##name, \
-    "Runtime::" #name },
+  for (unsigned i = 0; i < arraysize(builtins); ++i) {
+    ExternalReference ref(static_cast<Builtins::Name>(builtins[i].id), isolate);
+    Add(ref.address(), builtins[i].name);
+  }
 
-  RUNTIME_FUNCTION_LIST(RUNTIME_ENTRY)
-  INLINE_OPTIMIZED_FUNCTION_LIST(RUNTIME_ENTRY)
+  static const RefTableEntry runtime_functions[] = {
+#define RUNTIME_ENTRY(name, i1, i2)       \
+  { Runtime::k##name, "Runtime::" #name } \
+  ,
+      FOR_EACH_INTRINSIC(RUNTIME_ENTRY)
 #undef RUNTIME_ENTRY
+  };
 
-#define INLINE_OPTIMIZED_ENTRY(name, nargs, ressize) \
-  { RUNTIME_FUNCTION, \
-    Runtime::kInlineOptimized##name, \
-    "Runtime::" #name },
-
-  INLINE_OPTIMIZED_FUNCTION_LIST(INLINE_OPTIMIZED_ENTRY)
-#undef INLINE_OPTIMIZED_ENTRY
-
-  // IC utilities
-#define IC_ENTRY(name) \
-  { IC_UTILITY, \
-    IC::k##name, \
-    "IC::" #name },
+  for (unsigned i = 0; i < arraysize(runtime_functions); ++i) {
+    ExternalReference ref(
+        static_cast<Runtime::FunctionId>(runtime_functions[i].id), isolate);
+    Add(ref.address(), runtime_functions[i].name);
+  }
 
-  IC_UTIL_LIST(IC_ENTRY)
+  static const RefTableEntry inline_caches[] = {
+#define IC_ENTRY(name)          \
+  { IC::k##name, "IC::" #name } \
+  ,
+      IC_UTIL_LIST(IC_ENTRY)
 #undef IC_ENTRY
-  };  // end of ref_table[].
+  };
 
-  for (size_t i = 0; i < arraysize(ref_table); ++i) {
-    AddFromId(ref_table[i].type,
-              ref_table[i].id,
-              ref_table[i].name,
-              isolate);
+  for (unsigned i = 0; i < arraysize(inline_caches); ++i) {
+    ExternalReference ref(
+        IC_Utility(static_cast<IC::UtilityId>(inline_caches[i].id)), isolate);
+    Add(ref.address(), runtime_functions[i].name);
   }
 
   // Stat counters
   struct StatsRefTableEntry {
     StatsCounter* (Counters::*counter)();
-    uint16_t id;
     const char* name;
   };
 
-  const StatsRefTableEntry stats_ref_table[] = {
-#define COUNTER_ENTRY(name, caption) \
-  { &Counters::name,    \
-    Counters::k_##name, \
-    "Counters::" #name },
-
-  STATS_COUNTER_LIST_1(COUNTER_ENTRY)
-  STATS_COUNTER_LIST_2(COUNTER_ENTRY)
+  static const StatsRefTableEntry stats_ref_table[] = {
+#define COUNTER_ENTRY(name, caption)      \
+  { &Counters::name, "Counters::" #name } \
+  ,
+      STATS_COUNTER_LIST_1(COUNTER_ENTRY) STATS_COUNTER_LIST_2(COUNTER_ENTRY)
 #undef COUNTER_ENTRY
-  };  // end of stats_ref_table[].
+  };
 
   Counters* counters = isolate->counters();
-  for (size_t i = 0; i < arraysize(stats_ref_table); ++i) {
-    Add(reinterpret_cast<Address>(GetInternalPointer(
-            (counters->*(stats_ref_table[i].counter))())),
-        STATS_COUNTER,
-        stats_ref_table[i].id,
-        stats_ref_table[i].name);
+  for (unsigned i = 0; i < arraysize(stats_ref_table); ++i) {
+    // To make sure the indices are not dependent on whether counters are
+    // enabled, use a dummy address as filler.
+    Address address = NotAvailable();
+    StatsCounter* counter = (counters->*(stats_ref_table[i].counter))();
+    if (counter->Enabled()) {
+      address = reinterpret_cast<Address>(counter->GetInternalPointer());
+    }
+    Add(address, stats_ref_table[i].name);
   }
 
   // Top addresses
-
-  const char* AddressNames[] = {
-#define BUILD_NAME_LITERAL(CamelName, hacker_name)      \
-    "Isolate::" #hacker_name "_address",
-    FOR_EACH_ISOLATE_ADDRESS_NAME(BUILD_NAME_LITERAL)
-    NULL
+  static const char* address_names[] = {
+#define BUILD_NAME_LITERAL(Name, name) "Isolate::" #name "_address",
+      FOR_EACH_ISOLATE_ADDRESS_NAME(BUILD_NAME_LITERAL) NULL
 #undef BUILD_NAME_LITERAL
   };
 
-  for (uint16_t i = 0; i < Isolate::kIsolateAddressCount; ++i) {
-    Add(isolate->get_address_from_id((Isolate::AddressId)i),
-        TOP_ADDRESS, i, AddressNames[i]);
+  for (int i = 0; i < Isolate::kIsolateAddressCount; ++i) {
+    Add(isolate->get_address_from_id(static_cast<Isolate::AddressId>(i)),
+        address_names[i]);
   }
 
   // Accessors
-#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)
+  struct AccessorRefTable {
+    Address address;
+    const char* name;
+  };
+
+  static const AccessorRefTable accessors[] = {
+#define ACCESSOR_INFO_DECLARATION(name)                                     \
+  { FUNCTION_ADDR(&Accessors::name##Getter), "Accessors::" #name "Getter" } \
+  , {FUNCTION_ADDR(&Accessors::name##Setter), "Accessors::" #name "Setter"},
+      ACCESSOR_INFO_LIST(ACCESSOR_INFO_DECLARATION)
 #undef ACCESSOR_INFO_DECLARATION
+  };
+
+  for (unsigned i = 0; i < arraysize(accessors); ++i) {
+    Add(accessors[i].address, accessors[i].name);
+  }
 
   StubCache* stub_cache = isolate->stub_cache();
 
   // Stub cache tables
   Add(stub_cache->key_reference(StubCache::kPrimary).address(),
-      STUB_CACHE_TABLE, 1, "StubCache::primary_->key");
+      "StubCache::primary_->key");
   Add(stub_cache->value_reference(StubCache::kPrimary).address(),
-      STUB_CACHE_TABLE, 2, "StubCache::primary_->value");
+      "StubCache::primary_->value");
   Add(stub_cache->map_reference(StubCache::kPrimary).address(),
-      STUB_CACHE_TABLE, 3, "StubCache::primary_->map");
+      "StubCache::primary_->map");
   Add(stub_cache->key_reference(StubCache::kSecondary).address(),
-      STUB_CACHE_TABLE, 4, "StubCache::secondary_->key");
+      "StubCache::secondary_->key");
   Add(stub_cache->value_reference(StubCache::kSecondary).address(),
-      STUB_CACHE_TABLE, 5, "StubCache::secondary_->value");
+      "StubCache::secondary_->value");
   Add(stub_cache->map_reference(StubCache::kSecondary).address(),
-      STUB_CACHE_TABLE, 6, "StubCache::secondary_->map");
+      "StubCache::secondary_->map");
 
   // Runtime entries
   Add(ExternalReference::delete_handle_scope_extensions(isolate).address(),
-      RUNTIME_ENTRY, 1, "HandleScope::DeleteExtensions");
+      "HandleScope::DeleteExtensions");
   Add(ExternalReference::incremental_marking_record_write_function(isolate)
           .address(),
-      RUNTIME_ENTRY, 2, "IncrementalMarking::RecordWrite");
+      "IncrementalMarking::RecordWrite");
   Add(ExternalReference::store_buffer_overflow_function(isolate).address(),
-      RUNTIME_ENTRY, 3, "StoreBuffer::StoreBufferOverflow");
+      "StoreBuffer::StoreBufferOverflow");
 
   // Add a small set of deopt entry addresses to encoder without generating the
   // deopt table code, which isn't possible at deserialization time.
@@ -406,94 +333,69 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
         entry,
         Deoptimizer::LAZY,
         Deoptimizer::CALCULATE_ENTRY_ADDRESS);
-    Add(address, LAZY_DEOPTIMIZATION, entry, "lazy_deopt");
+    Add(address, "lazy_deopt");
   }
 }
 
 
-ExternalReferenceEncoder::ExternalReferenceEncoder(Isolate* isolate)
-    : encodings_(HashMap::PointersMatch),
-      isolate_(isolate) {
-  ExternalReferenceTable* external_references =
-      ExternalReferenceTable::instance(isolate_);
-  for (int i = 0; i < external_references->size(); ++i) {
-    Put(external_references->address(i), i);
+ExternalReferenceEncoder::ExternalReferenceEncoder(Isolate* isolate) {
+  map_ = isolate->external_reference_map();
+  if (map_ != NULL) return;
+  map_ = new HashMap(HashMap::PointersMatch);
+  ExternalReferenceTable* table = ExternalReferenceTable::instance(isolate);
+  for (int i = 0; i < table->size(); ++i) {
+    Address addr = table->address(i);
+    if (addr == ExternalReferenceTable::NotAvailable()) continue;
+    // We expect no duplicate external references entries in the table.
+    DCHECK_NULL(map_->Lookup(addr, Hash(addr), false));
+    map_->Lookup(addr, Hash(addr), true)->value = reinterpret_cast<void*>(i);
   }
+  isolate->set_external_reference_map(map_);
 }
 
 
-uint32_t ExternalReferenceEncoder::Encode(Address key) const {
-  int index = IndexOf(key);
-  DCHECK(key == NULL || index >= 0);
-  return index >= 0 ?
-         ExternalReferenceTable::instance(isolate_)->code(index) : 0;
-}
-
-
-const char* ExternalReferenceEncoder::NameOfAddress(Address key) const {
-  int index = IndexOf(key);
-  return index >= 0 ? ExternalReferenceTable::instance(isolate_)->name(index)
-                    : "<unknown>";
-}
-
-
-int ExternalReferenceEncoder::IndexOf(Address key) const {
-  if (key == NULL) return -1;
+uint32_t ExternalReferenceEncoder::Encode(Address address) const {
+  DCHECK_NOT_NULL(address);
   HashMap::Entry* entry =
-      const_cast<HashMap&>(encodings_).Lookup(key, Hash(key), false);
-  return entry == NULL
-      ? -1
-      : static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
+      const_cast<HashMap*>(map_)->Lookup(address, Hash(address), false);
+  DCHECK_NOT_NULL(entry);
+  return static_cast<uint32_t>(reinterpret_cast<intptr_t>(entry->value));
 }
 
 
-void ExternalReferenceEncoder::Put(Address key, int index) {
-  HashMap::Entry* entry = encodings_.Lookup(key, Hash(key), true);
-  entry->value = reinterpret_cast<void*>(index);
-}
-
-
-ExternalReferenceDecoder::ExternalReferenceDecoder(Isolate* isolate)
-    : encodings_(NewArray<Address*>(kTypeCodeCount)),
-      isolate_(isolate) {
-  ExternalReferenceTable* external_references =
-      ExternalReferenceTable::instance(isolate_);
-  for (int type = kFirstTypeCode; type < kTypeCodeCount; ++type) {
-    int max = external_references->max_id(type) + 1;
-    encodings_[type] = NewArray<Address>(max + 1);
-  }
-  for (int i = 0; i < external_references->size(); ++i) {
-    Put(external_references->code(i), external_references->address(i));
-  }
-}
-
-
-ExternalReferenceDecoder::~ExternalReferenceDecoder() {
-  for (int type = kFirstTypeCode; type < kTypeCodeCount; ++type) {
-    DeleteArray(encodings_[type]);
-  }
-  DeleteArray(encodings_);
+const char* ExternalReferenceEncoder::NameOfAddress(Isolate* isolate,
+                                                    Address address) const {
+  HashMap::Entry* entry =
+      const_cast<HashMap*>(map_)->Lookup(address, Hash(address), false);
+  if (entry == NULL) return "<unknown>";
+  uint32_t i = static_cast<uint32_t>(reinterpret_cast<intptr_t>(entry->value));
+  return ExternalReferenceTable::instance(isolate)->name(i);
 }
 
 
 RootIndexMap::RootIndexMap(Isolate* isolate) {
+  map_ = isolate->root_index_map();
+  if (map_ != NULL) return;
   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)) {
+  for (uint32_t i = 0; i < Heap::kStrongRootListLength; i++) {
+    Heap::RootListIndex root_index = static_cast<Heap::RootListIndex>(i);
+    Object* root = root_array[root_index];
+    // Omit root entries that can be written after initialization. They must
+    // not be referenced through the root list in the snapshot.
+    if (root->IsHeapObject() &&
+        isolate->heap()->RootCanBeTreatedAsConstant(root_index)) {
       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);
+      HashMap::Entry* entry = LookupEntry(map_, heap_object, false);
+      if (entry != NULL) {
+        // Some are initialized to a previous value in the root list.
+        DCHECK_LT(GetValue(entry), i);
       } else {
         SetValue(LookupEntry(map_, heap_object, true), i);
       }
     }
   }
+  isolate->set_root_index_map(map_);
 }
 
 
@@ -613,9 +515,7 @@ void Deserializer::DecodeReservation(
   DCHECK_EQ(0, reservations_[NEW_SPACE].length());
   STATIC_ASSERT(NEW_SPACE == 0);
   int current_space = NEW_SPACE;
-  for (int i = 0; i < res.length(); i++) {
-    SerializedData::Reservation r(0);
-    memcpy(&r, res.start() + i, sizeof(r));
+  for (auto& r : res) {
     reservations_[current_space].Add({r.chunk_size(), NULL, NULL});
     if (r.is_last()) current_space++;
   }
@@ -651,8 +551,10 @@ void Deserializer::Initialize(Isolate* isolate) {
   DCHECK_NULL(isolate_);
   DCHECK_NOT_NULL(isolate);
   isolate_ = isolate;
-  DCHECK_NULL(external_reference_decoder_);
-  external_reference_decoder_ = new ExternalReferenceDecoder(isolate);
+  DCHECK_NULL(external_reference_table_);
+  external_reference_table_ = ExternalReferenceTable::instance(isolate);
+  CHECK_EQ(magic_number_,
+           SerializedData::ComputeMagicNumber(external_reference_table_));
 }
 
 
@@ -672,6 +574,8 @@ void Deserializer::Deserialize(Isolate* isolate) {
       isolate_->heap()->undefined_value());
   isolate_->heap()->set_array_buffers_list(
       isolate_->heap()->undefined_value());
+  isolate->heap()->set_new_array_buffer_views_list(
+      isolate_->heap()->undefined_value());
 
   // The allocation site list is build during root iteration, but if no sites
   // were encountered then it needs to be initialized to undefined.
@@ -748,10 +652,6 @@ MaybeHandle<SharedFunctionInfo> Deserializer::DeserializeCode(
 Deserializer::~Deserializer() {
   // TODO(svenpanne) Re-enable this assertion when v8 initialization is fixed.
   // DCHECK(source_.AtEOF());
-  if (external_reference_decoder_) {
-    delete external_reference_decoder_;
-    external_reference_decoder_ = NULL;
-  }
   attached_objects_.Dispose();
 }
 
@@ -897,27 +797,13 @@ void Deserializer::ReadObject(int space_number, Object** write_back) {
 #ifdef DEBUG
   if (obj->IsCode()) {
     DCHECK(space_number == CODE_SPACE || space_number == LO_SPACE);
+#ifdef VERIFY_HEAP
+    obj->ObjectVerify();
+#endif  // VERIFY_HEAP
   } else {
     DCHECK(space_number != CODE_SPACE);
   }
-#endif
-#if V8_TARGET_ARCH_PPC && \
-    (ABI_USES_FUNCTION_DESCRIPTORS || V8_OOL_CONSTANT_POOL)
-  // If we're on a platform that uses function descriptors
-  // these jump tables make use of RelocInfo::INTERNAL_REFERENCE.
-  // As the V8 serialization code doesn't handle that relocation type
-  // we use this to fix up code that has function descriptors.
-  if (space_number == CODE_SPACE) {
-    Code* code = reinterpret_cast<Code*>(HeapObject::FromAddress(address));
-    for (RelocIterator it(code); !it.done(); it.next()) {
-      RelocInfo::Mode rmode = it.rinfo()->rmode();
-      if (rmode == RelocInfo::INTERNAL_REFERENCE) {
-        Assembler::RelocateInternalReference(it.rinfo()->pc(), 0,
-                                             code->instruction_start());
-      }
-    }
-  }
-#endif
+#endif  // DEBUG
 }
 
 
@@ -963,18 +849,16 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
   // 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,
   // but that may change.
-  bool write_barrier_needed = (current_object_address != NULL &&
-                               source_space != NEW_SPACE &&
-                               source_space != CELL_SPACE &&
-                               source_space != PROPERTY_CELL_SPACE &&
-                               source_space != CODE_SPACE &&
-                               source_space != OLD_DATA_SPACE);
+  bool write_barrier_needed =
+      (current_object_address != NULL && source_space != NEW_SPACE &&
+       source_space != CELL_SPACE && source_space != CODE_SPACE &&
+       source_space != OLD_DATA_SPACE);
   while (current < limit) {
     byte data = source_.Get();
     switch (data) {
 #define CASE_STATEMENT(where, how, within, space_number) \
   case where + how + within + space_number:              \
-    STATIC_ASSERT((where & ~kPointedToMask) == 0);       \
+    STATIC_ASSERT((where & ~kWhereMask) == 0);           \
     STATIC_ASSERT((how & ~kHowToCodeMask) == 0);         \
     STATIC_ASSERT((within & ~kWhereToPointMask) == 0);   \
     STATIC_ASSERT((space_number & ~kSpaceMask) == 0);
@@ -993,25 +877,37 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
       Object* new_object = NULL; /* May not be a real Object pointer. */       \
       if (where == kNewObject) {                                               \
         ReadObject(space_number, &new_object);                                 \
+      } else if (where == kBackref) {                                          \
+        emit_write_barrier = (space_number == NEW_SPACE);                      \
+        new_object = GetBackReferencedObject(data & kSpaceMask);               \
+      } else if (where == kBackrefWithSkip) {                                  \
+        int skip = source_.GetInt();                                           \
+        current = reinterpret_cast<Object**>(                                  \
+            reinterpret_cast<Address>(current) + skip);                        \
+        emit_write_barrier = (space_number == NEW_SPACE);                      \
+        new_object = GetBackReferencedObject(data & kSpaceMask);               \
       } else if (where == kRootArray) {                                        \
         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();                                    \
-        new_object = isolate->serialize_partial_snapshot_cache()[cache_index]; \
+        new_object = isolate->partial_snapshot_cache()->at(cache_index);       \
         emit_write_barrier = isolate->heap()->InNewSpace(new_object);          \
       } else if (where == kExternalReference) {                                \
         int skip = source_.GetInt();                                           \
         current = reinterpret_cast<Object**>(                                  \
             reinterpret_cast<Address>(current) + skip);                        \
         int reference_id = source_.GetInt();                                   \
-        Address address = external_reference_decoder_->Decode(reference_id);   \
+        Address address = external_reference_table_->address(reference_id);    \
         new_object = reinterpret_cast<Object*>(address);                       \
-      } else if (where == kBackref) {                                          \
-        emit_write_barrier = (space_number == NEW_SPACE);                      \
-        new_object = GetBackReferencedObject(data & kSpaceMask);               \
-      } else if (where == kBuiltin) {                                          \
+      } else if (where == kAttachedReference) {                                \
+        int index = source_.GetInt();                                          \
+        DCHECK(deserializing_user_code() || index == kGlobalProxyReference);   \
+        new_object = *attached_objects_[index];                                \
+        emit_write_barrier = isolate->heap()->InNewSpace(new_object);          \
+      } else {                                                                 \
+        DCHECK(where == kBuiltin);                                             \
         DCHECK(deserializing_user_code());                                     \
         int builtin_id = source_.GetInt();                                     \
         DCHECK_LE(0, builtin_id);                                              \
@@ -1019,18 +915,6 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
         Builtins::Name name = static_cast<Builtins::Name>(builtin_id);         \
         new_object = isolate->builtins()->builtin(name);                       \
         emit_write_barrier = false;                                            \
-      } else if (where == kAttachedReference) {                                \
-        int index = source_.GetInt();                                          \
-        DCHECK(deserializing_user_code() || index == kGlobalProxyReference);   \
-        new_object = *attached_objects_[index];                                \
-        emit_write_barrier = isolate->heap()->InNewSpace(new_object);          \
-      } else {                                                                 \
-        DCHECK(where == kBackrefWithSkip);                                     \
-        int skip = source_.GetInt();                                           \
-        current = reinterpret_cast<Object**>(                                  \
-            reinterpret_cast<Address>(current) + skip);                        \
-        emit_write_barrier = (space_number == NEW_SPACE);                      \
-        new_object = GetBackReferencedObject(data & kSpaceMask);               \
       }                                                                        \
       if (within == kInnerPointer) {                                           \
         if (space_number != CODE_SPACE || new_object->IsCode()) {              \
@@ -1069,18 +953,17 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
   }
 
 // 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, MAP_SPACE)           \
-  CASE_STATEMENT(where, how, within, CELL_SPACE)          \
-  CASE_STATEMENT(where, how, within, PROPERTY_CELL_SPACE) \
-  CASE_STATEMENT(where, how, within, LO_SPACE)            \
+// write barrier handling) and handles the other spaces with 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, MAP_SPACE)         \
+  CASE_STATEMENT(where, how, within, CELL_SPACE)        \
+  CASE_STATEMENT(where, how, within, LO_SPACE)          \
   CASE_BODY(where, how, within, kAnyOldSpace)
 
 #define FOUR_CASES(byte_code)             \
@@ -1095,106 +978,6 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
   FOUR_CASES(byte_code + 8)               \
   FOUR_CASES(byte_code + 12)
 
-#define COMMON_RAW_LENGTHS(f)        \
-  f(1)  \
-  f(2)  \
-  f(3)  \
-  f(4)  \
-  f(5)  \
-  f(6)  \
-  f(7)  \
-  f(8)  \
-  f(9)  \
-  f(10) \
-  f(11) \
-  f(12) \
-  f(13) \
-  f(14) \
-  f(15) \
-  f(16) \
-  f(17) \
-  f(18) \
-  f(19) \
-  f(20) \
-  f(21) \
-  f(22) \
-  f(23) \
-  f(24) \
-  f(25) \
-  f(26) \
-  f(27) \
-  f(28) \
-  f(29) \
-  f(30) \
-  f(31)
-
-      // 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;                                                                     \
-  }
-      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();
-        byte* raw_data_out = reinterpret_cast<byte*>(current);
-        source_.CopyRaw(raw_data_out, size);
-        break;
-      }
-
-      SIXTEEN_CASES(kRootArrayConstants + kNoSkipDistance)
-      SIXTEEN_CASES(kRootArrayConstants + kNoSkipDistance + 16) {
-        int root_id = RootArrayConstantFromByteCode(data);
-        Object* object = isolate->heap()->roots_array_start()[root_id];
-        DCHECK(!isolate->heap()->InNewSpace(object));
-        UnalignedCopy(current++, &object);
-        break;
-      }
-
-      SIXTEEN_CASES(kRootArrayConstants + kHasSkipDistance)
-      SIXTEEN_CASES(kRootArrayConstants + kHasSkipDistance + 16) {
-        int root_id = RootArrayConstantFromByteCode(data);
-        int skip = source_.GetInt();
-        current = reinterpret_cast<Object**>(
-            reinterpret_cast<intptr_t>(current) + skip);
-        Object* object = isolate->heap()->roots_array_start()[root_id];
-        DCHECK(!isolate->heap()->InNewSpace(object));
-        UnalignedCopy(current++, &object);
-        break;
-      }
-
-      case kVariableRepeat: {
-        int repeats = source_.GetInt();
-        Object* object = current[-1];
-        DCHECK(!isolate->heap()->InNewSpace(object));
-        for (int i = 0; i < repeats; i++) UnalignedCopy(current++, &object);
-        break;
-      }
-
-      STATIC_ASSERT(kRootArrayNumberOfConstantEncodings ==
-                    Heap::kOldSpaceRoots);
-      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;
-        UnalignedCopy(&object, current - 1);
-        DCHECK(!isolate->heap()->InNewSpace(object));
-        for (int i = 0; i < repeats; i++) UnalignedCopy(current++, &object);
-        break;
-      }
-
       // Deserialize a new object and write a pointer to it to the current
       // object.
       ALL_SPACES(kNewObject, kPlain, kStartOfObject)
@@ -1244,38 +1027,19 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
       // Find an object in the partial snapshots cache and write a pointer to it
       // to the current object.
       CASE_STATEMENT(kPartialSnapshotCache, kPlain, kStartOfObject, 0)
-      CASE_BODY(kPartialSnapshotCache,
-                kPlain,
-                kStartOfObject,
-                0)
+      CASE_BODY(kPartialSnapshotCache, kPlain, kStartOfObject, 0)
       // Find an code entry in the partial snapshots cache and
       // write a pointer to it to the current object.
       CASE_STATEMENT(kPartialSnapshotCache, kPlain, kInnerPointer, 0)
-      CASE_BODY(kPartialSnapshotCache,
-                kPlain,
-                kInnerPointer,
-                0)
+      CASE_BODY(kPartialSnapshotCache, kPlain, kInnerPointer, 0)
       // Find an external reference and write a pointer to it to the current
       // object.
       CASE_STATEMENT(kExternalReference, kPlain, kStartOfObject, 0)
-      CASE_BODY(kExternalReference,
-                kPlain,
-                kStartOfObject,
-                0)
+      CASE_BODY(kExternalReference, kPlain, kStartOfObject, 0)
       // Find an external reference and write a pointer to it in the current
       // code object.
       CASE_STATEMENT(kExternalReference, kFromCode, kStartOfObject, 0)
-      CASE_BODY(kExternalReference,
-                kFromCode,
-                kStartOfObject,
-                0)
-      // 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)
-      CASE_STATEMENT(kBuiltin, kPlain, kInnerPointer, 0)
-      CASE_BODY(kBuiltin, kPlain, kInnerPointer, 0)
-      CASE_STATEMENT(kBuiltin, kFromCode, kInnerPointer, 0)
-      CASE_BODY(kBuiltin, kFromCode, kInnerPointer, 0)
+      CASE_BODY(kExternalReference, kFromCode, kStartOfObject, 0)
       // Find an object in the attached references and write a pointer to it to
       // the current object.
       CASE_STATEMENT(kAttachedReference, kPlain, kStartOfObject, 0)
@@ -1284,6 +1048,13 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
       CASE_BODY(kAttachedReference, kPlain, kInnerPointer, 0)
       CASE_STATEMENT(kAttachedReference, kFromCode, kInnerPointer, 0)
       CASE_BODY(kAttachedReference, kFromCode, kInnerPointer, 0)
+      // 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)
+      CASE_STATEMENT(kBuiltin, kPlain, kInnerPointer, 0)
+      CASE_BODY(kBuiltin, kPlain, kInnerPointer, 0)
+      CASE_STATEMENT(kBuiltin, kFromCode, kInnerPointer, 0)
+      CASE_BODY(kBuiltin, kFromCode, kInnerPointer, 0)
 
 #undef CASE_STATEMENT
 #undef CASE_BODY
@@ -1296,18 +1067,28 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
         break;
       }
 
-      case kNativesStringResource: {
-        DCHECK(!isolate_->heap()->deserialization_complete());
-        int index = source_.Get();
-        Vector<const char> source_vector = Natives::GetScriptSource(index);
-        NativesExternalStringResource* resource =
-            new NativesExternalStringResource(source_vector.start(),
-                                              source_vector.length());
-        Object* resource_obj = reinterpret_cast<Object*>(resource);
-        UnalignedCopy(current++, &resource_obj);
+      case kInternalReferenceEncoded:
+      case kInternalReference: {
+        // Internal reference address is not encoded via skip, but by offset
+        // from code entry.
+        int pc_offset = source_.GetInt();
+        int target_offset = source_.GetInt();
+        Code* code =
+            Code::cast(HeapObject::FromAddress(current_object_address));
+        DCHECK(0 <= pc_offset && pc_offset <= code->instruction_size());
+        DCHECK(0 <= target_offset && target_offset <= code->instruction_size());
+        Address pc = code->entry() + pc_offset;
+        Address target = code->entry() + target_offset;
+        Assembler::deserialization_set_target_internal_reference_at(
+            pc, target, data == kInternalReference
+                            ? RelocInfo::INTERNAL_REFERENCE
+                            : RelocInfo::INTERNAL_REFERENCE_ENCODED);
         break;
       }
 
+      case kNop:
+        break;
+
       case kNextChunk: {
         int space = source_.Get();
         DCHECK(space < kNumberOfPreallocatedSpaces);
@@ -1322,6 +1103,60 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
         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.
+        CHECK(false);
+        break;
+
+      case kNativesStringResource: {
+        DCHECK(!isolate_->heap()->deserialization_complete());
+        int index = source_.Get();
+        Vector<const char> source_vector = Natives::GetScriptSource(index);
+        NativesExternalStringResource* resource =
+            new NativesExternalStringResource(source_vector.start(),
+                                              source_vector.length());
+        Object* resource_obj = reinterpret_cast<Object*>(resource);
+        UnalignedCopy(current++, &resource_obj);
+        break;
+      }
+
+      // Deserialize raw data of variable length.
+      case kVariableRawData: {
+        int size_in_bytes = source_.GetInt();
+        byte* raw_data_out = reinterpret_cast<byte*>(current);
+        source_.CopyRaw(raw_data_out, size_in_bytes);
+        break;
+      }
+
+      case kVariableRepeat: {
+        int repeats = source_.GetInt();
+        Object* object = current[-1];
+        DCHECK(!isolate->heap()->InNewSpace(object));
+        for (int i = 0; i < repeats; i++) UnalignedCopy(current++, &object);
+        break;
+      }
+
+      STATIC_ASSERT(kNumberOfRootArrayConstants == Heap::kOldSpaceRoots);
+      STATIC_ASSERT(kNumberOfRootArrayConstants == 32);
+      SIXTEEN_CASES(kRootArrayConstantsWithSkip)
+      SIXTEEN_CASES(kRootArrayConstantsWithSkip + 16) {
+        int skip = source_.GetInt();
+        current = reinterpret_cast<Object**>(
+            reinterpret_cast<intptr_t>(current) + skip);
+        // Fall through.
+      }
+
+      SIXTEEN_CASES(kRootArrayConstants)
+      SIXTEEN_CASES(kRootArrayConstants + 16) {
+        int root_id = data & kRootArrayConstantsMask;
+        Object* object = isolate->heap()->roots_array_start()[root_id];
+        DCHECK(!isolate->heap()->InNewSpace(object));
+        UnalignedCopy(current++, &object);
+        break;
+      }
+
+      STATIC_ASSERT(kNumberOfHotObjects == 8);
       FOUR_CASES(kHotObjectWithSkip)
       FOUR_CASES(kHotObjectWithSkip + 4) {
         int skip = source_.GetInt();
@@ -1329,9 +1164,10 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
             reinterpret_cast<Address>(current) + skip);
         // Fall through.
       }
+
       FOUR_CASES(kHotObject)
       FOUR_CASES(kHotObject + 4) {
-        int index = data & kHotObjectIndexMask;
+        int index = data & kHotObjectMask;
         Object* hot_object = hot_objects_.Get(index);
         UnalignedCopy(current, &hot_object);
         if (write_barrier_needed && isolate->heap()->InNewSpace(hot_object)) {
@@ -1344,12 +1180,30 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
         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.
-        CHECK(false);
+      // Deserialize raw data of fixed length from 1 to 32 words.
+      STATIC_ASSERT(kNumberOfFixedRawData == 32);
+      SIXTEEN_CASES(kFixedRawData)
+      SIXTEEN_CASES(kFixedRawData + 16) {
+        byte* raw_data_out = reinterpret_cast<byte*>(current);
+        int size_in_bytes = (data - kFixedRawDataStart) << kPointerSizeLog2;
+        source_.CopyRaw(raw_data_out, size_in_bytes);
+        current = reinterpret_cast<Object**>(raw_data_out + size_in_bytes);
+        break;
+      }
+
+      STATIC_ASSERT(kNumberOfFixedRepeat == 16);
+      SIXTEEN_CASES(kFixedRepeat) {
+        int repeats = data - kFixedRepeatStart;
+        Object* object;
+        UnalignedCopy(&object, current - 1);
+        DCHECK(!isolate->heap()->InNewSpace(object));
+        for (int i = 0; i < repeats; i++) UnalignedCopy(current++, &object);
+        break;
       }
 
+#undef SIXTEEN_CASES
+#undef FOUR_CASES
+
       default:
         CHECK(false);
     }
@@ -1361,7 +1215,7 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space,
 Serializer::Serializer(Isolate* isolate, SnapshotByteSink* sink)
     : isolate_(isolate),
       sink_(sink),
-      external_reference_encoder_(new ExternalReferenceEncoder(isolate)),
+      external_reference_encoder_(isolate),
       root_index_map_(isolate),
       code_address_map_(NULL),
       large_objects_total_size_(0),
@@ -1377,7 +1231,6 @@ Serializer::Serializer(Isolate* isolate, SnapshotByteSink* sink)
 
 
 Serializer::~Serializer() {
-  delete external_reference_encoder_;
   if (code_address_map_ != NULL) delete code_address_map_;
 }
 
@@ -1509,43 +1362,35 @@ void Serializer::EncodeReservations(
 void SerializerDeserializer::Iterate(Isolate* isolate,
                                      ObjectVisitor* visitor) {
   if (isolate->serializer_enabled()) return;
-  for (int i = 0; ; i++) {
-    if (isolate->serialize_partial_snapshot_cache_length() <= i) {
-      // Extend the array ready to get a value from the visitor when
-      // deserializing.
-      isolate->PushToPartialSnapshotCache(Smi::FromInt(0));
-    }
-    Object** cache = isolate->serialize_partial_snapshot_cache();
-    visitor->VisitPointers(&cache[i], &cache[i + 1]);
+  List<Object*>* cache = isolate->partial_snapshot_cache();
+  for (int i = 0;; ++i) {
+    // Extend the array ready to get a value when deserializing.
+    if (cache->length() <= i) cache->Add(Smi::FromInt(0));
+    visitor->VisitPointer(&cache->at(i));
     // Sentinel is the undefined object, which is a root so it will not normally
     // be found in the cache.
-    if (cache[i] == isolate->heap()->undefined_value()) {
-      break;
-    }
+    if (cache->at(i)->IsUndefined()) break;
   }
 }
 
 
 int PartialSerializer::PartialSnapshotCacheIndex(HeapObject* heap_object) {
   Isolate* isolate = this->isolate();
-
-  for (int i = 0;
-       i < isolate->serialize_partial_snapshot_cache_length();
-       i++) {
-    Object* entry = isolate->serialize_partial_snapshot_cache()[i];
-    if (entry == heap_object) return i;
+  List<Object*>* cache = isolate->partial_snapshot_cache();
+  int new_index = cache->length();
+
+  int index = partial_cache_index_map_.LookupOrInsert(heap_object, new_index);
+  if (index == PartialCacheIndexMap::kInvalidIndex) {
+    // We didn't find the object in the cache.  So we add it to the cache and
+    // then visit the pointer so that it becomes part of the startup snapshot
+    // and we can refer to it from the partial snapshot.
+    cache->Add(heap_object);
+    startup_serializer_->VisitPointer(reinterpret_cast<Object**>(&heap_object));
+    // We don't recurse from the startup snapshot generator into the partial
+    // snapshot generator.
+    return new_index;
   }
-
-  // We didn't find the object in the cache.  So we add it to the cache and
-  // then visit the pointer so that it becomes part of the startup snapshot
-  // and we can refer to it from the partial snapshot.
-  int length = isolate->serialize_partial_snapshot_cache_length();
-  isolate->PushToPartialSnapshotCache(heap_object);
-  startup_serializer_->VisitPointer(reinterpret_cast<Object**>(&heap_object));
-  // We don't recurse from the startup snapshot generator into the partial
-  // snapshot generator.
-  DCHECK(length == isolate->serialize_partial_snapshot_cache_length() - 1);
-  return length;
+  return index;
 }
 
 
@@ -1575,7 +1420,7 @@ bool Serializer::SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
     // 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);
+      DCHECK(index >= 0 && index < kNumberOfHotObjects);
       if (FLAG_trace_serializer) {
         PrintF(" Encoding hot object %d:", index);
         obj->ShortPrint();
@@ -1647,6 +1492,10 @@ void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
     return;
   }
 
+  if (obj->IsCode() && Code::cast(obj)->kind() == Code::FUNCTION) {
+    obj = isolate()->builtins()->builtin(Builtins::kCompileLazy);
+  }
+
   if (SerializeKnownObject(obj, how_to_code, where_to_point, skip)) return;
 
   FlushSkip(skip);
@@ -1682,16 +1531,13 @@ void Serializer::PutRoot(int root_index,
     PrintF("\n");
   }
 
-  if (how_to_code == kPlain &&
-      where_to_point == kStartOfObject &&
-      root_index < kRootArrayNumberOfConstantEncodings &&
+  if (how_to_code == kPlain && where_to_point == kStartOfObject &&
+      root_index < kNumberOfRootArrayConstants &&
       !isolate()->heap()->InNewSpace(object)) {
     if (skip == 0) {
-      sink_->Put(kRootArrayConstants + kNoSkipDistance + root_index,
-                 "RootConstant");
+      sink_->Put(kRootArrayConstants + root_index, "RootConstant");
     } else {
-      sink_->Put(kRootArrayConstants + kHasSkipDistance + root_index,
-                 "RootConstant");
+      sink_->Put(kRootArrayConstantsWithSkip + root_index, "RootConstant");
       sink_->PutInt(skip, "SkipInPutRoot");
     }
   } else {
@@ -1842,7 +1688,7 @@ void Serializer::ObjectSerializer::SerializeExternalString() {
   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_->Put(kVariableRawData, "RawDataForString");
   sink_->PutInt(bytes_to_output, "length");
 
   // Serialize string header (except for map).
@@ -1897,7 +1743,9 @@ void Serializer::ObjectSerializer::Serialize() {
 
   int size = object_->Size();
   Map* map = object_->map();
-  SerializePrologue(Serializer::SpaceOfObject(object_), size, map);
+  AllocationSpace space =
+      MemoryChunk::FromAddress(object_->address())->owner()->identity();
+  SerializePrologue(space, size, map);
 
   // Serialize the rest of the object.
   CHECK_EQ(0, bytes_processed_so_far_);
@@ -1931,11 +1779,11 @@ void Serializer::ObjectSerializer::VisitPointers(Object** start,
         }
         current += repeat_count;
         bytes_processed_so_far_ += repeat_count * kPointerSize;
-        if (repeat_count > kMaxFixedRepeats) {
-          sink_->Put(kVariableRepeat, "SerializeRepeats");
-          sink_->PutInt(repeat_count, "SerializeRepeats");
+        if (repeat_count > kNumberOfFixedRepeat) {
+          sink_->Put(kVariableRepeat, "VariableRepeat");
+          sink_->PutInt(repeat_count, "repeat count");
         } else {
-          sink_->Put(CodeForRepeats(repeat_count), "SerializeRepeats");
+          sink_->Put(kFixedRepeatStart + repeat_count, "FixedRepeat");
         }
       } else {
         serializer_->SerializeObject(
@@ -1979,12 +1827,37 @@ void Serializer::ObjectSerializer::VisitExternalReference(RelocInfo* rinfo) {
   HowToCode how_to_code = rinfo->IsCodedSpecially() ? kFromCode : kPlain;
   sink_->Put(kExternalReference + how_to_code + kStartOfObject, "ExternalRef");
   sink_->PutInt(skip, "SkipB4ExternalRef");
-  Address target = rinfo->target_reference();
+  Address target = rinfo->target_external_reference();
   sink_->PutInt(serializer_->EncodeExternalReference(target), "reference id");
   bytes_processed_so_far_ += rinfo->target_address_size();
 }
 
 
+void Serializer::ObjectSerializer::VisitInternalReference(RelocInfo* rinfo) {
+  // We can only reference to internal references of code that has been output.
+  DCHECK(is_code_object_ && code_has_been_output_);
+  // We do not use skip from last patched pc to find the pc to patch, since
+  // target_address_address may not return addresses in ascending order when
+  // used for internal references. External references may be stored at the
+  // end of the code in the constant pool, whereas internal references are
+  // inline. That would cause the skip to be negative. Instead, we store the
+  // offset from code entry.
+  Address entry = Code::cast(object_)->entry();
+  intptr_t pc_offset = rinfo->target_internal_reference_address() - entry;
+  intptr_t target_offset = rinfo->target_internal_reference() - entry;
+  DCHECK(0 <= pc_offset &&
+         pc_offset <= Code::cast(object_)->instruction_size());
+  DCHECK(0 <= target_offset &&
+         target_offset <= Code::cast(object_)->instruction_size());
+  sink_->Put(rinfo->rmode() == RelocInfo::INTERNAL_REFERENCE
+                 ? kInternalReference
+                 : kInternalReferenceEncoded,
+             "InternalRef");
+  sink_->PutInt(static_cast<uintptr_t>(pc_offset), "internal ref address");
+  sink_->PutInt(static_cast<uintptr_t>(target_offset), "internal ref value");
+}
+
+
 void Serializer::ObjectSerializer::VisitRuntimeEntry(RelocInfo* rinfo) {
   int skip = OutputRawData(rinfo->target_address_address(),
                            kCanReturnSkipInsteadOfSkipping);
@@ -2053,24 +1926,29 @@ void Serializer::ObjectSerializer::VisitExternalOneByteString(
 }
 
 
-static Code* CloneCodeObject(HeapObject* code) {
-  Address copy = new byte[code->Size()];
-  MemCopy(copy, code->address(), code->Size());
-  return Code::cast(HeapObject::FromAddress(copy));
-}
-
-
-static void WipeOutRelocations(Code* code) {
-  int mode_mask =
-      RelocInfo::kCodeTargetMask |
-      RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
-      RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
-      RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
+Address Serializer::ObjectSerializer::PrepareCode() {
+  // To make snapshots reproducible, we make a copy of the code object
+  // and wipe all pointers in the copy, which we then serialize.
+  Code* original = Code::cast(object_);
+  Code* code = serializer_->CopyCode(original);
+  // Code age headers are not serializable.
+  code->MakeYoung(serializer_->isolate());
+  int mode_mask = RelocInfo::kCodeTargetMask |
+                  RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
+                  RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
+                  RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
+                  RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
+                  RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED);
   for (RelocIterator it(code, mode_mask); !it.done(); it.next()) {
-    if (!(FLAG_enable_ool_constant_pool && it.rinfo()->IsInConstantPool())) {
-      it.rinfo()->WipeOut();
+    RelocInfo* rinfo = it.rinfo();
+    if (!(FLAG_enable_ool_constant_pool && rinfo->IsInConstantPool())) {
+      rinfo->WipeOut();
     }
   }
+  // We need to wipe out the header fields *after* wiping out the
+  // relocations, because some of these fields are needed for the latter.
+  code->WipeOutHeader();
+  return code->address();
 }
 
 
@@ -2086,47 +1964,33 @@ int Serializer::ObjectSerializer::OutputRawData(
   // locations in a non-ascending order.  Luckily that doesn't happen.
   DCHECK(to_skip >= 0);
   bool outputting_code = false;
-  if (to_skip != 0 && code_object_ && !code_has_been_output_) {
+  if (to_skip != 0 && is_code_object_ && !code_has_been_output_) {
     // Output the code all at once and fix later.
     bytes_to_output = object_->Size() + to_skip - bytes_processed_so_far_;
     outputting_code = true;
     code_has_been_output_ = true;
   }
-  if (bytes_to_output != 0 &&
-      (!code_object_ || outputting_code)) {
-#define RAW_CASE(index)                                                        \
-    if (!outputting_code && bytes_to_output == index * kPointerSize &&         \
-        index * kPointerSize == to_skip) {                                     \
-      sink_->PutSection(kRawData + index, "RawDataFixed");                     \
-      to_skip = 0;  /* This insn already skips. */                             \
-    } else  /* NOLINT */
-    COMMON_RAW_LENGTHS(RAW_CASE)
-#undef RAW_CASE
-    {  /* NOLINT */
+  if (bytes_to_output != 0 && (!is_code_object_ || outputting_code)) {
+    if (!outputting_code && bytes_to_output == to_skip &&
+        IsAligned(bytes_to_output, kPointerAlignment) &&
+        bytes_to_output <= kNumberOfFixedRawData * kPointerSize) {
+      int size_in_words = bytes_to_output >> kPointerSizeLog2;
+      sink_->PutSection(kFixedRawDataStart + size_in_words, "FixedRawData");
+      to_skip = 0;  // This instruction includes skip.
+    } else {
       // We always end up here if we are outputting the code of a code object.
-      sink_->Put(kRawData, "RawData");
+      sink_->Put(kVariableRawData, "VariableRawData");
       sink_->PutInt(bytes_to_output, "length");
     }
 
-    // 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.
-      code->WipeOutHeader();
-      object_start = code->address();
-    }
+    if (is_code_object_) object_start = PrepareCode();
 
-    const char* description = code_object_ ? "Code" : "Byte";
+    const char* description = is_code_object_ ? "Code" : "Byte";
 #ifdef MEMORY_SANITIZER
     // Object sizes are usually rounded up with uninitialized padding space.
     MSAN_MEMORY_IS_INITIALIZED(object_start + base, bytes_to_output);
 #endif  // MEMORY_SANITIZER
     sink_->PutRaw(object_start + base, bytes_to_output, description);
-    if (code_object_) delete[] object_start;
   }
   if (to_skip != 0 && return_skip == kIgnoringReturn) {
     sink_->Put(kSkip, "Skip");
@@ -2137,19 +2001,6 @@ int Serializer::ObjectSerializer::OutputRawData(
 }
 
 
-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 s;
-    }
-  }
-  UNREACHABLE();
-  return FIRST_SPACE;
-}
-
-
 BackReference Serializer::AllocateLargeObject(int size) {
   // Large objects are allocated one-by-one when deserializing. We do not
   // have to keep track of multiple chunks.
@@ -2198,6 +2049,14 @@ void Serializer::InitializeCodeAddressMap() {
 }
 
 
+Code* Serializer::CopyCode(Code* code) {
+  code_buffer_.Rewind(0);  // Clear buffer without deleting backing store.
+  int size = code->CodeSize();
+  code_buffer_.AddAll(Vector<byte>(code->address(), size));
+  return Code::cast(HeapObject::FromAddress(&code_buffer_.first()));
+}
+
+
 ScriptData* CodeSerializer::Serialize(Isolate* isolate,
                                       Handle<SharedFunctionInfo> info,
                                       Handle<String> source) {
@@ -2400,7 +2259,7 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
   HandleScope scope(isolate);
 
   SmartPointer<SerializedCodeData> scd(
-      SerializedCodeData::FromCachedData(cached_data, *source));
+      SerializedCodeData::FromCachedData(isolate, cached_data, *source));
   if (scd.is_empty()) {
     if (FLAG_profile_deserialization) PrintF("[Cached code failed check]\n");
     DCHECK(cached_data->rejected());
@@ -2450,7 +2309,6 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
     isolate->logger()->CodeCreateEvent(Logger::SCRIPT_TAG, result->code(),
                                        *result, NULL, name);
   }
-
   return scope.CloseAndEscape(result);
 }
 
@@ -2478,6 +2336,7 @@ SnapshotData::SnapshotData(const Serializer& ser) {
   AllocateData(size);
 
   // Set header values.
+  SetMagicNumber(ser.isolate());
   SetHeaderValue(kCheckSumOffset, Version::Hash());
   SetHeaderValue(kNumReservationsOffset, reservations.length());
   SetHeaderValue(kPayloadLengthOffset, payload.length());
@@ -2568,7 +2427,7 @@ SerializedCodeData::SerializedCodeData(const List<byte>& payload,
   AllocateData(size);
 
   // Set header values.
-  SetHeaderValue(kMagicNumberOffset, kMagicNumber);
+  SetMagicNumber(cs.isolate());
   SetHeaderValue(kVersionHashOffset, Version::Hash());
   SetHeaderValue(kSourceHashOffset, SourceHash(cs.source()));
   SetHeaderValue(kCpuFeaturesOffset,
@@ -2600,15 +2459,15 @@ SerializedCodeData::SerializedCodeData(const List<byte>& payload,
 
 
 SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
-    String* source) const {
-  uint32_t magic_number = GetHeaderValue(kMagicNumberOffset);
+    Isolate* isolate, String* source) const {
+  uint32_t magic_number = GetMagicNumber();
   uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
   uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
   uint32_t cpu_features = GetHeaderValue(kCpuFeaturesOffset);
   uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
   uint32_t c1 = GetHeaderValue(kChecksum1Offset);
   uint32_t c2 = GetHeaderValue(kChecksum2Offset);
-  if (magic_number != kMagicNumber) return MAGIC_NUMBER_MISMATCH;
+  if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH;
   if (version_hash != Version::Hash()) return VERSION_MISMATCH;
   if (source_hash != SourceHash(source)) return SOURCE_MISMATCH;
   if (cpu_features != static_cast<uint32_t>(CpuFeatures::SupportedFeatures())) {
@@ -2668,11 +2527,12 @@ SerializedCodeData::SerializedCodeData(ScriptData* data)
     : SerializedData(const_cast<byte*>(data->data()), data->length()) {}
 
 
-SerializedCodeData* SerializedCodeData::FromCachedData(ScriptData* cached_data,
+SerializedCodeData* SerializedCodeData::FromCachedData(Isolate* isolate,
+                                                       ScriptData* cached_data,
                                                        String* source) {
   DisallowHeapAllocation no_gc;
   SerializedCodeData* scd = new SerializedCodeData(cached_data);
-  SanityCheckResult r = scd->SanityCheck(source);
+  SanityCheckResult r = scd->SanityCheck(isolate, source);
   if (r == CHECK_SUCCESS) return scd;
   cached_data->Reject();
   source->GetIsolate()->counters()->code_cache_reject_reason()->AddSample(r);
similarity index 78%
rename from deps/v8/src/serialize.h
rename to deps/v8/src/snapshot/serialize.h
index b76abbc..41c4286 100644 (file)
@@ -8,37 +8,14 @@
 #include "src/hashmap.h"
 #include "src/heap-profiler.h"
 #include "src/isolate.h"
-#include "src/snapshot-source-sink.h"
+#include "src/snapshot/snapshot-source-sink.h"
 
 namespace v8 {
 namespace internal {
 
 class ScriptData;
 
-// A TypeCode is used to distinguish different kinds of external reference.
-// It is a single bit to make testing for types easy.
-enum TypeCode {
-  UNCLASSIFIED,  // One-of-a-kind references.
-  C_BUILTIN,
-  BUILTIN,
-  RUNTIME_FUNCTION,
-  IC_UTILITY,
-  STATS_COUNTER,
-  TOP_ADDRESS,
-  ACCESSOR_CODE,
-  STUB_CACHE_TABLE,
-  RUNTIME_ENTRY,
-  LAZY_DEOPTIMIZATION
-};
-
-const int kTypeCodeCount = LAZY_DEOPTIMIZATION + 1;
-const int kFirstTypeCode = UNCLASSIFIED;
-
-const int kReferenceIdBits = 16;
-const int kReferenceIdMask = (1 << kReferenceIdBits) - 1;
-const int kReferenceTypeShift = kReferenceIdBits;
-
-const int kDeoptTableSerializeEntryCount = 64;
+static const int kDeoptTableSerializeEntryCount = 64;
 
 // ExternalReferenceTable is a helper class that defines the relationship
 // between external references and their encodings. It is used to build
@@ -47,46 +24,28 @@ class ExternalReferenceTable {
  public:
   static ExternalReferenceTable* instance(Isolate* isolate);
 
-  ~ExternalReferenceTable() { }
-
   int size() const { return refs_.length(); }
-
   Address address(int i) { return refs_[i].address; }
-
-  uint32_t code(int i) { return refs_[i].code; }
-
   const char* name(int i) { return refs_[i].name; }
 
-  int max_id(int code) { return max_id_[code]; }
+  inline static Address NotAvailable() { return NULL; }
 
  private:
-  explicit ExternalReferenceTable(Isolate* isolate) : refs_(64) {
-    PopulateTable(isolate);
-  }
-
   struct ExternalReferenceEntry {
     Address address;
-    uint32_t code;
     const char* name;
   };
 
-  void PopulateTable(Isolate* isolate);
-
-  // For a few types of references, we can get their address from their id.
-  void AddFromId(TypeCode type,
-                 uint16_t id,
-                 const char* name,
-                 Isolate* isolate);
-
-  // For other types of references, the caller will figure out the address.
-  void Add(Address address, TypeCode type, uint16_t id, const char* name);
+  explicit ExternalReferenceTable(Isolate* isolate);
 
   void Add(Address address, const char* name) {
-    Add(address, UNCLASSIFIED, ++max_id_[UNCLASSIFIED], name);
+    ExternalReferenceEntry entry = {address, name};
+    refs_.Add(entry);
   }
 
   List<ExternalReferenceEntry> refs_;
-  uint16_t max_id_[kTypeCodeCount];
+
+  DISALLOW_COPY_AND_ASSIGN(ExternalReferenceTable);
 };
 
 
@@ -96,47 +55,17 @@ class ExternalReferenceEncoder {
 
   uint32_t Encode(Address key) const;
 
-  const char* NameOfAddress(Address key) const;
+  const char* NameOfAddress(Isolate* isolate, Address address) const;
 
  private:
-  HashMap encodings_;
   static uint32_t Hash(Address key) {
-    return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key) >> 2);
+    return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key) >>
+                                 kPointerSizeLog2);
   }
 
-  int IndexOf(Address key) const;
-
-  void Put(Address key, int index);
-
-  Isolate* isolate_;
-};
-
-
-class ExternalReferenceDecoder {
- public:
-  explicit ExternalReferenceDecoder(Isolate* isolate);
-  ~ExternalReferenceDecoder();
-
-  Address Decode(uint32_t key) const {
-    if (key == 0) return NULL;
-    return *Lookup(key);
-  }
-
- private:
-  Address** encodings_;
-
-  Address* Lookup(uint32_t key) const {
-    int type = key >> kReferenceTypeShift;
-    DCHECK(kFirstTypeCode <= type && type < kTypeCodeCount);
-    int id = key & kReferenceIdMask;
-    return &encodings_[type][id];
-  }
-
-  void Put(uint32_t key, Address value) {
-    *Lookup(key) = value;
-  }
+  HashMap* map_;
 
-  Isolate* isolate_;
+  DISALLOW_COPY_AND_ASSIGN(ExternalReferenceEncoder);
 };
 
 
@@ -150,8 +79,8 @@ class AddressMapBase {
     return static_cast<uint32_t>(reinterpret_cast<intptr_t>(entry->value));
   }
 
-  static HashMap::Entry* LookupEntry(HashMap* map, HeapObject* obj,
-                                     bool insert) {
+  inline static HashMap::Entry* LookupEntry(HashMap* map, HeapObject* obj,
+                                            bool insert) {
     return map->Lookup(Key(obj), Hash(obj), insert);
   }
 
@@ -170,9 +99,8 @@ 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);
@@ -186,6 +114,28 @@ class RootIndexMap : public AddressMapBase {
 };
 
 
+class PartialCacheIndexMap : public AddressMapBase {
+ public:
+  PartialCacheIndexMap() : map_(HashMap::PointersMatch) {}
+
+  static const int kInvalidIndex = -1;
+
+  // Lookup object in the map. Return its index if found, or create
+  // a new entry with new_index as value, and return kInvalidIndex.
+  int LookupOrInsert(HeapObject* obj, int new_index) {
+    HashMap::Entry* entry = LookupEntry(&map_, obj, false);
+    if (entry != NULL) return GetValue(entry);
+    SetValue(LookupEntry(&map_, obj, true), static_cast<uint32_t>(new_index));
+    return kInvalidIndex;
+  }
+
+ private:
+  HashMap map_;
+
+  DISALLOW_COPY_AND_ASSIGN(PartialCacheIndexMap);
+};
+
+
 class BackReference {
  public:
   explicit BackReference(uint32_t bitfield) : bitfield_(bitfield) {}
@@ -353,113 +303,116 @@ class SerializerDeserializer: public ObjectVisitor {
   static const int kNumberOfSpaces = LAST_SPACE + 1;
 
  protected:
+  // ---------- byte code range 0x00..0x7f ----------
+  // Byte codes in this range represent Where, HowToCode and WhereToPoint.
   // Where the pointed-to object can be found:
   enum Where {
-    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.
-    // 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
+    // 0x00..0x05  Allocate new object, in specified space.
+    kNewObject = 0,
+    // 0x06        Unused (including 0x26, 0x46, 0x66).
+    // 0x07        Unused (including 0x27, 0x47, 0x67).
+    // 0x08..0x0d  Reference to previous object from space.
+    kBackref = 0x08,
+    // 0x0e        Unused (including 0x2e, 0x4e, 0x6e).
+    // 0x0f        Unused (including 0x2f, 0x4f, 0x6f).
+    // 0x10..0x15  Reference to previous object from space after skip.
+    kBackrefWithSkip = 0x10,
+    // 0x16        Unused (including 0x36, 0x56, 0x76).
+    // 0x17        Unused (including 0x37, 0x57, 0x77).
+    // 0x18        Root array item.
+    kRootArray = 0x18,
+    // 0x19        Object in the partial snapshot cache.
+    kPartialSnapshotCache = 0x19,
+    // 0x1a        External reference referenced by id.
+    kExternalReference = 0x1a,
+    // 0x1b        Object provided in the attached list.
+    kAttachedReference = 0x1b,
+    // 0x1c        Builtin code referenced by index.
+    kBuiltin = 0x1c
+    // 0x1d..0x1f  Misc (including 0x3d..0x3f, 0x5d..0x5f, 0x7d..0x7f)
   };
 
+  static const int kWhereMask = 0x1f;
+  static const int kSpaceMask = 7;
+  STATIC_ASSERT(kNumberOfSpaces <= kSpaceMask + 1);
+
   // How to code the pointer to the object.
   enum HowToCode {
-    kPlain = 0,                          // Straight pointer.
-    // What this means depends on the architecture:
-    kFromCode = 0x40,                    // A pointer inlined in code.
-    kHowToCodeMask = 0x40
+    // Straight pointer.
+    kPlain = 0,
+    // A pointer inlined in code. What this means depends on the architecture.
+    kFromCode = 0x20
   };
 
-  // For kRootArrayConstants
-  enum WithSkip {
-    kNoSkipDistance = 0,
-    kHasSkipDistance = 0x40,
-    kWithSkipMask = 0x40
-  };
+  static const int kHowToCodeMask = 0x20;
 
   // Where to point within the object.
   enum WhereToPoint {
+    // Points to start of object
     kStartOfObject = 0,
-    kInnerPointer = 0x80,  // First insn in code object or payload of cell.
-    kWhereToPointMask = 0x80
+    // Points to instruction in code object or payload of cell.
+    kInnerPointer = 0x40
   };
 
-  // Misc.
-  // Raw data to be copied from the snapshot.  This byte code does not advance
-  // the current pointer, which is used for code objects, where we write the
-  // 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.
-  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 <= kMaxFixedRepeats);
-    return kFixedRepeatBase + repeats;
-  }
-  static int RepeatsForCode(int byte_code) {
-    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.
-  static const int kRootArrayNumberOfConstantEncodings = 0x20;
-  static int RootArrayConstantFromByteCode(int byte_code) {
-    return byte_code & 0x1f;
-  }
+  static const int kWhereToPointMask = 0x40;
 
+  // ---------- Misc ----------
+  // Skip.
+  static const int kSkip = 0x1d;
+  // Internal reference encoded as offsets of pc and target from code entry.
+  static const int kInternalReference = 0x1e;
+  static const int kInternalReferenceEncoded = 0x1f;
   // Do nothing, used for padding.
-  static const int kNop = 0xf;
-
+  static const int kNop = 0x3d;
   // Move to next reserved chunk.
-  static const int kNextChunk = 0x4f;
-
+  static const int kNextChunk = 0x3e;
   // 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;
-
+  static const int kSynchronize = 0x5d;
   // 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 kNativesStringResource = 0x5e;
+  // Raw data of variable length.
+  static const int kVariableRawData = 0x7d;
+  // Repeats of variable length.
+  static const int kVariableRepeat = 0x7e;
+
+  // ---------- byte code range 0x80..0xff ----------
+  // First 32 root array items.
+  static const int kNumberOfRootArrayConstants = 0x20;
+  // 0x80..0x9f
+  static const int kRootArrayConstants = 0x80;
+  // 0xa0..0xbf
+  static const int kRootArrayConstantsWithSkip = 0xa0;
+  static const int kRootArrayConstantsMask = 0x1f;
+
+  // 8 hot (recently seen or back-referenced) objects with optional skip.
+  static const int kNumberOfHotObjects = 0x08;
+  // 0xc0..0xc7
+  static const int kHotObject = 0xc0;
+  // 0xc8..0xcf
+  static const int kHotObjectWithSkip = 0xc8;
+  static const int kHotObjectMask = 0x07;
+
+  // 32 common raw data lengths.
+  static const int kNumberOfFixedRawData = 0x20;
+  // 0xd0..0xef
+  static const int kFixedRawData = 0xd0;
+  static const int kOnePointerRawData = kFixedRawData;
+  static const int kFixedRawDataStart = kFixedRawData - 1;
+
+  // 16 repeats lengths.
+  static const int kNumberOfFixedRepeat = 0x10;
+  // 0xf0..0xff
+  static const int kFixedRepeat = 0xf0;
+  static const int kFixedRepeatStart = kFixedRepeat - 1;
+
+  // ---------- special values ----------
   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;
 
@@ -469,6 +422,7 @@ class SerializerDeserializer: public ObjectVisitor {
   // Used as index for the attached reference representing the global proxy.
   static const int kGlobalProxyReference = 0;
 
+  // ---------- member variable ----------
   HotObjectsList hot_objects_;
 };
 
@@ -497,9 +451,16 @@ class SerializedData {
     if (owns_data_) DeleteArray<byte>(data_);
   }
 
+  uint32_t GetMagicNumber() const { return GetHeaderValue(kMagicNumberOffset); }
+
   class ChunkSizeBits : public BitField<uint32_t, 0, 31> {};
   class IsLastChunkBits : public BitField<bool, 31, 1> {};
 
+  static uint32_t ComputeMagicNumber(ExternalReferenceTable* table) {
+    uint32_t external_refs = table->size();
+    return 0xC0DE0000 ^ external_refs;
+  }
+
  protected:
   void SetHeaderValue(int offset, uint32_t value) {
     uint32_t* address = reinterpret_cast<uint32_t*>(data_ + offset);
@@ -514,6 +475,16 @@ class SerializedData {
 
   void AllocateData(int size);
 
+  static uint32_t ComputeMagicNumber(Isolate* isolate) {
+    return ComputeMagicNumber(ExternalReferenceTable::instance(isolate));
+  }
+
+  void SetMagicNumber(Isolate* isolate) {
+    SetHeaderValue(kMagicNumberOffset, ComputeMagicNumber(isolate));
+  }
+
+  static const int kMagicNumberOffset = 0;
+
   byte* data_;
   int size_;
   bool owns_data_;
@@ -528,7 +499,8 @@ class Deserializer: public SerializerDeserializer {
   explicit Deserializer(Data* data)
       : isolate_(NULL),
         source_(data->Payload()),
-        external_reference_decoder_(NULL),
+        magic_number_(data->GetMagicNumber()),
+        external_reference_table_(NULL),
         deserialized_large_objects_(0),
         deserializing_user_code_(false) {
     DecodeReservation(data->Reservations());
@@ -602,6 +574,8 @@ class Deserializer: public SerializerDeserializer {
   Vector<Handle<Object> > attached_objects_;
 
   SnapshotByteSource source_;
+  uint32_t magic_number_;
+
   // 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
@@ -610,7 +584,7 @@ class Deserializer: public SerializerDeserializer {
   uint32_t current_chunk_[kNumberOfPreallocatedSpaces];
   Address high_water_[kNumberOfPreallocatedSpaces];
 
-  ExternalReferenceDecoder* external_reference_decoder_;
+  ExternalReferenceTable* external_reference_table_;
 
   List<HeapObject*> deserialized_large_objects_;
 
@@ -639,23 +613,21 @@ class Serializer : public SerializerDeserializer {
  protected:
   class ObjectSerializer : public ObjectVisitor {
    public:
-    ObjectSerializer(Serializer* serializer,
-                     Object* o,
-                     SnapshotByteSink* sink,
-                     HowToCode how_to_code,
-                     WhereToPoint where_to_point)
-      : serializer_(serializer),
-        object_(HeapObject::cast(o)),
-        sink_(sink),
-        reference_representation_(how_to_code + where_to_point),
-        bytes_processed_so_far_(0),
-        code_object_(o->IsCode()),
-        code_has_been_output_(false) { }
+    ObjectSerializer(Serializer* serializer, Object* o, SnapshotByteSink* sink,
+                     HowToCode how_to_code, WhereToPoint where_to_point)
+        : serializer_(serializer),
+          object_(HeapObject::cast(o)),
+          sink_(sink),
+          reference_representation_(how_to_code + where_to_point),
+          bytes_processed_so_far_(0),
+          is_code_object_(o->IsCode()),
+          code_has_been_output_(false) {}
     void Serialize();
     void VisitPointers(Object** start, Object** end);
     void VisitEmbeddedPointer(RelocInfo* target);
     void VisitExternalReference(Address* p);
     void VisitExternalReference(RelocInfo* rinfo);
+    void VisitInternalReference(RelocInfo* rinfo);
     void VisitCodeTarget(RelocInfo* target);
     void VisitCodeEntry(Address entry_address);
     void VisitCell(RelocInfo* rinfo);
@@ -681,12 +653,14 @@ class Serializer : public SerializerDeserializer {
     // External strings are serialized in a way to resemble sequential strings.
     void SerializeExternalString();
 
+    Address PrepareCode();
+
     Serializer* serializer_;
     HeapObject* object_;
     SnapshotByteSink* sink_;
     int reference_representation_;
     int bytes_processed_so_far_;
-    bool code_object_;
+    bool is_code_object_;
     bool code_has_been_output_;
   };
 
@@ -710,11 +684,10 @@ class Serializer : public SerializerDeserializer {
   bool BackReferenceIsAlreadyAllocated(BackReference back_reference);
 
   // This will return the space for an object.
-  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);
+    return external_reference_encoder_.Encode(addr);
   }
 
   // GetInt reads 4 bytes at once, requiring padding at the end.
@@ -728,6 +701,8 @@ class Serializer : public SerializerDeserializer {
   // of the serializer.  Initialize it on demand.
   void InitializeCodeAddressMap();
 
+  Code* CopyCode(Code* code);
+
   inline uint32_t max_chunk_size(int space) const {
     DCHECK_LE(0, space);
     DCHECK_LT(space, kNumberOfSpaces);
@@ -739,7 +714,7 @@ class Serializer : public SerializerDeserializer {
   Isolate* isolate_;
 
   SnapshotByteSink* sink_;
-  ExternalReferenceEncoder* external_reference_encoder_;
+  ExternalReferenceEncoder external_reference_encoder_;
 
   BackReferenceMap back_reference_map_;
   RootIndexMap root_index_map_;
@@ -762,6 +737,8 @@ class Serializer : public SerializerDeserializer {
   uint32_t large_objects_total_size_;
   uint32_t seen_large_objects_index_;
 
+  List<byte> code_buffer_;
+
   DISALLOW_COPY_AND_ASSIGN(Serializer);
 };
 
@@ -802,6 +779,7 @@ class PartialSerializer : public Serializer {
   Serializer* startup_serializer_;
   List<BackReference> outdated_contexts_;
   Object* global_object_;
+  PartialCacheIndexMap partial_cache_index_map_;
   DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
 };
 
@@ -814,7 +792,7 @@ class StartupSerializer : public Serializer {
     // strong roots have been serialized we can create a partial snapshot
     // which will repopulate the cache with objects needed by that partial
     // snapshot.
-    isolate->set_serialize_partial_snapshot_cache_length(0);
+    isolate->partial_snapshot_cache()->Clear();
     InitializeCodeAddressMap();
   }
 
@@ -917,13 +895,15 @@ class SnapshotData : public SerializedData {
 
  private:
   bool IsSane();
+
   // The data header consists of uint32_t-sized entries:
-  // [0] version hash
-  // [1] number of reservation size entries
-  // [2] payload length
+  // [0] magic number and external reference count
+  // [1] version hash
+  // [2] number of reservation size entries
+  // [3] payload length
   // ... reservations
   // ... serialized payload
-  static const int kCheckSumOffset = 0;
+  static const int kCheckSumOffset = kMagicNumberOffset + kInt32Size;
   static const int kNumReservationsOffset = kCheckSumOffset + kInt32Size;
   static const int kPayloadLengthOffset = kNumReservationsOffset + kInt32Size;
   static const int kHeaderSize = kPayloadLengthOffset + kInt32Size;
@@ -934,7 +914,8 @@ class SnapshotData : public SerializedData {
 class SerializedCodeData : public SerializedData {
  public:
   // Used when consuming.
-  static SerializedCodeData* FromCachedData(ScriptData* cached_data,
+  static SerializedCodeData* FromCachedData(Isolate* isolate,
+                                            ScriptData* cached_data,
                                             String* source);
 
   // Used when producing.
@@ -959,17 +940,15 @@ class SerializedCodeData : public SerializedData {
     SOURCE_MISMATCH = 3,
     CPU_FEATURES_MISMATCH = 4,
     FLAGS_MISMATCH = 5,
-    CHECKSUM_MISMATCH = 6,
+    CHECKSUM_MISMATCH = 6
   };
 
-  SanityCheckResult SanityCheck(String* source) const;
+  SanityCheckResult SanityCheck(Isolate* isolate, String* source) const;
 
   uint32_t SourceHash(String* source) const { return source->length(); }
 
-  static const uint32_t kMagicNumber = 0xC0D1F1ED;
-
   // The data header consists of uint32_t-sized entries:
-  // [ 0] magic number
+  // [ 0] magic number and external reference count
   // [ 1] version hash
   // [ 2] source hash
   // [ 3] cpu features
@@ -983,7 +962,6 @@ class SerializedCodeData : public SerializedData {
   // ...  reservations
   // ...  code stub keys
   // ...  serialized payload
-  static const int kMagicNumberOffset = 0;
   static const int kVersionHashOffset = kMagicNumberOffset + kInt32Size;
   static const int kSourceHashOffset = kVersionHashOffset + kInt32Size;
   static const int kCpuFeaturesOffset = kSourceHashOffset + kInt32Size;
similarity index 79%
rename from deps/v8/src/snapshot-common.cc
rename to deps/v8/src/snapshot/snapshot-common.cc
index 637bac0..6d760b5 100644 (file)
@@ -9,16 +9,11 @@
 #include "src/api.h"
 #include "src/base/platform/platform.h"
 #include "src/full-codegen.h"
-#include "src/snapshot.h"
+#include "src/snapshot/snapshot.h"
 
 namespace v8 {
 namespace internal {
 
-bool Snapshot::HaveASnapshotToStartFrom() {
-  return SnapshotBlob().data != NULL;
-}
-
-
 #ifdef DEBUG
 bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
   return !Snapshot::ExtractStartupData(snapshot_blob).is_empty() &&
@@ -27,32 +22,31 @@ bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
 #endif  // DEBUG
 
 
-bool Snapshot::EmbedsScript() {
-  if (!HaveASnapshotToStartFrom()) return false;
-  const v8::StartupData blob = SnapshotBlob();
-  return ExtractMetadata(&blob).embeds_script();
+bool Snapshot::EmbedsScript(Isolate* isolate) {
+  if (!isolate->snapshot_available()) return false;
+  return ExtractMetadata(isolate->snapshot_blob()).embeds_script();
 }
 
 
-uint32_t Snapshot::SizeOfFirstPage(AllocationSpace space) {
+uint32_t Snapshot::SizeOfFirstPage(Isolate* isolate, AllocationSpace space) {
   DCHECK(space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE);
-  if (!HaveASnapshotToStartFrom()) {
+  if (!isolate->snapshot_available()) {
     return static_cast<uint32_t>(MemoryAllocator::PageAreaSize(space));
   }
   uint32_t size;
   int offset = kFirstPageSizesOffset + (space - FIRST_PAGED_SPACE) * kInt32Size;
-  memcpy(&size, SnapshotBlob().data + offset, kInt32Size);
+  memcpy(&size, isolate->snapshot_blob()->data + offset, kInt32Size);
   return size;
 }
 
 
 bool Snapshot::Initialize(Isolate* isolate) {
-  if (!HaveASnapshotToStartFrom()) return false;
+  if (!isolate->snapshot_available()) return false;
   base::ElapsedTimer timer;
   if (FLAG_profile_deserialization) timer.Start();
 
-  const v8::StartupData blob = SnapshotBlob();
-  Vector<const byte> startup_data = ExtractStartupData(&blob);
+  const v8::StartupData* blob = isolate->snapshot_blob();
+  Vector<const byte> startup_data = ExtractStartupData(blob);
   SnapshotData snapshot_data(startup_data);
   Deserializer deserializer(&snapshot_data);
   bool success = isolate->Init(&deserializer);
@@ -68,12 +62,12 @@ bool Snapshot::Initialize(Isolate* isolate) {
 MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
     Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
     Handle<FixedArray>* outdated_contexts_out) {
-  if (!HaveASnapshotToStartFrom()) return Handle<Context>();
+  if (!isolate->snapshot_available()) return Handle<Context>();
   base::ElapsedTimer timer;
   if (FLAG_profile_deserialization) timer.Start();
 
-  const v8::StartupData blob = SnapshotBlob();
-  Vector<const byte> context_data = ExtractContextData(&blob);
+  const v8::StartupData* blob = isolate->snapshot_blob();
+  Vector<const byte> context_data = ExtractContextData(blob);
   SnapshotData snapshot_data(context_data);
   Deserializer deserializer(&snapshot_data);
 
@@ -84,7 +78,7 @@ MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
   CHECK(result->IsContext());
   // If the snapshot does not contain a custom script, we need to update
   // the global object for exactly one context.
-  CHECK(EmbedsScript() || (*outdated_contexts_out)->length() == 1);
+  CHECK(EmbedsScript(isolate) || (*outdated_contexts_out)->length() == 1);
   if (FLAG_profile_deserialization) {
     double ms = timer.Elapsed().InMillisecondsF();
     int bytes = context_data.length();
@@ -104,6 +98,23 @@ void CalculateFirstPageSizes(bool is_default_snapshot,
       context_snapshot.Reservations();
   int startup_index = 0;
   int context_index = 0;
+
+  if (FLAG_profile_deserialization) {
+    int startup_total = 0;
+    int context_total = 0;
+    for (auto& reservation : startup_reservations) {
+      startup_total += reservation.chunk_size();
+    }
+    for (auto& reservation : context_reservations) {
+      context_total += reservation.chunk_size();
+    }
+    PrintF(
+        "Deserialization will reserve:\n"
+        "%10d bytes for startup\n"
+        "%10d bytes per context\n",
+        startup_total, context_total);
+  }
+
   for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) {
     bool single_chunk = true;
     while (!startup_reservations[startup_index].is_last()) {
@@ -124,6 +135,8 @@ void CalculateFirstPageSizes(bool is_default_snapshot,
       required = (startup_reservations[startup_index].chunk_size() +
                   2 * context_reservations[context_index].chunk_size()) +
                  Page::kObjectStartOffset;
+      // Add a small allowance to the code space for small scripts.
+      if (space == CODE_SPACE) required += 32 * KB;
     } else {
       // We expect the vanilla snapshot to only require on page per space.
       DCHECK(!is_default_snapshot);
@@ -155,7 +168,7 @@ v8::StartupData Snapshot::CreateSnapshotBlob(
 
   uint32_t first_page_sizes[kNumPagedSpaces];
 
-  CalculateFirstPageSizes(metadata.embeds_script(), startup_snapshot,
+  CalculateFirstPageSizes(!metadata.embeds_script(), startup_snapshot,
                           context_snapshot, first_page_sizes);
 
   int startup_length = startup_data.length();
@@ -172,6 +185,14 @@ v8::StartupData Snapshot::CreateSnapshotBlob(
   memcpy(data + kStartupDataOffset, startup_data.begin(), startup_length);
   memcpy(data + context_offset, context_data.begin(), context_length);
   v8::StartupData result = {data, length};
+
+  if (FLAG_profile_deserialization) {
+    PrintF(
+        "Snapshot blob consists of:\n"
+        "%10d bytes for startup\n"
+        "%10d bytes for context\n",
+        startup_length, context_length);
+  }
   return result;
 }
 
similarity index 83%
rename from deps/v8/src/snapshot-empty.cc
rename to deps/v8/src/snapshot/snapshot-empty.cc
index 020d1cb..0eea940 100644 (file)
@@ -6,7 +6,7 @@
 
 #include "src/v8.h"
 
-#include "src/snapshot.h"
+#include "src/snapshot/snapshot.h"
 
 namespace v8 {
 namespace internal {
@@ -19,10 +19,10 @@ namespace internal {
 // below. This happens when compiling the mksnapshot utility.
 void SetNativesFromFile(StartupData* data) { CHECK(false); }
 void SetSnapshotFromFile(StartupData* data) { CHECK(false); }
+void ReadNatives() {}
+void DisposeNatives() {}
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
 
 
-const v8::StartupData Snapshot::SnapshotBlob() {
-  return {NULL, 0};
-}
+const v8::StartupData* Snapshot::DefaultSnapshotBlob() { return NULL; }
 } }  // namespace v8::internal
similarity index 84%
rename from deps/v8/src/snapshot-external.cc
rename to deps/v8/src/snapshot/snapshot-external.cc
index a9a5df1..f5e3de4 100644 (file)
@@ -4,11 +4,11 @@
 
 // Used for building with external snapshots.
 
-#include "src/snapshot.h"
+#include "src/snapshot/snapshot.h"
 
 #include "src/base/platform/mutex.h"
-#include "src/serialize.h"
-#include "src/snapshot-source-sink.h"
+#include "src/snapshot/serialize.h"
+#include "src/snapshot/snapshot-source-sink.h"
 #include "src/v8.h"  // for V8::Initialize
 
 
@@ -35,9 +35,9 @@ void SetSnapshotFromFile(StartupData* snapshot_blob) {
 }
 
 
-const v8::StartupData Snapshot::SnapshotBlob() {
+const v8::StartupData* Snapshot::DefaultSnapshotBlob() {
   base::LockGuard<base::Mutex> lock_guard(
       external_startup_data_mutex.Pointer());
-  return external_startup_blob;
+  return &external_startup_blob;
 }
 } }  // namespace v8::internal
similarity index 79%
rename from deps/v8/src/snapshot-source-sink.cc
rename to deps/v8/src/snapshot/snapshot-source-sink.cc
index fd94724..c0179b7 100644 (file)
@@ -3,28 +3,18 @@
 // found in the LICENSE file.
 
 
-#include "src/snapshot-source-sink.h"
+#include "src/snapshot/snapshot-source-sink.h"
 
 #include "src/base/logging.h"
 #include "src/handles-inl.h"
-#include "src/serialize.h"  // for SerializerDeserializer::nop() in AtEOF()
+#include "src/snapshot/serialize.h"  // for SerializerDeserializer::nop()
 
 
 namespace v8 {
 namespace internal {
 
-int32_t SnapshotByteSource::GetUnalignedInt() {
-  DCHECK(position_ < length_);  // Require at least one byte left.
-  int32_t answer = data_[position_];
-  answer |= data_[position_ + 1] << 8;
-  answer |= data_[position_ + 2] << 16;
-  answer |= data_[position_ + 3] << 24;
-  return answer;
-}
-
-
 void SnapshotByteSource::CopyRaw(byte* to, int number_of_bytes) {
-  MemCopy(to, data_ + position_, number_of_bytes);
+  memcpy(to, data_ + position_, number_of_bytes);
   position_ += number_of_bytes;
 }
 
similarity index 87%
rename from deps/v8/src/snapshot-source-sink.h
rename to deps/v8/src/snapshot/snapshot-source-sink.h
index 66feaec..6612029 100644 (file)
@@ -36,16 +36,18 @@ class SnapshotByteSource FINAL {
     return data_[position_++];
   }
 
-  int32_t GetUnalignedInt();
-
   void Advance(int by) { position_ += by; }
 
   void CopyRaw(byte* to, int number_of_bytes);
 
   inline int GetInt() {
-    // This way of variable-length encoding integers does not suffer from branch
-    // mispredictions.
-    uint32_t answer = GetUnalignedInt();
+    // This way of decoding variable-length encoded integers does not
+    // suffer from branch mispredictions.
+    DCHECK(position_ + 3 < length_);
+    uint32_t answer = data_[position_];
+    answer |= data_[position_ + 1] << 8;
+    answer |= data_[position_ + 2] << 16;
+    answer |= data_[position_ + 3] << 24;
     int bytes = (answer & 3) + 1;
     Advance(bytes);
     uint32_t mask = 0xffffffffu;
similarity index 86%
rename from deps/v8/src/snapshot.h
rename to deps/v8/src/snapshot/snapshot.h
index 3135756..d2eaaa2 100644 (file)
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "src/isolate.h"
-#include "src/serialize.h"
+#include "src/snapshot/serialize.h"
 
 #ifndef V8_SNAPSHOT_H_
 #define V8_SNAPSHOT_H_
@@ -36,14 +36,18 @@ class Snapshot : public AllStatic {
       Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
       Handle<FixedArray>* outdated_contexts_out);
 
-  static bool HaveASnapshotToStartFrom();
+  static bool HaveASnapshotToStartFrom(Isolate* isolate) {
+    // Do not use snapshots if the isolate is used to create snapshots.
+    return isolate->snapshot_blob() != NULL;
+  }
+
+  static bool EmbedsScript(Isolate* isolate);
 
-  static bool EmbedsScript();
+  static uint32_t SizeOfFirstPage(Isolate* isolate, AllocationSpace space);
 
-  static uint32_t SizeOfFirstPage(AllocationSpace space);
 
   // To be implemented by the snapshot source.
-  static const v8::StartupData SnapshotBlob();
+  static const v8::StartupData* DefaultSnapshotBlob();
 
   static v8::StartupData CreateSnapshotBlob(
       const StartupSerializer& startup_ser,
index f5eef37..df31c13 100644 (file)
@@ -2,13 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+(function() {
+
 "use strict";
 
+%CheckIsBootstrapping();
 
-// This file relies on the fact that the following declaration has been made
-// in runtime.js:
-// var $String = global.String;
+var GlobalArray = global.Array;
+var GlobalObject = global.Object;
+var GlobalString = global.String;
 
+//-------------------------------------------------------------------
 
 var stringIteratorIteratedStringSymbol =
     GLOBAL_PRIVATE("StringIterator#iteratedString");
@@ -75,35 +79,27 @@ function StringIteratorNext() {
 }
 
 
-function SetUpStringIterator() {
-  %CheckIsBootstrapping();
-
-  %FunctionSetPrototype(StringIterator, new $Object());
-  %FunctionSetInstanceClassName(StringIterator, 'String Iterator');
-
-  InstallFunctions(StringIterator.prototype, DONT_ENUM, $Array(
-    'next', StringIteratorNext
-  ));
-  %FunctionSetName(StringIteratorIterator, '[Symbol.iterator]');
-  %AddNamedProperty(StringIterator.prototype, symbolIterator,
-                    StringIteratorIterator, DONT_ENUM);
-  %AddNamedProperty(StringIterator.prototype, symbolToStringTag,
-                    "String Iterator", READ_ONLY | DONT_ENUM);
-}
-SetUpStringIterator();
-
-
 // 21.1.3.27 String.prototype [ @@iterator ]( )
 function StringPrototypeIterator() {
   return CreateStringIterator(this);
 }
 
+//-------------------------------------------------------------------
 
-function ExtendStringPrototypeWithIterator() {
-  %CheckIsBootstrapping();
+%FunctionSetPrototype(StringIterator, new GlobalObject());
+%FunctionSetInstanceClassName(StringIterator, 'String Iterator');
 
-  %FunctionSetName(StringPrototypeIterator, '[Symbol.iterator]');
-  %AddNamedProperty($String.prototype, symbolIterator,
-                    StringPrototypeIterator, DONT_ENUM);
-}
-ExtendStringPrototypeWithIterator();
+InstallFunctions(StringIterator.prototype, DONT_ENUM, GlobalArray(
+  'next', StringIteratorNext
+));
+%FunctionSetName(StringIteratorIterator, '[Symbol.iterator]');
+%AddNamedProperty(StringIterator.prototype, symbolIterator,
+                  StringIteratorIterator, DONT_ENUM);
+%AddNamedProperty(StringIterator.prototype, symbolToStringTag,
+                  "String Iterator", READ_ONLY | DONT_ENUM);
+
+%FunctionSetName(StringPrototypeIterator, '[Symbol.iterator]');
+%AddNamedProperty(GlobalString.prototype, symbolIterator,
+                  StringPrototypeIterator, DONT_ENUM);
+
+})();
index ac5cb7f..0f29cd1 100644 (file)
@@ -2,11 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This file relies on the fact that the following declaration has been made
-// in runtime.js:
-// var $String = global.String;
+var $stringCharAt;
+var $stringIndexOf;
+var $stringSubstring;
 
-// -------------------------------------------------------------------
+(function() {
+
+%CheckIsBootstrapping();
+
+var GlobalArray = global.Array;
+var GlobalRegExp = global.RegExp;
+var GlobalString = global.String;
+
+//-------------------------------------------------------------------
 
 function StringConstructor(x) {
   if (%_ArgumentsLength() == 0) x = '';
@@ -14,7 +22,7 @@ function StringConstructor(x) {
     %_SetValueOf(this, TO_STRING_INLINE(x));
   } else {
     return IS_SYMBOL(x) ?
-        %_CallFunction(x, SymbolToString) : TO_STRING_INLINE(x);
+        %_CallFunction(x, $symbolToString) : TO_STRING_INLINE(x);
   }
 }
 
@@ -38,7 +46,7 @@ function StringValueOf() {
 
 
 // ECMA-262, section 15.5.4.4
-function StringCharAt(pos) {
+function StringCharAtJS(pos) {
   CHECK_OBJECT_COERCIBLE(this, "String.prototype.charAt");
 
   var result = %_StringCharAt(this, pos);
@@ -50,7 +58,7 @@ function StringCharAt(pos) {
 
 
 // ECMA-262 section 15.5.4.5
-function StringCharCodeAt(pos) {
+function StringCharCodeAtJS(pos) {
   CHECK_OBJECT_COERCIBLE(this, "String.prototype.charCodeAt");
 
   var result = %_StringCharCodeAt(this, pos);
@@ -64,11 +72,10 @@ function StringCharCodeAt(pos) {
 // ECMA-262, section 15.5.4.6
 function StringConcat(other /* and more */) {  // length == 1
   CHECK_OBJECT_COERCIBLE(this, "String.prototype.concat");
-
   var len = %_ArgumentsLength();
   var this_as_string = TO_STRING_INLINE(this);
   if (len === 1) {
-    return this_as_string + other;
+    return this_as_string + TO_STRING_INLINE(other);
   }
   var parts = new InternalArray(len + 1);
   parts[0] = this_as_string;
@@ -147,16 +154,15 @@ function StringMatchJS(regexp) {
     // value is discarded.
     var lastIndex = regexp.lastIndex;
     TO_INTEGER_FOR_SIDE_EFFECT(lastIndex);
-    if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0);
-    // lastMatchInfo is defined in regexp.js.
-    var result = %StringMatch(subject, regexp, lastMatchInfo);
-    if (result !== null) lastMatchInfoOverride = null;
+    if (!regexp.global) return $regexpExecNoTests(regexp, subject, 0);
+    var result = %StringMatch(subject, regexp, $regexpLastMatchInfo);
+    if (result !== null) $regexpLastMatchInfoOverride = null;
     regexp.lastIndex = 0;
     return result;
   }
   // Non-regexp argument.
-  regexp = new $RegExp(regexp);
-  return RegExpExecNoTests(regexp, subject, 0);
+  regexp = new GlobalRegExp(regexp);
+  return $regexpExecNoTests(regexp, subject, 0);
 }
 
 
@@ -182,9 +188,9 @@ function StringNormalizeJS(form) {
 }
 
 
-// This has the same size as the lastMatchInfo array, and can be used for
-// functions that expect that structure to be returned.  It is used when the
-// needle is a string rather than a regexp.  In this case we can't update
+// This has the same size as the $regexpLastMatchInfo array, and can be used
+// for functions that expect that structure to be returned.  It is used when
+// the needle is a string rather than a regexp.  In this case we can't update
 // lastMatchArray without erroneously affecting the properties on the global
 // RegExp object.
 var reusableMatchInfo = [2, "", "", -1, -1];
@@ -224,7 +230,7 @@ function StringReplace(search, replace) {
 
       if (!search.global) {
         // Non-global regexp search, string replace.
-        var match = DoRegExpExec(search, subject, 0);
+        var match = $regexpExec(search, subject, 0);
         if (match == null) {
           search.lastIndex = 0
           return subject;
@@ -233,28 +239,28 @@ function StringReplace(search, replace) {
           return %_SubString(subject, 0, match[CAPTURE0]) +
                  %_SubString(subject, match[CAPTURE1], subject.length)
         }
-        return ExpandReplacement(replace, subject, lastMatchInfo,
+        return ExpandReplacement(replace, subject, $regexpLastMatchInfo,
                                  %_SubString(subject, 0, match[CAPTURE0])) +
                %_SubString(subject, match[CAPTURE1], subject.length);
       }
 
       // Global regexp search, string replace.
       search.lastIndex = 0;
-      if (lastMatchInfoOverride == null) {
+      if ($regexpLastMatchInfoOverride == null) {
         return %StringReplaceGlobalRegExpWithString(
-            subject, search, replace, lastMatchInfo);
+            subject, search, replace, $regexpLastMatchInfo);
       } else {
         // We use this hack to detect whether StringReplaceRegExpWithString
         // found at least one hit. In that case we need to remove any
         // override.
-        var saved_subject = lastMatchInfo[LAST_SUBJECT_INDEX];
-        lastMatchInfo[LAST_SUBJECT_INDEX] = 0;
+        var saved_subject = $regexpLastMatchInfo[LAST_SUBJECT_INDEX];
+        $regexpLastMatchInfo[LAST_SUBJECT_INDEX] = 0;
         var answer = %StringReplaceGlobalRegExpWithString(
-            subject, search, replace, lastMatchInfo);
-        if (%_IsSmi(lastMatchInfo[LAST_SUBJECT_INDEX])) {
-          lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject;
+            subject, search, replace, $regexpLastMatchInfo);
+        if (%_IsSmi($regexpLastMatchInfo[LAST_SUBJECT_INDEX])) {
+          $regexpLastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject;
         } else {
-          lastMatchInfoOverride = null;
+          $regexpLastMatchInfoOverride = null;
         }
         return answer;
       }
@@ -418,7 +424,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
   }
   var res = %RegExpExecMultiple(regexp,
                                 subject,
-                                lastMatchInfo,
+                                $regexpLastMatchInfo,
                                 resultArray);
   regexp.lastIndex = 0;
   if (IS_NULL(res)) {
@@ -427,7 +433,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
     return subject;
   }
   var len = res.length;
-  if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
+  if (NUMBER_OF_CAPTURES($regexpLastMatchInfo) == 2) {
     // If the number of captures is two then there are no explicit captures in
     // the regexp, just the implicit capture that captures the whole match.  In
     // this case we can simplify quite a bit and end up with something faster.
@@ -451,7 +457,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
       } else {
         override[0] = elem;
         override[1] = match_start;
-        lastMatchInfoOverride = override;
+        $regexpLastMatchInfoOverride = override;
         var func_result =
             %_CallFunction(receiver, elem, match_start, subject, replace);
         // Overwrite the i'th element in the results with the string we got
@@ -467,7 +473,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
       if (!%_IsSmi(elem)) {
         // elem must be an Array.
         // Use the apply argument as backing for global RegExp properties.
-        lastMatchInfoOverride = elem;
+        $regexpLastMatchInfoOverride = elem;
         var func_result = %Apply(replace, receiver, elem, 0, elem.length);
         // Overwrite the i'th element in the results with the string we got
         // back from the callback function.
@@ -483,7 +489,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
 
 
 function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
-  var matchInfo = DoRegExpExec(regexp, subject, 0);
+  var matchInfo = $regexpExec(regexp, subject, 0);
   if (IS_NULL(matchInfo)) {
     regexp.lastIndex = 0;
     return subject;
@@ -530,9 +536,9 @@ function StringSearch(re) {
   } else if (IS_REGEXP(re)) {
     regexp = re;
   } else {
-    regexp = new $RegExp(re);
+    regexp = new GlobalRegExp(re);
   }
-  var match = DoRegExpExec(regexp, TO_STRING_INLINE(this), 0);
+  var match = $regexpExec(regexp, TO_STRING_INLINE(this), 0);
   if (match) {
     return match[CAPTURE0];
   }
@@ -618,7 +624,7 @@ function StringSplitJS(separator, limit) {
 
 function StringSplitOnRegExp(subject, separator, limit, length) {
   if (length === 0) {
-    if (DoRegExpExec(separator, subject, 0, 0) != null) {
+    if ($regexpExec(separator, subject, 0, 0) != null) {
       return [];
     }
     return [subject];
@@ -637,7 +643,7 @@ function StringSplitOnRegExp(subject, separator, limit, length) {
       break;
     }
 
-    var matchInfo = DoRegExpExec(separator, subject, startIndex);
+    var matchInfo = $regexpExec(separator, subject, startIndex);
     if (matchInfo == null || length === (startMatch = matchInfo[CAPTURE0])) {
       result[result.length] = %_SubString(subject, currentIndex, length);
       break;
@@ -924,62 +930,255 @@ function StringSup() {
   return "<sup>" + this + "</sup>";
 }
 
+// ES6 draft 01-20-14, section 21.1.3.13
+function StringRepeat(count) {
+  CHECK_OBJECT_COERCIBLE(this, "String.prototype.repeat");
+
+  var s = TO_STRING_INLINE(this);
+  var n = ToInteger(count);
+  // 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 r = "";
+  while (true) {
+    if (n & 1) r += s;
+    n >>= 1;
+    if (n === 0) return r;
+    s += s;
+  }
+}
+
+
+// ES6 draft 04-05-14, section 21.1.3.18
+function StringStartsWith(searchString /* position */) {  // length == 1
+  CHECK_OBJECT_COERCIBLE(this, "String.prototype.startsWith");
+
+  var s = TO_STRING_INLINE(this);
+
+  if (IS_REGEXP(searchString)) {
+    throw MakeTypeError("first_argument_not_regexp",
+                        ["String.prototype.startsWith"]);
+  }
+
+  var ss = TO_STRING_INLINE(searchString);
+  var pos = 0;
+  if (%_ArgumentsLength() > 1) {
+    pos = %_Arguments(1);  // position
+    pos = ToInteger(pos);
+  }
+
+  var s_len = s.length;
+  var start = $min($max(pos, 0), s_len);
+  var ss_len = ss.length;
+  if (ss_len + start > s_len) {
+    return false;
+  }
+
+  return %StringIndexOf(s, ss, start) === start;
+}
+
+
+// ES6 draft 04-05-14, section 21.1.3.7
+function StringEndsWith(searchString /* position */) {  // length == 1
+  CHECK_OBJECT_COERCIBLE(this, "String.prototype.endsWith");
+
+  var s = TO_STRING_INLINE(this);
+
+  if (IS_REGEXP(searchString)) {
+    throw MakeTypeError("first_argument_not_regexp",
+                        ["String.prototype.endsWith"]);
+  }
+
+  var ss = TO_STRING_INLINE(searchString);
+  var s_len = s.length;
+  var pos = s_len;
+  if (%_ArgumentsLength() > 1) {
+    var arg = %_Arguments(1);  // position
+    if (!IS_UNDEFINED(arg)) {
+      pos = ToInteger(arg);
+    }
+  }
+
+  var end = $min($max(pos, 0), s_len);
+  var ss_len = ss.length;
+  var start = end - ss_len;
+  if (start < 0) {
+    return false;
+  }
+
+  return %StringLastIndexOf(s, ss, start) === start;
+}
+
+
+// ES6 draft 04-05-14, section 21.1.3.6
+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.includes"]);
+  }
+
+  var ss = TO_STRING_INLINE(searchString);
+  var pos = 0;
+  if (%_ArgumentsLength() > 1) {
+    pos = %_Arguments(1);  // position
+    pos = ToInteger(pos);
+  }
+
+  var s_len = s.length;
+  var start = $min($max(pos, 0), s_len);
+  var ss_len = ss.length;
+  if (ss_len + start > s_len) {
+    return false;
+  }
+
+  return %StringIndexOf(s, ss, start) !== -1;
+}
+
+
+// ES6 Draft 05-22-2014, section 21.1.3.3
+function StringCodePointAt(pos) {
+  CHECK_OBJECT_COERCIBLE(this, "String.prototype.codePointAt");
+
+  var string = TO_STRING_INLINE(this);
+  var size = string.length;
+  pos = TO_INTEGER(pos);
+  if (pos < 0 || pos >= size) {
+    return UNDEFINED;
+  }
+  var first = %_StringCharCodeAt(string, pos);
+  if (first < 0xD800 || first > 0xDBFF || pos + 1 == size) {
+    return first;
+  }
+  var second = %_StringCharCodeAt(string, pos + 1);
+  if (second < 0xDC00 || second > 0xDFFF) {
+    return first;
+  }
+  return (first - 0xD800) * 0x400 + second + 0x2400;
+}
+
+
+// ES6 Draft 05-22-2014, section 21.1.2.2
+function StringFromCodePoint(_) {  // length = 1
+  var code;
+  var length = %_ArgumentsLength();
+  var index;
+  var result = "";
+  for (index = 0; index < length; index++) {
+    code = %_Arguments(index);
+    if (!%_IsSmi(code)) {
+      code = ToNumber(code);
+    }
+    if (code < 0 || code > 0x10FFFF || code !== TO_INTEGER(code)) {
+      throw MakeRangeError("invalid_code_point", [code]);
+    }
+    if (code <= 0xFFFF) {
+      result += %_StringCharFromCode(code);
+    } else {
+      code -= 0x10000;
+      result += %_StringCharFromCode((code >>> 10) & 0x3FF | 0xD800);
+      result += %_StringCharFromCode(code & 0x3FF | 0xDC00);
+    }
+  }
+  return result;
+}
+
+
+// -------------------------------------------------------------------
+// String methods related to templates
+
+// ES6 Draft 03-17-2015, 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 SetUpString() {
-  %CheckIsBootstrapping();
-
-  // Set the String function and constructor.
-  %SetCode($String, StringConstructor);
-  %FunctionSetPrototype($String, new $String());
-
-  // Set up the constructor property on the String prototype object.
-  %AddNamedProperty($String.prototype, "constructor", $String, DONT_ENUM);
-
-  // Set up the non-enumerable functions on the String object.
-  InstallFunctions($String, DONT_ENUM, $Array(
-    "fromCharCode", StringFromCharCode
-  ));
-
-  // Set up the non-enumerable functions on the String prototype object.
-  InstallFunctions($String.prototype, DONT_ENUM, $Array(
-    "valueOf", StringValueOf,
-    "toString", StringToString,
-    "charAt", StringCharAt,
-    "charCodeAt", StringCharCodeAt,
-    "concat", StringConcat,
-    "indexOf", StringIndexOfJS,
-    "lastIndexOf", StringLastIndexOfJS,
-    "localeCompare", StringLocaleCompareJS,
-    "match", StringMatchJS,
-    "normalize", StringNormalizeJS,
-    "replace", StringReplace,
-    "search", StringSearch,
-    "slice", StringSlice,
-    "split", StringSplitJS,
-    "substring", StringSubstring,
-    "substr", StringSubstr,
-    "toLowerCase", StringToLowerCaseJS,
-    "toLocaleLowerCase", StringToLocaleLowerCase,
-    "toUpperCase", StringToUpperCaseJS,
-    "toLocaleUpperCase", StringToLocaleUpperCase,
-    "trim", StringTrimJS,
-    "trimLeft", StringTrimLeft,
-    "trimRight", StringTrimRight,
-    "link", StringLink,
-    "anchor", StringAnchor,
-    "fontcolor", StringFontcolor,
-    "fontsize", StringFontsize,
-    "big", StringBig,
-    "blink", StringBlink,
-    "bold", StringBold,
-    "fixed", StringFixed,
-    "italics", StringItalics,
-    "small", StringSmall,
-    "strike", StringStrike,
-    "sub", StringSub,
-    "sup", StringSup
-  ));
-}
-
-SetUpString();
+// Set the String function and constructor.
+%SetCode(GlobalString, StringConstructor);
+%FunctionSetPrototype(GlobalString, new GlobalString());
+
+// Set up the constructor property on the String prototype object.
+%AddNamedProperty(
+    GlobalString.prototype, "constructor", GlobalString, DONT_ENUM);
+
+// Set up the non-enumerable functions on the String object.
+InstallFunctions(GlobalString, DONT_ENUM, GlobalArray(
+  "fromCharCode", StringFromCharCode,
+  "fromCodePoint", StringFromCodePoint,
+  "raw", StringRaw
+));
+
+// Set up the non-enumerable functions on the String prototype object.
+InstallFunctions(GlobalString.prototype, DONT_ENUM, GlobalArray(
+  "valueOf", StringValueOf,
+  "toString", StringToString,
+  "charAt", StringCharAtJS,
+  "charCodeAt", StringCharCodeAtJS,
+  "codePointAt", StringCodePointAt,
+  "concat", StringConcat,
+  "endsWith", StringEndsWith,
+  "includes", StringIncludes,
+  "indexOf", StringIndexOfJS,
+  "lastIndexOf", StringLastIndexOfJS,
+  "localeCompare", StringLocaleCompareJS,
+  "match", StringMatchJS,
+  "normalize", StringNormalizeJS,
+  "repeat", StringRepeat,
+  "replace", StringReplace,
+  "search", StringSearch,
+  "slice", StringSlice,
+  "split", StringSplitJS,
+  "substring", StringSubstring,
+  "substr", StringSubstr,
+  "startsWith", StringStartsWith,
+  "toLowerCase", StringToLowerCaseJS,
+  "toLocaleLowerCase", StringToLocaleLowerCase,
+  "toUpperCase", StringToUpperCaseJS,
+  "toLocaleUpperCase", StringToLocaleUpperCase,
+  "trim", StringTrimJS,
+  "trimLeft", StringTrimLeft,
+  "trimRight", StringTrimRight,
+
+  "link", StringLink,
+  "anchor", StringAnchor,
+  "fontcolor", StringFontcolor,
+  "fontsize", StringFontsize,
+  "big", StringBig,
+  "blink", StringBlink,
+  "bold", StringBold,
+  "fixed", StringFixed,
+  "italics", StringItalics,
+  "small", StringSmall,
+  "strike", StringStrike,
+  "sub", StringSub,
+  "sup", StringSup
+));
+
+$stringCharAt = StringCharAtJS;
+$stringIndexOf = StringIndexOfJS;
+$stringSubstring = StringSubstring;
+
+})();
diff --git a/deps/v8/src/strings-storage.cc b/deps/v8/src/strings-storage.cc
new file mode 100644 (file)
index 0000000..1d862d6
--- /dev/null
@@ -0,0 +1,123 @@
+// 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.
+
+#include "src/v8.h"
+
+#include "src/strings-storage.h"
+
+
+namespace v8 {
+namespace internal {
+
+
+bool StringsStorage::StringsMatch(void* key1, void* key2) {
+  return strcmp(reinterpret_cast<char*>(key1), reinterpret_cast<char*>(key2)) ==
+         0;
+}
+
+
+StringsStorage::StringsStorage(Heap* heap)
+    : hash_seed_(heap->HashSeed()), names_(StringsMatch) {}
+
+
+StringsStorage::~StringsStorage() {
+  for (HashMap::Entry* p = names_.Start(); p != NULL; p = names_.Next(p)) {
+    DeleteArray(reinterpret_cast<const char*>(p->value));
+  }
+}
+
+
+const char* StringsStorage::GetCopy(const char* src) {
+  int len = static_cast<int>(strlen(src));
+  HashMap::Entry* entry = GetEntry(src, len);
+  if (entry->value == NULL) {
+    Vector<char> dst = Vector<char>::New(len + 1);
+    StrNCpy(dst, src, len);
+    dst[len] = '\0';
+    entry->key = dst.start();
+    entry->value = entry->key;
+  }
+  return reinterpret_cast<const char*>(entry->value);
+}
+
+
+const char* StringsStorage::GetFormatted(const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  const char* result = GetVFormatted(format, args);
+  va_end(args);
+  return result;
+}
+
+
+const char* StringsStorage::AddOrDisposeString(char* str, int len) {
+  HashMap::Entry* entry = GetEntry(str, len);
+  if (entry->value == NULL) {
+    // New entry added.
+    entry->key = str;
+    entry->value = str;
+  } else {
+    DeleteArray(str);
+  }
+  return reinterpret_cast<const char*>(entry->value);
+}
+
+
+const char* StringsStorage::GetVFormatted(const char* format, va_list args) {
+  Vector<char> str = Vector<char>::New(1024);
+  int len = VSNPrintF(str, format, args);
+  if (len == -1) {
+    DeleteArray(str.start());
+    return GetCopy(format);
+  }
+  return AddOrDisposeString(str.start(), len);
+}
+
+
+const char* StringsStorage::GetName(Name* name) {
+  if (name->IsString()) {
+    String* str = String::cast(name);
+    int length = Min(kMaxNameSize, str->length());
+    int actual_length = 0;
+    SmartArrayPointer<char> data = str->ToCString(
+        DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL, 0, length, &actual_length);
+    return AddOrDisposeString(data.Detach(), actual_length);
+  } else if (name->IsSymbol()) {
+    return "<symbol>";
+  }
+  return "";
+}
+
+
+const char* StringsStorage::GetName(int index) {
+  return GetFormatted("%d", index);
+}
+
+
+const char* StringsStorage::GetFunctionName(Name* name) {
+  return GetName(name);
+}
+
+
+const char* StringsStorage::GetFunctionName(const char* name) {
+  return GetCopy(name);
+}
+
+
+size_t StringsStorage::GetUsedMemorySize() const {
+  size_t size = sizeof(*this);
+  size += sizeof(HashMap::Entry) * names_.capacity();
+  for (HashMap::Entry* p = names_.Start(); p != NULL; p = names_.Next(p)) {
+    size += strlen(reinterpret_cast<const char*>(p->value)) + 1;
+  }
+  return size;
+}
+
+
+HashMap::Entry* StringsStorage::GetEntry(const char* str, int len) {
+  uint32_t hash = StringHasher::HashSequentialString(str, len, hash_seed_);
+  return names_.Lookup(const_cast<char*>(str), hash, true);
+}
+}
+}  // namespace v8::internal
diff --git a/deps/v8/src/strings-storage.h b/deps/v8/src/strings-storage.h
new file mode 100644 (file)
index 0000000..8fd9da7
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+#ifndef V8_STRINGS_STORAGE_H_
+#define V8_STRINGS_STORAGE_H_
+
+#include "src/allocation.h"
+#include "src/hashmap.h"
+
+namespace v8 {
+namespace internal {
+
+struct OffsetRange;
+
+// Provides a storage of strings allocated in C++ heap, to hold them
+// forever, even if they disappear from JS heap or external storage.
+class StringsStorage {
+ public:
+  explicit StringsStorage(Heap* heap);
+  ~StringsStorage();
+
+  const char* GetCopy(const char* src);
+  const char* GetFormatted(const char* format, ...);
+  const char* GetVFormatted(const char* format, va_list args);
+  const char* GetName(Name* name);
+  const char* GetName(int index);
+  const char* GetFunctionName(Name* name);
+  const char* GetFunctionName(const char* name);
+  size_t GetUsedMemorySize() const;
+
+ private:
+  static const int kMaxNameSize = 1024;
+
+  static bool StringsMatch(void* key1, void* key2);
+  const char* AddOrDisposeString(char* str, int len);
+  HashMap::Entry* GetEntry(const char* str, int len);
+
+  uint32_t hash_seed_;
+  HashMap names_;
+
+  DISALLOW_COPY_AND_ASSIGN(StringsStorage);
+};
+}
+}  // namespace v8::internal
+
+#endif  // V8_STRINGS_STORAGE_H_
index d9cf792..7a80815 100644 (file)
@@ -2,13 +2,7 @@
 // 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;
-
-// And requires following symbols to be set in the bootstrapper during genesis:
+// Expects following symbols to be set in the bootstrapper during genesis:
 // - symbolHasInstance
 // - symbolIsConcatSpreadable
 // - symbolIsRegExp
 // - symbolToStringTag
 // - symbolUnscopables
 
-var $Symbol = global.Symbol;
+var $symbolToString;
+
+(function() {
+
+"use strict";
+
+%CheckIsBootstrapping();
+
+var GlobalArray = global.Array;
+var GlobalObject = global.Object;
+var GlobalSymbol = global.Symbol;
 
 // -------------------------------------------------------------------
 
@@ -77,46 +81,40 @@ function ObjectGetOwnPropertySymbols(obj) {
 
 //-------------------------------------------------------------------
 
-function SetUpSymbol() {
-  %CheckIsBootstrapping();
-
-  %SetCode($Symbol, SymbolConstructor);
-  %FunctionSetPrototype($Symbol, new $Object());
-
-  InstallConstants($Symbol, $Array(
-    // TODO(rossberg): expose when implemented.
-    // "hasInstance", symbolHasInstance,
-    // "isConcatSpreadable", symbolIsConcatSpreadable,
-    // "isRegExp", symbolIsRegExp,
-    "iterator", symbolIterator,
-    // TODO(dslomov, caitp): Currently defined in harmony-tostring.js ---
-    // Move here when shipping
-    // "toStringTag", symbolToStringTag,
-    "unscopables", symbolUnscopables
-  ));
-  InstallFunctions($Symbol, DONT_ENUM, $Array(
-    "for", SymbolFor,
-    "keyFor", SymbolKeyFor
-  ));
-
-  %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
-  ));
-}
-
-SetUpSymbol();
-
-
-function ExtendObject() {
-  %CheckIsBootstrapping();
-
-  InstallFunctions($Object, DONT_ENUM, $Array(
-    "getOwnPropertySymbols", ObjectGetOwnPropertySymbols
-  ));
-}
-
-ExtendObject();
+%SetCode(GlobalSymbol, SymbolConstructor);
+%FunctionSetPrototype(GlobalSymbol, new GlobalObject());
+
+InstallConstants(GlobalSymbol, GlobalArray(
+  // TODO(rossberg): expose when implemented.
+  // "hasInstance", symbolHasInstance,
+  // "isConcatSpreadable", symbolIsConcatSpreadable,
+  // "isRegExp", symbolIsRegExp,
+  "iterator", symbolIterator,
+  // TODO(dslomov, caitp): Currently defined in harmony-tostring.js ---
+  // Move here when shipping
+  // "toStringTag", symbolToStringTag,
+  "unscopables", symbolUnscopables
+));
+
+InstallFunctions(GlobalSymbol, DONT_ENUM, GlobalArray(
+  "for", SymbolFor,
+  "keyFor", SymbolKeyFor
+));
+
+%AddNamedProperty(
+    GlobalSymbol.prototype, "constructor", GlobalSymbol, DONT_ENUM);
+%AddNamedProperty(
+    GlobalSymbol.prototype, symbolToStringTag, "Symbol", DONT_ENUM | READ_ONLY);
+
+InstallFunctions(GlobalSymbol.prototype, DONT_ENUM, GlobalArray(
+  "toString", SymbolToString,
+  "valueOf", SymbolValueOf
+));
+
+InstallFunctions(GlobalObject, DONT_ENUM, GlobalArray(
+  "getOwnPropertySymbols", ObjectGetOwnPropertySymbols
+));
+
+$symbolToString = SymbolToString;
+
+})();
similarity index 62%
rename from deps/v8/src/harmony-templates.js
rename to deps/v8/src/templates.js
index 254f434..20f8af5 100644 (file)
@@ -58,37 +58,3 @@ function GetTemplateCallSite(siteObj, rawStrings, hash) {
 
   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();
index 8804469..e037392 100644 (file)
 // rempio2result is used as a container for return values of %RemPiO2. It is
 // initialized to a two-element Float64Array during genesis.
 
-"use strict";
-
 var kMath;
 var rempio2result;
 
+(function() {
+  
+"use strict";
+
+%CheckIsBootstrapping();
+
+var GlobalMath = global.Math;
+var GlobalArray = global.Array;
+
+//-------------------------------------------------------------------
+
 const INVPIO2 = kMath[0];
 const PIO2_1  = kMath[1];
 const PIO2_1T = kMath[2];
@@ -79,7 +88,7 @@ macro REMPIO2(X)
     }
   } else if (ix <= 0x413921fb) {
     // |X| ~<= 2^19*(pi/2), medium size
-    var t = MathAbs(X);
+    var t = $abs(X);
     n = (t * INVPIO2 + 0.5) | 0;
     var r = t - n * PIO2_1;
     var w = n * PIO2_1T;
@@ -141,16 +150,18 @@ endmacro
 //     then                   3    2
 //          sin(x) = X + (S1*X + (X *(r-Y/2)+Y))
 //
-macro KSIN(x)
-kMath[7+x]
-endmacro
+const S1 = -1.66666666666666324348e-01;
+const S2 = 8.33333333332248946124e-03;
+const S3 = -1.98412698298579493134e-04;
+const S4 = 2.75573137070700676789e-06;
+const S5 = -2.50507602534068634195e-08;
+const S6 = 1.58969099521155010221e-10;
 
 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;
+  var r = S2 + z * (S3 + z * (S4 + z * (S5 + z * S6)));
+  return (X - ((z * (0.5 * Y - v * r) - Y) - v * S1)) SIGN;
 endmacro
 
 // __kernel_cos(X, Y)
@@ -185,15 +196,17 @@ endmacro
 //     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
+const C1 = 4.16666666666666019037e-02;
+const C2 = -1.38888888888741095749e-03;
+const C3 = 2.48015872894767294178e-05;
+const C4 = -2.75573143513906633035e-07;
+const C5 = 2.08757232129817482790e-09;
+const C6 = -1.13596475577881948265e-11;
 
 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))))));
+  var r = z * (C1 + z * (C2 + z * (C3 + z * (C4 + z * (C5 + z * C6)))));
   if (ix < 0x3fd33333) {  // |x| ~< 0.3
     return (1 - (0.5 * z - (z * r - X * Y))) SIGN;
   } else {
@@ -257,7 +270,7 @@ function KernelTan(x, y, returnTan) {
   if (ix < 0x3e300000) {  // |x| < 2^-28
     if (((ix | %_DoubleLo(x)) | (returnTan + 1)) == 0) {
       // x == 0 && returnTan = -1
-      return 1 / MathAbs(x);
+      return 1 / $abs(x);
     } else {
       if (returnTan == 1) {
         return x;
@@ -336,22 +349,22 @@ function MathCosSlow(x) {
 
 // ECMA 262 - 15.8.2.16
 function MathSin(x) {
-  x = x * 1;  // Convert to number.
+  x = +x;  // Convert to number.
   if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
     // |x| < pi/4, approximately.  No reduction needed.
     RETURN_KERNELSIN(x, 0, /* empty */);
   }
-  return MathSinSlow(x);
+  return +MathSinSlow(x);
 }
 
 // ECMA 262 - 15.8.2.7
 function MathCos(x) {
-  x = x * 1;  // Convert to number.
+  x = +x;  // Convert to number.
   if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
     // |x| < pi/4, approximately.  No reduction needed.
     RETURN_KERNELCOS(x, 0, /* empty */);
   }
-  return MathCosSlow(x);
+  return +MathCosSlow(x);
 }
 
 // ECMA 262 - 15.8.2.18
@@ -745,7 +758,7 @@ 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);
+  var ax = $abs(x);
   if (ax < 22) {
     // For |x| < 2^-28, sinh(x) = x
     if (ax < TWO_M28) return x;
@@ -754,11 +767,11 @@ function MathSinh(x) {
     return h * (t + t / (t + 1));
   }
   // |x| in [22, log(maxdouble)], return 0.5 * exp(|x|)
-  if (ax < LOG_MAXD) return h * MathExp(ax);
+  if (ax < LOG_MAXD) return h * $exp(ax);
   // |x| in [log(maxdouble), overflowthreshold]
   // overflowthreshold = 710.4758600739426
   if (ax <= KSINH_OVERFLOW) {
-    var w = MathExp(0.5 * ax);
+    var w = $exp(0.5 * ax);
     var t = h * w;
     return t * w;
   }
@@ -796,7 +809,7 @@ function MathCosh(x) {
   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 t = MathExpm1($abs(x));
     var w = 1 + t;
     // For |x| < 2^-55, cosh(x) = 1
     if (ix < 0x3c800000) return w;
@@ -804,14 +817,14 @@ function MathCosh(x) {
   }
   // |x| in [0.5*log2, 22], return (exp(|x|)+1/exp(|x|)/2
   if (ix < 0x40360000) {
-    var t = MathExp(MathAbs(x));
+    var t = $exp($abs(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));
+  if (ix < 0x40862e42) return 0.5 * $exp($abs(x));
   // |x| in [log(maxdouble), overflowthreshold]
-  if (MathAbs(x) <= KCOSH_OVERFLOW) {
-    var w = MathExp(0.5 * MathAbs(x));
+  if ($abs(x) <= KCOSH_OVERFLOW) {
+    var w = $exp(0.5 * $abs(x));
     var t = 0.5 * w;
     return t * w;
   }
@@ -879,7 +892,7 @@ function MathLog10(x) {
   y = k + i;
   x = %_ConstructDouble(hx, lx);
 
-  z = y * LOG10_2LO + IVLN10 * MathLog(x);
+  z = y * LOG10_2LO + IVLN10 * %_MathLogRT(x);
   return z + y * LOG10_2HI;
 }
 
@@ -914,7 +927,7 @@ const TWO53 = 9007199254740992;
 
 function MathLog2(x) {
   x = x * 1;  // Convert to number.
-  var ax = MathAbs(x);
+  var ax = $abs(x);
   var hx = %_DoubleHi(x);
   var lx = %_DoubleLo(x);
   var ix = hx & 0x7fffffff;
@@ -997,3 +1010,22 @@ function MathLog2(x) {
   // t1 + t2 = log2(ax), sum up because we do not care about extra precision.
   return t1 + t2;
 }
+
+//-------------------------------------------------------------------
+
+InstallFunctions(GlobalMath, DONT_ENUM, GlobalArray(
+  "cos", MathCos,
+  "sin", MathSin,
+  "tan", MathTan,
+  "sinh", MathSinh,
+  "cosh", MathCosh,
+  "log10", MathLog10,
+  "log2", MathLog2,
+  "log1p", MathLog1p,
+  "expm1", MathExpm1
+));
+
+%SetInlineBuiltinFlag(MathSin);
+%SetInlineBuiltinFlag(MathCos);
+
+})();
index 0f46b11..cc7e9f8 100644 (file)
@@ -40,7 +40,7 @@ namespace internal {
   T(COLON, ":", 0)                                                   \
   T(SEMICOLON, ";", 0)                                               \
   T(PERIOD, ".", 0)                                                  \
-  T(ELLIPSIS, "...", 0)                                               \
+  T(ELLIPSIS, "...", 0)                                              \
   T(CONDITIONAL, "?", 3)                                             \
   T(INC, "++", 0)                                                    \
   T(DEC, "--", 0)                                                    \
@@ -142,6 +142,7 @@ namespace internal {
   K(TRUE_LITERAL, "true", 0)                                         \
   K(FALSE_LITERAL, "false", 0)                                       \
   T(NUMBER, NULL, 0)                                                 \
+  T(SMI, NULL, 0)                                                    \
   T(STRING, NULL, 0)                                                 \
                                                                      \
   /* Identifiers (not keywords or future reserved words). */         \
index fd8eb8b..f31eff9 100644 (file)
@@ -11,55 +11,19 @@ namespace v8 {
 namespace internal {
 
 
-#define FIELD_ADDR(p, offset) \
-  (reinterpret_cast<byte*>(p) + offset - kHeapObjectTag)
-
-#define WRITE_FIELD(p, offset, value) \
-  (*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)) = value)
-
-#define CONDITIONAL_WRITE_BARRIER(heap, object, offset, value, mode)    \
-  if (mode == UPDATE_WRITE_BARRIER) {                                   \
-    heap->incremental_marking()->RecordWrite(                           \
-      object, HeapObject::RawField(object, offset), value);             \
-    if (heap->InNewSpace(value)) {                                      \
-      heap->RecordWrite(object->address(), offset);                     \
-    }                                                                   \
-  }
-
-
 TransitionArray* TransitionArray::cast(Object* object) {
   DCHECK(object->IsTransitionArray());
   return reinterpret_cast<TransitionArray*>(object);
 }
 
 
-bool TransitionArray::HasElementsTransition() {
-  return SearchSpecial(GetHeap()->elements_transition_symbol()) != kNotFound;
-}
-
-
-Object* TransitionArray::back_pointer_storage() {
-  return get(kBackPointerStorageIndex);
-}
-
-
-void TransitionArray::set_back_pointer_storage(Object* back_pointer,
-                                               WriteBarrierMode mode) {
-  Heap* heap = GetHeap();
-  WRITE_FIELD(this, kBackPointerStorageOffset, back_pointer);
-  CONDITIONAL_WRITE_BARRIER(
-      heap, this, kBackPointerStorageOffset, back_pointer, mode);
-}
-
-
 bool TransitionArray::HasPrototypeTransitions() {
-  return IsFullTransitionArray() &&
-      get(kPrototypeTransitionsIndex) != Smi::FromInt(0);
+  return get(kPrototypeTransitionsIndex) != Smi::FromInt(0);
 }
 
 
 FixedArray* TransitionArray::GetPrototypeTransitions() {
-  DCHECK(IsFullTransitionArray());
+  DCHECK(HasPrototypeTransitions());  // Callers must check first.
   Object* prototype_transitions = get(kPrototypeTransitionsIndex);
   return FixedArray::cast(prototype_transitions);
 }
@@ -67,88 +31,68 @@ FixedArray* TransitionArray::GetPrototypeTransitions() {
 
 void TransitionArray::SetPrototypeTransitions(FixedArray* transitions,
                                               WriteBarrierMode mode) {
-  DCHECK(IsFullTransitionArray());
   DCHECK(transitions->IsFixedArray());
-  Heap* heap = GetHeap();
-  WRITE_FIELD(this, kPrototypeTransitionsOffset, transitions);
-  CONDITIONAL_WRITE_BARRIER(
-      heap, this, kPrototypeTransitionsOffset, transitions, mode);
+  set(kPrototypeTransitionsIndex, transitions, mode);
 }
 
 
 Object** TransitionArray::GetPrototypeTransitionsSlot() {
-  return HeapObject::RawField(reinterpret_cast<HeapObject*>(this),
-                              kPrototypeTransitionsOffset);
+  return RawFieldOfElementAt(kPrototypeTransitionsIndex);
 }
 
 
 Object** TransitionArray::GetKeySlot(int transition_number) {
-  DCHECK(!IsSimpleTransition());
   DCHECK(transition_number < number_of_transitions());
   return RawFieldOfElementAt(ToKeyIndex(transition_number));
 }
 
 
 Name* TransitionArray::GetKey(int transition_number) {
-  if (IsSimpleTransition()) {
-    Map* target = GetTarget(kSimpleTransitionIndex);
-    int descriptor = target->LastAdded();
-    Name* key = target->instance_descriptors()->GetKey(descriptor);
-    return key;
-  }
   DCHECK(transition_number < number_of_transitions());
   return Name::cast(get(ToKeyIndex(transition_number)));
 }
 
 
+Name* TransitionArray::GetKey(Object* raw_transitions, int transition_number) {
+  if (IsSimpleTransition(raw_transitions)) {
+    DCHECK(transition_number == 0);
+    return GetSimpleTransitionKey(GetSimpleTransition(raw_transitions));
+  }
+  DCHECK(IsFullTransitionArray(raw_transitions));
+  return TransitionArray::cast(raw_transitions)->GetKey(transition_number);
+}
+
+
 void TransitionArray::SetKey(int transition_number, Name* key) {
-  DCHECK(!IsSimpleTransition());
   DCHECK(transition_number < number_of_transitions());
   set(ToKeyIndex(transition_number), key);
 }
 
 
 Map* TransitionArray::GetTarget(int transition_number) {
-  if (IsSimpleTransition()) {
-    DCHECK(transition_number == kSimpleTransitionIndex);
-    return Map::cast(get(kSimpleTransitionTarget));
-  }
   DCHECK(transition_number < number_of_transitions());
   return Map::cast(get(ToTargetIndex(transition_number)));
 }
 
 
-void TransitionArray::SetTarget(int transition_number, Map* value) {
-  if (IsSimpleTransition()) {
-    DCHECK(transition_number == kSimpleTransitionIndex);
-    return set(kSimpleTransitionTarget, value);
+Map* TransitionArray::GetTarget(Object* raw_transitions,
+                                int transition_number) {
+  if (IsSimpleTransition(raw_transitions)) {
+    DCHECK(transition_number == 0);
+    return GetSimpleTransition(raw_transitions);
   }
-  DCHECK(transition_number < number_of_transitions());
-  set(ToTargetIndex(transition_number), value);
-}
-
-
-PropertyDetails TransitionArray::GetTargetDetails(int transition_number) {
-  Map* map = GetTarget(transition_number);
-  return map->GetLastDescriptorDetails();
+  DCHECK(IsFullTransitionArray(raw_transitions));
+  return TransitionArray::cast(raw_transitions)->GetTarget(transition_number);
 }
 
 
-Object* TransitionArray::GetTargetValue(int transition_number) {
-  Map* map = GetTarget(transition_number);
-  return map->instance_descriptors()->GetValue(map->LastAdded());
+void TransitionArray::SetTarget(int transition_number, Map* value) {
+  DCHECK(transition_number < number_of_transitions());
+  set(ToTargetIndex(transition_number), value);
 }
 
 
 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, 0, out_insertion_index);
 }
 
@@ -225,19 +169,10 @@ void TransitionArray::NoIncrementalWriteBarrierSet(int transition_number,
 
 
 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));
-  }
+  DCHECK(number_of_transitions <= Capacity(this));
+  set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions));
 }
 
-
-#undef FIELD_ADDR
-#undef WRITE_FIELD
-#undef CONDITIONAL_WRITE_BARRIER
-
-
 } }  // namespace v8::internal
 
 #endif  // V8_TRANSITIONS_INL_H_
index 43fc90b..2e65e38 100644 (file)
@@ -12,141 +12,110 @@ namespace v8 {
 namespace internal {
 
 
-Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate,
-                                                  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);
-}
-
-
-Handle<TransitionArray> TransitionArray::AllocateSimple(Isolate* isolate,
-                                                        Handle<Map> target) {
-  Handle<FixedArray> array =
-      isolate->factory()->NewFixedArray(kSimpleTransitionSize);
-  array->set(kSimpleTransitionTarget, *target);
-  return Handle<TransitionArray>::cast(array);
-}
-
-
-void TransitionArray::NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin,
-                                                        int origin_transition,
-                                                        int target_transition) {
-  NoIncrementalWriteBarrierSet(target_transition,
-                               origin->GetKey(origin_transition),
-                               origin->GetTarget(origin_transition));
-}
-
-
-Handle<TransitionArray> TransitionArray::NewWith(Handle<Map> map,
-                                                 Handle<Name> name,
-                                                 Handle<Map> target,
-                                                 SimpleTransitionFlag flag) {
-  Handle<TransitionArray> result;
-  Isolate* isolate = name->GetIsolate();
-
-  if (flag == SIMPLE_PROPERTY_TRANSITION) {
-    result = AllocateSimple(isolate, target);
-  } else {
-    result = Allocate(isolate, 1);
-    result->NoIncrementalWriteBarrierSet(0, *name, *target);
-  }
-  result->set_back_pointer_storage(map->GetBackPointer());
-  return result;
-}
-
-
-Handle<TransitionArray> TransitionArray::ExtendToFullTransitionArray(
-    Handle<Map> containing_map) {
-  DCHECK(!containing_map->transitions()->IsFullTransitionArray());
-  int nof = containing_map->transitions()->number_of_transitions();
-
-  // A transition array may shrink during GC.
-  Handle<TransitionArray> result = Allocate(containing_map->GetIsolate(), nof);
-  DisallowHeapAllocation no_gc;
-  int new_nof = containing_map->transitions()->number_of_transitions();
-  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);
+// static
+void TransitionArray::Insert(Handle<Map> map, Handle<Name> name,
+                             Handle<Map> target, SimpleTransitionFlag flag) {
+  Isolate* isolate = map->GetIsolate();
+  target->SetBackPointer(*map);
+
+  // If the map doesn't have any transitions at all yet, install the new one.
+  if (CanStoreSimpleTransition(map->raw_transitions())) {
+    if (flag == SIMPLE_PROPERTY_TRANSITION) {
+      Handle<WeakCell> cell = Map::WeakCellForMap(target);
+      ReplaceTransitions(map, *cell);
+      return;
+    }
+    // If the flag requires a full TransitionArray, allocate one.
+    Handle<TransitionArray> result = Allocate(isolate, 0, 1);
+    ReplaceTransitions(map, *result);
   }
 
-  result->set_back_pointer_storage(
-      containing_map->transitions()->back_pointer_storage());
-  return result;
-}
-
-
-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);
+  bool is_special_transition = flag == SPECIAL_TRANSITION;
+  // If the map has a simple transition, check if it should be overwritten.
+  if (IsSimpleTransition(map->raw_transitions())) {
+    Map* old_target = GetSimpleTransition(map->raw_transitions());
+    Name* key = GetSimpleTransitionKey(old_target);
+    PropertyDetails old_details = GetSimpleTargetDetails(old_target);
+    PropertyDetails new_details = is_special_transition
+                                      ? PropertyDetails::Empty()
+                                      : GetTargetDetails(*name, *target);
+    if (flag == SIMPLE_PROPERTY_TRANSITION && key->Equals(*name) &&
+        old_details.kind() == new_details.kind() &&
+        old_details.attributes() == new_details.attributes()) {
+      Handle<WeakCell> cell = Map::WeakCellForMap(target);
+      ReplaceTransitions(map, *cell);
+      return;
+    }
+    // Otherwise allocate a full TransitionArray with slack for a new entry.
+    Handle<TransitionArray> result = Allocate(isolate, 1, 1);
+    // Re-read existing data; the allocation might have caused it to be cleared.
+    if (IsSimpleTransition(map->raw_transitions())) {
+      old_target = GetSimpleTransition(map->raw_transitions());
+      result->NoIncrementalWriteBarrierSet(
+          0, GetSimpleTransitionKey(old_target), old_target);
+    } else {
+      result->SetNumberOfTransitions(0);
+    }
+    ReplaceTransitions(map, *result);
   }
 
-  int number_of_transitions = map->transitions()->number_of_transitions();
-  int new_nof = number_of_transitions;
+  // At this point, we know that the map has a full TransitionArray.
+  DCHECK(IsFullTransitionArray(map->raw_transitions()));
 
-  bool is_special_transition = flag == SPECIAL_TRANSITION;
+  int number_of_transitions = 0;
+  int new_nof = 0;
+  int insertion_index = kNotFound;
   DCHECK_EQ(is_special_transition, IsSpecialTransition(*name));
   PropertyDetails details = is_special_transition
-                                ? PropertyDetails(NONE, DATA, 0)
+                                ? PropertyDetails::Empty()
                                 : GetTargetDetails(*name, *target);
 
-  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();
+    TransitionArray* array = TransitionArray::cast(map->raw_transitions());
+    number_of_transitions = array->number_of_transitions();
+    new_nof = number_of_transitions;
 
+    int index =
+        is_special_transition
+            ? array->SearchSpecial(Symbol::cast(*name), &insertion_index)
+            : array->Search(details.kind(), *name, details.attributes(),
+                            &insertion_index);
+    // If an existing entry was found, overwrite it and return.
     if (index != kNotFound) {
       array->SetTarget(index, *target);
-      return handle(array);
+      return;
     }
 
-    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));
+    ++new_nof;
+    CHECK(new_nof <= kMaxNumberOfTransitions);
+    DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);
+
+    // If there is enough capacity, insert new entry into the existing array.
+    if (new_nof <= Capacity(array)) {
+      array->SetNumberOfTransitions(new_nof);
+      for (index = number_of_transitions; index > insertion_index; --index) {
+        array->SetKey(index, array->GetKey(index - 1));
+        array->SetTarget(index, array->GetTarget(index - 1));
+      }
+      array->SetKey(index, *name);
+      array->SetTarget(index, *target);
+      SLOW_DCHECK(array->IsSortedNoDuplicates());
+      return;
     }
-    array->SetKey(index, *name);
-    array->SetTarget(index, *target);
-    SLOW_DCHECK(array->IsSortedNoDuplicates());
-    return handle(array);
   }
 
+  // We're gonna need a bigger TransitionArray.
   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
+  // The map's transition array may have shrunk during the allocation above as
   // it was weakly traversed, though it is guaranteed not to disappear. Trim the
   // result copy if needed, and recompute variables.
-  DCHECK(map->HasTransitionArray());
+  DCHECK(IsFullTransitionArray(map->raw_transitions()));
   DisallowHeapAllocation no_gc;
-  TransitionArray* array = map->transitions();
+  TransitionArray* array = TransitionArray::cast(map->raw_transitions());
   if (array->number_of_transitions() != number_of_transitions) {
     DCHECK(array->number_of_transitions() < number_of_transitions);
 
@@ -154,11 +123,11 @@ Handle<TransitionArray> TransitionArray::Insert(Handle<Map> map,
     new_nof = number_of_transitions;
 
     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);
+    int index =
+        is_special_transition
+            ? array->SearchSpecial(Symbol::cast(*name), &insertion_index)
+            : array->Search(details.kind(), *name, details.attributes(),
+                            &insertion_index);
     if (index == kNotFound) {
       ++new_nof;
     } else {
@@ -183,12 +152,332 @@ Handle<TransitionArray> TransitionArray::Insert(Handle<Map> map,
     result->NoIncrementalWriteBarrierCopyFrom(array, i, i + 1);
   }
 
-  result->set_back_pointer_storage(array->back_pointer_storage());
   SLOW_DCHECK(result->IsSortedNoDuplicates());
-  return result;
+  ReplaceTransitions(map, *result);
+}
+
+
+// static
+Map* TransitionArray::SearchTransition(Map* map, PropertyKind kind, Name* name,
+                                       PropertyAttributes attributes) {
+  Object* raw_transitions = map->raw_transitions();
+  if (IsSimpleTransition(raw_transitions)) {
+    Map* target = GetSimpleTransition(raw_transitions);
+    Name* key = GetSimpleTransitionKey(target);
+    if (!key->Equals(name)) return NULL;
+    PropertyDetails details = GetSimpleTargetDetails(target);
+    if (details.attributes() != attributes) return NULL;
+    if (details.kind() != kind) return NULL;
+    return target;
+  }
+  if (IsFullTransitionArray(raw_transitions)) {
+    TransitionArray* transitions = TransitionArray::cast(raw_transitions);
+    int transition = transitions->Search(kind, name, attributes);
+    if (transition == kNotFound) return NULL;
+    return transitions->GetTarget(transition);
+  }
+  return NULL;
 }
 
 
+// static
+Map* TransitionArray::SearchSpecial(Map* map, Symbol* name) {
+  Object* raw_transitions = map->raw_transitions();
+  if (IsFullTransitionArray(raw_transitions)) {
+    TransitionArray* transitions = TransitionArray::cast(raw_transitions);
+    int transition = transitions->SearchSpecial(name);
+    if (transition == kNotFound) return NULL;
+    return transitions->GetTarget(transition);
+  }
+  return NULL;
+}
+
+
+// static
+Handle<Map> TransitionArray::FindTransitionToField(Handle<Map> map,
+                                                   Handle<Name> name) {
+  DisallowHeapAllocation no_gc;
+  Map* target = SearchTransition(*map, kData, *name, NONE);
+  if (target == NULL) return Handle<Map>::null();
+  PropertyDetails details = target->GetLastDescriptorDetails();
+  DCHECK_EQ(NONE, details.attributes());
+  if (details.type() != DATA) return Handle<Map>::null();
+  return Handle<Map>(target);
+}
+
+
+// static
+Handle<String> TransitionArray::ExpectedTransitionKey(Handle<Map> map) {
+  DisallowHeapAllocation no_gc;
+  Object* raw_transition = map->raw_transitions();
+  if (!IsSimpleTransition(raw_transition)) return Handle<String>::null();
+  Map* target = GetSimpleTransition(raw_transition);
+  PropertyDetails details = GetSimpleTargetDetails(target);
+  if (details.type() != DATA) return Handle<String>::null();
+  if (details.attributes() != NONE) return Handle<String>::null();
+  Name* name = GetSimpleTransitionKey(target);
+  if (!name->IsString()) return Handle<String>::null();
+  return Handle<String>(String::cast(name));
+}
+
+
+// static
+bool TransitionArray::CanHaveMoreTransitions(Handle<Map> map) {
+  Object* raw_transitions = map->raw_transitions();
+  if (IsFullTransitionArray(raw_transitions)) {
+    TransitionArray* transitions = TransitionArray::cast(raw_transitions);
+    return transitions->number_of_transitions() < kMaxNumberOfTransitions;
+  }
+  return true;
+}
+
+
+// static
+Handle<Map> TransitionArray::PutPrototypeTransition(Handle<Map> map,
+                                                    Handle<Object> prototype,
+                                                    Handle<Map> target_map) {
+  DCHECK(HeapObject::cast(*prototype)->map()->IsMap());
+  // Don't cache prototype transition if this map is either shared, or a map of
+  // a prototype.
+  if (map->is_prototype_map()) return map;
+  if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return map;
+
+  const int header = kProtoTransitionHeaderSize;
+
+  Handle<FixedArray> cache(GetPrototypeTransitions(*map));
+  int capacity = cache->length() - header;
+  int transitions = NumberOfPrototypeTransitions(*cache) + 1;
+
+  if (transitions > capacity) {
+    // Grow array by factor 2 up to MaxCachedPrototypeTransitions.
+    int new_capacity = Min(kMaxCachedPrototypeTransitions, transitions * 2);
+    if (new_capacity == capacity) return map;
+
+    cache = FixedArray::CopySize(cache, header + new_capacity);
+    if (capacity < 0) {
+      // There was no prototype transitions array before, so the size
+      // couldn't be copied. Initialize it explicitly.
+      SetNumberOfPrototypeTransitions(*cache, 0);
+    }
+
+    SetPrototypeTransitions(map, cache);
+  }
+
+  // Reload number of transitions as GC might shrink them.
+  int last = NumberOfPrototypeTransitions(*cache);
+  int entry = header + last;
+
+  cache->set(entry, *target_map);
+  SetNumberOfPrototypeTransitions(*cache, last + 1);
+
+  return map;
+}
+
+
+// static
+Handle<Map> TransitionArray::GetPrototypeTransition(Handle<Map> map,
+                                                    Handle<Object> prototype) {
+  DisallowHeapAllocation no_gc;
+  FixedArray* cache = GetPrototypeTransitions(*map);
+  int number_of_transitions = NumberOfPrototypeTransitions(cache);
+  for (int i = 0; i < number_of_transitions; i++) {
+    Map* target = Map::cast(cache->get(kProtoTransitionHeaderSize + i));
+    if (target->prototype() == *prototype) return handle(target);
+  }
+  return Handle<Map>();
+}
+
+
+// static
+FixedArray* TransitionArray::GetPrototypeTransitions(Map* map) {
+  Object* raw_transitions = map->raw_transitions();
+  Heap* heap = map->GetHeap();
+  if (!IsFullTransitionArray(raw_transitions)) {
+    return heap->empty_fixed_array();
+  }
+  TransitionArray* transitions = TransitionArray::cast(raw_transitions);
+  if (!transitions->HasPrototypeTransitions()) {
+    return heap->empty_fixed_array();
+  }
+  return transitions->GetPrototypeTransitions();
+}
+
+
+// static
+void TransitionArray::SetNumberOfPrototypeTransitions(
+    FixedArray* proto_transitions, int value) {
+  DCHECK(proto_transitions->length() != 0);
+  proto_transitions->set(kProtoTransitionNumberOfEntriesOffset,
+                         Smi::FromInt(value));
+}
+
+
+// static
+int TransitionArray::NumberOfTransitions(Object* raw_transitions) {
+  if (CanStoreSimpleTransition(raw_transitions)) return 0;
+  if (IsSimpleTransition(raw_transitions)) return 1;
+  DCHECK(IsFullTransitionArray(raw_transitions));
+  return TransitionArray::cast(raw_transitions)->number_of_transitions();
+}
+
+
+// static
+int TransitionArray::Capacity(Object* raw_transitions) {
+  if (!IsFullTransitionArray(raw_transitions)) return 1;
+  TransitionArray* t = TransitionArray::cast(raw_transitions);
+  if (t->length() <= kFirstIndex) return 0;
+  return (t->length() - kFirstIndex) / kTransitionSize;
+}
+
+
+// Private static helper functions.
+
+Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate,
+                                                  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);
+}
+
+
+void TransitionArray::NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin,
+                                                        int origin_transition,
+                                                        int target_transition) {
+  NoIncrementalWriteBarrierSet(target_transition,
+                               origin->GetKey(origin_transition),
+                               origin->GetTarget(origin_transition));
+}
+
+
+static void ZapTransitionArray(TransitionArray* transitions) {
+  MemsetPointer(transitions->data_start(),
+                transitions->GetHeap()->the_hole_value(),
+                transitions->length());
+}
+
+
+void TransitionArray::ReplaceTransitions(Handle<Map> map,
+                                         Object* new_transitions) {
+  Object* raw_transitions = map->raw_transitions();
+  if (IsFullTransitionArray(raw_transitions)) {
+    TransitionArray* old_transitions = TransitionArray::cast(raw_transitions);
+#ifdef DEBUG
+    CheckNewTransitionsAreConsistent(map, old_transitions, new_transitions);
+    DCHECK(old_transitions != new_transitions);
+#endif
+    // Transition arrays are not shared. When one is replaced, it should not
+    // keep referenced objects alive, so we zap it.
+    // When there is another reference to the array somewhere (e.g. a handle),
+    // not zapping turns from a waste of memory into a source of crashes.
+    ZapTransitionArray(old_transitions);
+  }
+  map->set_raw_transitions(new_transitions);
+}
+
+
+static void ZapPrototypeTransitions(Object* raw_transitions) {
+  DCHECK(TransitionArray::IsFullTransitionArray(raw_transitions));
+  TransitionArray* transitions = TransitionArray::cast(raw_transitions);
+  if (!transitions->HasPrototypeTransitions()) return;
+  FixedArray* proto_transitions = transitions->GetPrototypeTransitions();
+  MemsetPointer(proto_transitions->data_start(),
+                proto_transitions->GetHeap()->the_hole_value(),
+                proto_transitions->length());
+}
+
+
+void TransitionArray::SetPrototypeTransitions(
+    Handle<Map> map, Handle<FixedArray> proto_transitions) {
+  EnsureHasFullTransitionArray(map);
+  if (Heap::ShouldZapGarbage()) {
+    Object* raw_transitions = map->raw_transitions();
+    DCHECK(raw_transitions != *proto_transitions);
+    ZapPrototypeTransitions(raw_transitions);
+  }
+  TransitionArray* transitions = TransitionArray::cast(map->raw_transitions());
+  transitions->SetPrototypeTransitions(*proto_transitions);
+}
+
+
+void TransitionArray::EnsureHasFullTransitionArray(Handle<Map> map) {
+  Object* raw_transitions = map->raw_transitions();
+  if (IsFullTransitionArray(raw_transitions)) return;
+  int nof = IsSimpleTransition(raw_transitions) ? 1 : 0;
+  Handle<TransitionArray> result = Allocate(map->GetIsolate(), nof);
+  DisallowHeapAllocation no_gc;
+  // Reload pointer after the allocation that just happened.
+  raw_transitions = map->raw_transitions();
+  int new_nof = IsSimpleTransition(raw_transitions) ? 1 : 0;
+  if (new_nof != nof) {
+    DCHECK(new_nof == 0);
+    result->Shrink(ToKeyIndex(0));
+    result->SetNumberOfTransitions(0);
+  } else if (nof == 1) {
+    Map* target = GetSimpleTransition(raw_transitions);
+    Name* key = GetSimpleTransitionKey(target);
+    result->NoIncrementalWriteBarrierSet(0, key, target);
+  }
+  ReplaceTransitions(map, *result);
+}
+
+
+void TransitionArray::TraverseTransitionTreeInternal(Map* map,
+                                                     TraverseCallback callback,
+                                                     void* data) {
+  Object* raw_transitions = map->raw_transitions();
+  if (IsFullTransitionArray(raw_transitions)) {
+    TransitionArray* transitions = TransitionArray::cast(raw_transitions);
+    if (transitions->HasPrototypeTransitions()) {
+      FixedArray* proto_trans = transitions->GetPrototypeTransitions();
+      for (int i = 0; i < NumberOfPrototypeTransitions(proto_trans); ++i) {
+        int index = TransitionArray::kProtoTransitionHeaderSize + i;
+        TraverseTransitionTreeInternal(Map::cast(proto_trans->get(index)),
+                                       callback, data);
+      }
+    }
+    for (int i = 0; i < transitions->number_of_transitions(); ++i) {
+      TraverseTransitionTreeInternal(transitions->GetTarget(i), callback, data);
+    }
+  } else if (IsSimpleTransition(raw_transitions)) {
+    TraverseTransitionTreeInternal(GetSimpleTransition(raw_transitions),
+                                   callback, data);
+  }
+  callback(map, data);
+}
+
+
+#ifdef DEBUG
+void TransitionArray::CheckNewTransitionsAreConsistent(
+    Handle<Map> map, TransitionArray* old_transitions, Object* transitions) {
+  // This function only handles full transition arrays.
+  DCHECK(IsFullTransitionArray(transitions));
+  TransitionArray* new_transitions = TransitionArray::cast(transitions);
+  for (int i = 0; i < old_transitions->number_of_transitions(); i++) {
+    Map* target = old_transitions->GetTarget(i);
+    if (target->instance_descriptors() == map->instance_descriptors()) {
+      Name* key = old_transitions->GetKey(i);
+      int new_target_index;
+      if (TransitionArray::IsSpecialTransition(key)) {
+        new_target_index = new_transitions->SearchSpecial(Symbol::cast(key));
+      } else {
+        PropertyDetails details =
+            TransitionArray::GetTargetDetails(key, target);
+        new_target_index =
+            new_transitions->Search(details.kind(), key, details.attributes());
+      }
+      DCHECK_NE(TransitionArray::kNotFound, new_target_index);
+      DCHECK_EQ(target, new_transitions->GetTarget(new_target_index));
+    }
+  }
+}
+#endif
+
+
+// Private non-static helper functions (operating on full transition arrays).
+
 int TransitionArray::SearchDetails(int transition, PropertyKind kind,
                                    PropertyAttributes attributes,
                                    int* out_insertion_index) {
index 999ad86..1cb91a2 100644 (file)
@@ -16,47 +16,99 @@ namespace internal {
 
 
 // TransitionArrays are fixed arrays used to hold map transitions for property,
-// constant, and element changes. They can either be simple transition arrays
-// that store a single property transition, or a full transition array that has
+// constant, and element changes. "Simple" transitions storing only a single
+// property transition are stored inline (i.e. the target map is stored
+// directly); otherwise a full transition array is used that has
 // prototype transitions and multiple property transitons. The details related
 // to property transitions are accessed in the descriptor array of the target
 // map. In the case of a simple transition, the key is also read from the
 // descriptor array of the target map.
 //
-// The simple format of the these objects is:
-// [0] Undefined or back pointer map
-// [1] Single transition
+// This class provides a static interface that operates directly on maps
+// and handles the distinction between simple and full transitions storage.
 //
 // The full format is:
-// [0] Undefined or back pointer map
-// [1] Smi(0) or fixed array of prototype transitions
-// [2] Number of transitions
-// [3] First transition
-// [3 + number of transitions * kTransitionSize]: start of slack
+// [0] Smi(0) or fixed array of prototype transitions
+// [1] Number of transitions
+// [2] First transition
+// [2 + number of transitions * kTransitionSize]: start of slack
 class TransitionArray: public FixedArray {
  public:
-  // Accessors for fetching instance transition at transition number.
-  inline Name* GetKey(int transition_number);
-  inline void SetKey(int transition_number, Name* value);
-  inline Object** GetKeySlot(int transition_number);
-  int GetSortedKeyIndex(int transition_number) { return transition_number; }
+  // Insert a new transition into |map|'s transition array, extending it
+  // as necessary.
+  static void Insert(Handle<Map> map, Handle<Name> name, Handle<Map> target,
+                     SimpleTransitionFlag flag);
 
-  Name* GetSortedKey(int transition_number) {
-    return GetKey(transition_number);
-  }
+  static Map* SearchTransition(Map* map, PropertyKind kind, Name* name,
+                               PropertyAttributes attributes);
 
-  inline Map* GetTarget(int transition_number);
-  inline void SetTarget(int transition_number, Map* target);
+  static Map* SearchSpecial(Map* map, Symbol* name);
 
-  inline PropertyDetails GetTargetDetails(int transition_number);
-  inline Object* GetTargetValue(int transition_number);
+  static Handle<Map> FindTransitionToField(Handle<Map> map, Handle<Name> name);
 
-  inline bool HasElementsTransition();
+  static Handle<String> ExpectedTransitionKey(Handle<Map> map);
 
-  inline Object* back_pointer_storage();
-  inline void set_back_pointer_storage(
-      Object* back_pointer,
-      WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+  static Handle<Map> ExpectedTransitionTarget(Handle<Map> map) {
+    DCHECK(!ExpectedTransitionKey(map).is_null());
+    return Handle<Map>(GetSimpleTransition(map->raw_transitions()));
+  }
+  // Returns true if |raw_transition| can be overwritten with a simple
+  // transition (because it's either uninitialized, or has been cleared).
+  static inline bool CanStoreSimpleTransition(Object* raw_transition) {
+    return raw_transition->IsSmi() ||
+           (raw_transition->IsWeakCell() &&
+            WeakCell::cast(raw_transition)->cleared());
+  }
+  static inline bool IsSimpleTransition(Object* raw_transition) {
+    DCHECK(!raw_transition->IsWeakCell() ||
+           WeakCell::cast(raw_transition)->cleared() ||
+           WeakCell::cast(raw_transition)->value()->IsMap());
+    return raw_transition->IsWeakCell() &&
+           !WeakCell::cast(raw_transition)->cleared();
+  }
+  static inline Map* GetSimpleTransition(Object* raw_transition) {
+    DCHECK(IsSimpleTransition(raw_transition));
+    DCHECK(raw_transition->IsWeakCell());
+    return Map::cast(WeakCell::cast(raw_transition)->value());
+  }
+  static inline bool IsFullTransitionArray(Object* raw_transitions) {
+    return raw_transitions->IsTransitionArray();
+  }
+
+  // The size of transition arrays are limited so they do not end up in large
+  // object space. Otherwise ClearNonLiveReferences would leak memory while
+  // applying in-place right trimming.
+  static bool CanHaveMoreTransitions(Handle<Map> map);
+
+  // ===== PROTOTYPE TRANSITIONS =====
+  // When you set the prototype of an object using the __proto__ accessor you
+  // need a new map for the object (the prototype is stored in the map).  In
+  // order not to multiply maps unnecessarily we store these as transitions in
+  // 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 they transition to.
+  // Cache format:
+  //    0: finger - index of the first free cell in the cache
+  //    1 + i: target map
+  static const int kMaxCachedPrototypeTransitions = 256;
+  static Handle<Map> PutPrototypeTransition(Handle<Map> map,
+                                            Handle<Object> prototype,
+                                            Handle<Map> target_map);
+
+  static Handle<Map> GetPrototypeTransition(Handle<Map> map,
+                                            Handle<Object> prototype);
+
+  static FixedArray* GetPrototypeTransitions(Map* map);
+
+  static int NumberOfPrototypeTransitions(FixedArray* proto_transitions) {
+    if (proto_transitions->length() == 0) return 0;
+    Object* raw = proto_transitions->get(kProtoTransitionNumberOfEntriesOffset);
+    return Smi::cast(raw)->value();
+  }
+
+  static void SetNumberOfPrototypeTransitions(FixedArray* proto_transitions,
+                                              int value);
 
   inline FixedArray* GetPrototypeTransitions();
   inline void SetPrototypeTransitions(
@@ -65,133 +117,92 @@ class TransitionArray: public FixedArray {
   inline Object** GetPrototypeTransitionsSlot();
   inline bool HasPrototypeTransitions();
 
-  // Returns the number of transitions in the array.
-  int number_of_transitions() {
-    if (IsSimpleTransition()) return 1;
-    if (length() <= kFirstIndex) return 0;
-    return Smi::cast(get(kTransitionLengthIndex))->value();
-  }
+  // ===== ITERATION =====
 
-  int number_of_transitions_storage() {
-    if (IsSimpleTransition()) return 1;
-    if (length() <= kFirstIndex) return 0;
-    return (length() - kFirstIndex) / kTransitionSize;
-  }
+  typedef void (*TraverseCallback)(Map* map, void* data);
 
-  int NumberOfSlackTransitions() {
-    return number_of_transitions_storage() - number_of_transitions();
+  // Traverse the transition tree in postorder.
+  static void TraverseTransitionTree(Map* map, TraverseCallback callback,
+                                     void* data) {
+    // Make sure that we do not allocate in the callback.
+    DisallowHeapAllocation no_allocation;
+    TraverseTransitionTreeInternal(map, callback, data);
   }
 
-  inline void SetNumberOfTransitions(int number_of_transitions);
-  inline int number_of_entries() { return number_of_transitions(); }
+  // ===== LOW-LEVEL ACCESSORS =====
 
-  // Creates a FullTransitionArray from a SimpleTransitionArray in
-  // containing_map.
-  static Handle<TransitionArray> ExtendToFullTransitionArray(
-      Handle<Map> containing_map);
-
-  // 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> 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);
+  // Accessors for fetching instance transition at transition number.
+  static inline Name* GetKey(Object* raw_transitions, int transition_number);
+  inline Name* GetKey(int transition_number);
+  inline void SetKey(int transition_number, Name* value);
+  inline Object** GetKeySlot(int transition_number);
+  int GetSortedKeyIndex(int transition_number) { return transition_number; }
 
-  // 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);
+  Name* GetSortedKey(int transition_number) {
+    return GetKey(transition_number);
   }
 
+  static inline Map* GetTarget(Object* raw_transitions, int transition_number);
+  inline Map* GetTarget(int transition_number);
+  inline void SetTarget(int transition_number, Map* target);
+
   static inline PropertyDetails GetTargetDetails(Name* name, Map* target);
 
-  // Allocates a TransitionArray.
-  static Handle<TransitionArray> Allocate(Isolate* isolate,
-                                          int number_of_transitions,
-                                          int slack = 0);
+  // Returns the number of transitions in the array.
+  static int NumberOfTransitions(Object* raw_transitions);
+  // Required for templatized Search interface.
+  inline int number_of_entries() { return number_of_transitions(); }
 
-  bool IsSimpleTransition() {
-    return length() == kSimpleTransitionSize &&
-        get(kSimpleTransitionTarget)->IsHeapObject() &&
-        // The IntrusivePrototypeTransitionIterator may have set the map of the
-        // prototype transitions array to a smi. In that case, there are
-        // prototype transitions, hence this transition array is a full
-        // transition array.
-        HeapObject::cast(get(kSimpleTransitionTarget))->map()->IsMap() &&
-        get(kSimpleTransitionTarget)->IsMap();
-  }
+  inline void SetNumberOfTransitions(int number_of_transitions);
 
-  bool IsFullTransitionArray() {
-    return length() > kFirstIndex ||
-        (length() == kFirstIndex && !IsSimpleTransition());
-  }
+  static int Capacity(Object* raw_transitions);
 
   // Casting.
   static inline TransitionArray* cast(Object* obj);
 
-  // Constant for denoting key was not found.
-  static const int kNotFound = -1;
-
-  static const int kBackPointerStorageIndex = 0;
-
-  // Layout for full transition arrays.
-  static const int kPrototypeTransitionsIndex = 1;
-  static const int kTransitionLengthIndex = 2;
-  static const int kFirstIndex = 3;
-
-  // Layout for simple transition arrays.
-  static const int kSimpleTransitionTarget = 1;
-  static const int kSimpleTransitionSize = 2;
-  static const int kSimpleTransitionIndex = 0;
-  STATIC_ASSERT(kSimpleTransitionIndex != kNotFound);
-
-  static const int kBackPointerStorageOffset = FixedArray::kHeaderSize;
-
-  // 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;
+  static const int kProtoTransitionHeaderSize = 1;
 
 #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(std::ostream& os, bool print_header = true);  // NOLINT
+  static void PrintTransitions(std::ostream& os, Object* transitions,
+                               bool print_header = true);  // NOLINT
 #endif
 
 #ifdef DEBUG
   bool IsSortedNoDuplicates(int valid_entries = -1);
-  bool IsConsistentWithBackPointers(Map* current_map);
-  bool IsEqualTo(TransitionArray* other);
+  static bool IsSortedNoDuplicates(Map* map);
+  static bool IsConsistentWithBackPointers(Map* map);
 
   // Returns true for a non-property transitions like elements kind, observed
   // or frozen transitions.
   static inline bool IsSpecialTransition(Name* name);
 #endif
 
+  // Constant for denoting key was not found.
+  static const int kNotFound = -1;
+
   // 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:
+  // Layout for full transition arrays.
+  static const int kPrototypeTransitionsIndex = 0;
+  static const int kTransitionLengthIndex = 1;
+  static const int kFirstIndex = 2;
+
+  // Layout of map transition entries in full transition arrays.
+  static const int kTransitionKey = 0;
+  static const int kTransitionTarget = 1;
+  STATIC_ASSERT(kTransitionSize == 2);
+
+  static const int kProtoTransitionNumberOfEntriesOffset = 0;
+  STATIC_ASSERT(kProtoTransitionHeaderSize == 1);
+
   // Conversion from transition number to array indices.
   static int ToKeyIndex(int transition_number) {
     return kFirstIndex +
@@ -205,20 +216,55 @@ class TransitionArray: public FixedArray {
            kTransitionTarget;
   }
 
-  static Handle<TransitionArray> AllocateSimple(
-      Isolate* isolate, Handle<Map> target);
+  // Returns the fixed array length required to hold number_of_transitions
+  // transitions.
+  static int LengthFor(int number_of_transitions) {
+    return ToKeyIndex(number_of_transitions);
+  }
+
+  // Allocates a TransitionArray.
+  static Handle<TransitionArray> Allocate(Isolate* isolate,
+                                          int number_of_transitions,
+                                          int slack = 0);
+
+  static void EnsureHasFullTransitionArray(Handle<Map> map);
+  static void ReplaceTransitions(Handle<Map> map, Object* new_transitions);
 
-  // Allocate a new transition array with a single entry.
-  static Handle<TransitionArray> NewWith(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 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);
+  }
   // 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);
 
+  int number_of_transitions() {
+    if (length() < kFirstIndex) return 0;
+    return Smi::cast(get(kTransitionLengthIndex))->value();
+  }
+
+  static inline PropertyDetails GetSimpleTargetDetails(Map* transition) {
+    return transition->GetLastDescriptorDetails();
+  }
+
+  static inline Name* GetSimpleTransitionKey(Map* transition) {
+    int descriptor = transition->LastAdded();
+    return transition->instance_descriptors()->GetKey(descriptor);
+  }
+
+  static void TraverseTransitionTreeInternal(Map* map,
+                                             TraverseCallback callback,
+                                             void* data);
+
+  static void SetPrototypeTransitions(Handle<Map> map,
+                                      Handle<FixedArray> proto_transitions);
+
   // 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,
@@ -247,6 +293,12 @@ class TransitionArray: public FixedArray {
                                                 int origin_transition,
                                                 int target_transition);
 
+#ifdef DEBUG
+  static void CheckNewTransitionsAreConsistent(Handle<Map> map,
+                                               TransitionArray* old_transitions,
+                                               Object* transitions);
+#endif
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(TransitionArray);
 };
 
index b0be315..6653bea 100644 (file)
@@ -75,15 +75,22 @@ void TypeFeedbackVector::SetKind(FeedbackVectorICSlot slot, Code::Kind kind) {
 }
 
 
+template Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(
+    Isolate* isolate, const FeedbackVectorSpec* spec);
+template Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(
+    Isolate* isolate, const ZoneFeedbackVectorSpec* spec);
+
+
 // static
-Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(
-    Isolate* isolate, const FeedbackVectorSpec& spec) {
-  const int slot_count = spec.slots();
-  const int ic_slot_count = spec.ic_slots();
+template <typename Spec>
+Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(Isolate* isolate,
+                                                        const Spec* 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;
+  const int length = slot_count + (ic_slot_count * elements_per_ic_slot()) +
+                     index_count + kReservedIndexCount;
   if (length == kReservedIndexCount) {
     return Handle<TypeFeedbackVector>::cast(
         isolate->factory()->empty_fixed_array());
@@ -113,7 +120,7 @@ Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(
   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));
+      vector->SetKind(FeedbackVectorICSlot(i), spec->GetKind(i));
     }
   }
   return vector;
@@ -207,16 +214,28 @@ Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
 }
 
 
-void FeedbackNexus::InstallHandlers(int start_index, MapHandleList* maps,
-                                    CodeHandleList* handlers) {
+Handle<FixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
   Isolate* isolate = GetIsolate();
-  Handle<FixedArray> array = handle(FixedArray::cast(GetFeedback()), isolate);
+  Handle<Object> feedback_extra = handle(GetFeedbackExtra(), isolate);
+  if (!feedback_extra->IsFixedArray() ||
+      FixedArray::cast(*feedback_extra)->length() != length) {
+    Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
+    SetFeedbackExtra(*array);
+    return array;
+  }
+  return Handle<FixedArray>::cast(feedback_extra);
+}
+
+
+void FeedbackNexus::InstallHandlers(Handle<FixedArray> array,
+                                    MapHandleList* maps,
+                                    CodeHandleList* handlers) {
   int receiver_count = maps->length();
   for (int current = 0; current < receiver_count; ++current) {
     Handle<Map> map = maps->at(current);
     Handle<WeakCell> cell = Map::WeakCellForMap(map);
-    array->set(start_index + (current * 2), *cell);
-    array->set(start_index + (current * 2 + 1), *handlers->at(current));
+    array->set(current * 2, *cell);
+    array->set(current * 2 + 1, *handlers->at(current));
   }
 }
 
@@ -224,6 +243,7 @@ void FeedbackNexus::InstallHandlers(int start_index, MapHandleList* maps,
 InlineCacheState LoadICNexus::StateFromFeedback() const {
   Isolate* isolate = GetIsolate();
   Object* feedback = GetFeedback();
+
   if (feedback == *vector()->UninitializedSentinel(isolate)) {
     return UNINITIALIZED;
   } else if (feedback == *vector()->MegamorphicSentinel(isolate)) {
@@ -233,10 +253,10 @@ InlineCacheState LoadICNexus::StateFromFeedback() const {
   } 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 POLYMORPHIC;
+  } else if (feedback->IsWeakCell()) {
+    // Don't check if the map is cleared.
+    return MONOMORPHIC;
   }
 
   return UNINITIALIZED;
@@ -246,6 +266,7 @@ InlineCacheState LoadICNexus::StateFromFeedback() const {
 InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
   Isolate* isolate = GetIsolate();
   Object* feedback = GetFeedback();
+
   if (feedback == *vector()->UninitializedSentinel(isolate)) {
     return UNINITIALIZED;
   } else if (feedback == *vector()->PremonomorphicSentinel(isolate)) {
@@ -255,10 +276,14 @@ InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
   } 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 POLYMORPHIC;
+  } else if (feedback->IsWeakCell()) {
+    // Don't check if the map is cleared.
+    return MONOMORPHIC;
+  } else if (feedback->IsName()) {
+    Object* extra = GetFeedbackExtra();
+    FixedArray* extra_array = FixedArray::cast(extra);
+    return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
   }
 
   return UNINITIALIZED;
@@ -268,6 +293,8 @@ InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
 InlineCacheState CallICNexus::StateFromFeedback() const {
   Isolate* isolate = GetIsolate();
   Object* feedback = GetFeedback();
+  DCHECK(!FLAG_vector_ics ||
+         GetFeedbackExtra() == *vector()->UninitializedSentinel(isolate));
 
   if (feedback == *vector()->MegamorphicSentinel(isolate)) {
     return GENERIC;
@@ -311,56 +338,68 @@ void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
 
 
 void KeyedLoadICNexus::ConfigureMegamorphic() {
-  SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
+  Isolate* isolate = GetIsolate();
+  SetFeedback(*vector()->MegamorphicSentinel(isolate), SKIP_WRITE_BARRIER);
+  SetFeedbackExtra(*vector()->UninitializedSentinel(isolate),
+                   SKIP_WRITE_BARRIER);
 }
 
 
 void LoadICNexus::ConfigureMegamorphic() {
   SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
+  SetFeedbackExtra(*vector()->UninitializedSentinel(GetIsolate()),
+                   SKIP_WRITE_BARRIER);
 }
 
 
 void LoadICNexus::ConfigurePremonomorphic() {
   SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
               SKIP_WRITE_BARRIER);
+  SetFeedbackExtra(*vector()->UninitializedSentinel(GetIsolate()),
+                   SKIP_WRITE_BARRIER);
 }
 
 
 void KeyedLoadICNexus::ConfigurePremonomorphic() {
-  SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
-              SKIP_WRITE_BARRIER);
+  Isolate* isolate = GetIsolate();
+  SetFeedback(*vector()->PremonomorphicSentinel(isolate), SKIP_WRITE_BARRIER);
+  SetFeedbackExtra(*vector()->UninitializedSentinel(isolate),
+                   SKIP_WRITE_BARRIER);
 }
 
 
 void LoadICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
                                        Handle<Code> handler) {
-  Handle<FixedArray> array = EnsureArrayOfSize(2);
   Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
-  array->set(0, *cell);
-  array->set(1, *handler);
+  SetFeedback(*cell);
+  SetFeedbackExtra(*handler);
 }
 
 
 void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
                                             Handle<Map> receiver_map,
                                             Handle<Code> handler) {
-  Handle<FixedArray> array = EnsureArrayOfSize(3);
+  Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
   if (name.is_null()) {
-    array->set(0, Smi::FromInt(0));
+    SetFeedback(*cell);
+    SetFeedbackExtra(*handler);
   } else {
-    array->set(0, *name);
+    SetFeedback(*name);
+    Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
+    array->set(0, *cell);
+    array->set(1, *handler);
   }
-  Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
-  array->set(1, *cell);
-  array->set(2, *handler);
 }
 
 
 void LoadICNexus::ConfigurePolymorphic(MapHandleList* maps,
                                        CodeHandleList* handlers) {
+  Isolate* isolate = GetIsolate();
   int receiver_count = maps->length();
-  EnsureArrayOfSize(receiver_count * 2);
-  InstallHandlers(0, maps, handlers);
+  Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
+  InstallHandlers(array, maps, handlers);
+  SetFeedbackExtra(*vector()->UninitializedSentinel(isolate),
+                   SKIP_WRITE_BARRIER);
 }
 
 
@@ -368,26 +407,35 @@ void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
                                             MapHandleList* maps,
                                             CodeHandleList* handlers) {
   int receiver_count = maps->length();
-  Handle<FixedArray> array = EnsureArrayOfSize(1 + receiver_count * 2);
+  DCHECK(receiver_count > 1);
+  Handle<FixedArray> array;
   if (name.is_null()) {
-    array->set(0, Smi::FromInt(0));
+    array = EnsureArrayOfSize(receiver_count * 2);
+    SetFeedbackExtra(*vector()->UninitializedSentinel(GetIsolate()),
+                     SKIP_WRITE_BARRIER);
   } else {
-    array->set(0, *name);
+    SetFeedback(*name);
+    array = EnsureExtraArrayOfSize(receiver_count * 2);
   }
-  InstallHandlers(1, maps, handlers);
+
+  InstallHandlers(array, maps, handlers);
 }
 
 
-int FeedbackNexus::ExtractMaps(int start_index, MapHandleList* maps) const {
+int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
   Isolate* isolate = GetIsolate();
   Object* feedback = GetFeedback();
-  if (feedback->IsFixedArray()) {
+  if (feedback->IsFixedArray() || feedback->IsString()) {
     int found = 0;
+    if (feedback->IsString()) {
+      feedback = GetFeedbackExtra();
+    }
     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) {
+    DCHECK(array->length() >= 2);
+    for (int i = 0; i < array->length(); i += 2) {
+      DCHECK(array->get(i)->IsWeakCell());
       WeakCell* cell = WeakCell::cast(array->get(i));
       if (!cell->cleared()) {
         Map* map = Map::cast(cell->value());
@@ -396,18 +444,28 @@ int FeedbackNexus::ExtractMaps(int start_index, MapHandleList* maps) const {
       }
     }
     return found;
+  } else if (feedback->IsWeakCell()) {
+    WeakCell* cell = WeakCell::cast(feedback);
+    if (!cell->cleared()) {
+      Map* map = Map::cast(cell->value());
+      maps->Add(handle(map, isolate));
+      return 1;
+    }
   }
 
   return 0;
 }
 
 
-MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(int start_index,
-                                                   Handle<Map> map) const {
+MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
   Object* feedback = GetFeedback();
-  if (feedback->IsFixedArray()) {
+  if (feedback->IsFixedArray() || feedback->IsString()) {
+    if (feedback->IsString()) {
+      feedback = GetFeedbackExtra();
+    }
     FixedArray* array = FixedArray::cast(feedback);
-    for (int i = start_index; i < array->length(); i += 2) {
+    for (int i = 0; i < array->length(); i += 2) {
+      DCHECK(array->get(i)->IsWeakCell());
       WeakCell* cell = WeakCell::cast(array->get(i));
       if (!cell->cleared()) {
         Map* array_map = Map::cast(cell->value());
@@ -418,23 +476,35 @@ MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(int start_index,
         }
       }
     }
+  } else if (feedback->IsWeakCell()) {
+    WeakCell* cell = WeakCell::cast(feedback);
+    if (!cell->cleared()) {
+      Map* cell_map = Map::cast(cell->value());
+      if (cell_map == *map) {
+        Code* code = Code::cast(GetFeedbackExtra());
+        DCHECK(code->kind() == Code::HANDLER);
+        return handle(code);
+      }
+    }
   }
 
   return MaybeHandle<Code>();
 }
 
 
-bool FeedbackNexus::FindHandlers(int start_index, CodeHandleList* code_list,
-                                 int length) const {
+bool FeedbackNexus::FindHandlers(CodeHandleList* code_list, int length) const {
   Object* feedback = GetFeedback();
   int count = 0;
-  if (feedback->IsFixedArray()) {
+  if (feedback->IsFixedArray() || feedback->IsString()) {
+    if (feedback->IsString()) {
+      feedback = GetFeedbackExtra();
+    }
     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) {
+    // The array should be of the form [map, handler, map, handler, ... ].
+    // Be sure to skip handlers whose maps have been cleared.
+    DCHECK(array->length() >= 2);
+    for (int i = 0; i < array->length(); i += 2) {
+      DCHECK(array->get(i)->IsWeakCell());
       WeakCell* cell = WeakCell::cast(array->get(i));
       if (!cell->cleared()) {
         Code* code = Code::cast(array->get(i + 1));
@@ -443,16 +513,19 @@ bool FeedbackNexus::FindHandlers(int start_index, CodeHandleList* code_list,
         count++;
       }
     }
+  } else if (feedback->IsWeakCell()) {
+    WeakCell* cell = WeakCell::cast(feedback);
+    if (!cell->cleared()) {
+      Code* code = Code::cast(GetFeedbackExtra());
+      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); }
 
 
@@ -461,39 +534,10 @@ void KeyedLoadICNexus::Clear(Code* host) {
 }
 
 
-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);
+  if (feedback->IsString()) {
+    return Name::cast(feedback);
   }
   return NULL;
 }
index b7abad5..c26a2d3 100644 (file)
 #include "src/heap/heap.h"
 #include "src/isolate.h"
 #include "src/objects.h"
+#include "src/zone-containers.h"
 
 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);
+  FeedbackVectorSpec() : slots_(0), has_ic_slot_(false) {}
+  explicit FeedbackVectorSpec(int slots) : slots_(slots), has_ic_slot_(false) {}
+  FeedbackVectorSpec(int slots, Code::Kind ic_slot_kind)
+      : slots_(slots), has_ic_slot_(true), ic_kind_(ic_slot_kind) {}
+
+  int slots() const { return slots_; }
+
+  int ic_slots() const { return has_ic_slot_ ? 1 : 0; }
+
+  Code::Kind GetKind(int ic_slot) const {
+    DCHECK(FLAG_vector_ics && has_ic_slot_ && ic_slot == 0);
+    return ic_kind_;
   }
 
+ private:
+  int slots_;
+  bool has_ic_slot_;
+  Code::Kind ic_kind_;
+};
+
+
+class ZoneFeedbackVectorSpec {
+ public:
+  explicit ZoneFeedbackVectorSpec(Zone* zone)
+      : slots_(0), ic_slots_(0), ic_slot_kinds_(zone) {}
+
+  ZoneFeedbackVectorSpec(Zone* zone, int slots, int ic_slots)
+      : slots_(slots),
+        ic_slots_(ic_slots),
+        ic_slot_kinds_(FLAG_vector_ics ? ic_slots : 0, zone) {}
+
   int slots() const { return slots_; }
   void increase_slots(int count) { slots_ += count; }
 
@@ -46,7 +72,7 @@ class FeedbackVectorSpec {
  private:
   int slots_;
   int ic_slots_;
-  std::vector<unsigned char> ic_slot_kinds_;
+  ZoneVector<unsigned char> ic_slot_kinds_;
 };
 
 
@@ -74,6 +100,8 @@ class TypeFeedbackVector : public FixedArray {
   static const int kWithTypesIndex = 1;
   static const int kGenericCountIndex = 2;
 
+  static int elements_per_ic_slot() { return FLAG_vector_ics ? 2 : 1; }
+
   int first_ic_slot_index() const {
     DCHECK(length() >= kReservedIndexCount);
     return Smi::cast(get(kFirstICSlotIndex))->value();
@@ -114,7 +142,7 @@ class TypeFeedbackVector : public FixedArray {
 
   int ICSlots() const {
     if (length() == 0) return 0;
-    return length() - first_ic_slot_index();
+    return (length() - first_ic_slot_index()) / elements_per_ic_slot();
   }
 
   // Conversion from a slot or ic slot to an integer index to the underlying
@@ -127,7 +155,7 @@ class TypeFeedbackVector : public FixedArray {
   int GetIndex(FeedbackVectorICSlot slot) const {
     int first_ic_slot = first_ic_slot_index();
     DCHECK(slot.ToInt() < ICSlots());
-    return first_ic_slot + slot.ToInt();
+    return first_ic_slot + slot.ToInt() * elements_per_ic_slot();
   }
 
   // Conversion from an integer index to either a slot or an ic slot. The caller
@@ -140,7 +168,8 @@ class TypeFeedbackVector : public FixedArray {
 
   FeedbackVectorICSlot ToICSlot(int index) const {
     DCHECK(index >= first_ic_slot_index() && index < length());
-    return FeedbackVectorICSlot(index - first_ic_slot_index());
+    int ic_slot = (index - first_ic_slot_index()) / elements_per_ic_slot();
+    return FeedbackVectorICSlot(ic_slot);
   }
 
   Object* Get(FeedbackVectorSlot slot) const { return get(GetIndex(slot)); }
@@ -158,8 +187,9 @@ class TypeFeedbackVector : public FixedArray {
   // IC slots need metadata to recognize the type of IC.
   Code::Kind GetKind(FeedbackVectorICSlot slot) const;
 
+  template <typename Spec>
   static Handle<TypeFeedbackVector> Allocate(Isolate* isolate,
-                                             const FeedbackVectorSpec& spec);
+                                             const Spec* spec);
 
   static Handle<TypeFeedbackVector> Copy(Isolate* isolate,
                                          Handle<TypeFeedbackVector> vector);
@@ -244,14 +274,17 @@ class FeedbackNexus {
   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 int ExtractMaps(MapHandleList* maps) const;
+  virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const;
+  virtual bool FindHandlers(CodeHandleList* code_list, int length = -1) const;
   virtual Name* FindFirstName() const { return NULL; }
 
   Object* GetFeedback() const { return vector()->Get(slot()); }
+  Object* GetFeedbackExtra() const {
+    DCHECK(TypeFeedbackVector::elements_per_ic_slot() > 1);
+    int extra_index = vector()->GetIndex(slot()) + 1;
+    return vector()->get(extra_index);
+  }
 
  protected:
   Isolate* GetIsolate() const { return vector()->GetIsolate(); }
@@ -261,13 +294,17 @@ class FeedbackNexus {
     vector()->Set(slot(), feedback, mode);
   }
 
+  void SetFeedbackExtra(Object* feedback_extra,
+                        WriteBarrierMode mode = UPDATE_WRITE_BARRIER) {
+    DCHECK(TypeFeedbackVector::elements_per_ic_slot() > 1);
+    int index = vector()->GetIndex(slot()) + 1;
+    vector()->set(index, feedback_extra, mode);
+  }
+
   Handle<FixedArray> EnsureArrayOfSize(int length);
-  void InstallHandlers(int start_index, MapHandleList* maps,
+  Handle<FixedArray> EnsureExtraArrayOfSize(int length);
+  void InstallHandlers(Handle<FixedArray> array, MapHandleList* maps,
                        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
@@ -334,10 +371,6 @@ class LoadICNexus : public FeedbackNexus {
   void ConfigurePolymorphic(MapHandleList* maps, 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;
 };
 
 
@@ -364,10 +397,6 @@ class KeyedLoadICNexus : public FeedbackNexus {
                             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;
 };
 }
index 96bd0ed..087e1db 100644 (file)
@@ -52,11 +52,7 @@ Handle<Object> TypeFeedbackOracle::GetInfo(TypeFeedbackId ast_id) {
 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());
+  return Handle<Object>(obj, isolate());
 }
 
 
@@ -74,10 +70,10 @@ Handle<Object> TypeFeedbackOracle::GetInfo(FeedbackVectorICSlot slot) {
     obj = cell->value();
   }
 
-  if (!obj->IsJSFunction() ||
-      !CanRetainOtherContext(JSFunction::cast(obj), *native_context_)) {
+  if (obj->IsJSFunction() || obj->IsAllocationSite() || obj->IsSymbol()) {
     return Handle<Object>(obj, isolate());
   }
+
   return undefined;
 }
 
@@ -245,12 +241,7 @@ void TypeFeedbackOracle::CompareType(TypeFeedbackId id,
 
   Handle<Map> map;
   Map* raw_map = code->FindFirstMap();
-  if (raw_map != NULL) {
-    if (Map::TryUpdate(handle(raw_map)).ToHandle(&map) &&
-        CanRetainOtherContext(*map, *native_context_)) {
-      map = Handle<Map>::null();
-    }
-  }
+  if (raw_map != NULL) Map::TryUpdate(handle(raw_map)).ToHandle(&map);
 
   if (code->is_compare_ic_stub()) {
     CompareICStub stub(code->stub_key(), isolate());
@@ -279,7 +270,7 @@ void TypeFeedbackOracle::BinaryType(TypeFeedbackId id,
     DCHECK(op < BinaryOpICState::FIRST_TOKEN ||
            op > BinaryOpICState::LAST_TOKEN);
     *left = *right = *result = Type::None(zone());
-    *fixed_right_arg = Maybe<int>();
+    *fixed_right_arg = Nothing<int>();
     *allocation_site = Handle<AllocationSite>::null();
     return;
   }
@@ -313,7 +304,7 @@ Type* TypeFeedbackOracle::CountType(TypeFeedbackId id) {
 
 
 void TypeFeedbackOracle::PropertyReceiverTypes(TypeFeedbackId id,
-                                               Handle<String> name,
+                                               Handle<Name> name,
                                                SmallMapList* receiver_types) {
   receiver_types->Clear();
   Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
@@ -343,7 +334,7 @@ void TypeFeedbackOracle::KeyedPropertyReceiverTypes(
 
 
 void TypeFeedbackOracle::PropertyReceiverTypes(FeedbackVectorICSlot slot,
-                                               Handle<String> name,
+                                               Handle<Name> name,
                                                SmallMapList* receiver_types) {
   receiver_types->Clear();
   LoadICNexus nexus(feedback_vector_, slot);
@@ -363,8 +354,9 @@ void TypeFeedbackOracle::KeyedPropertyReceiverTypes(
 }
 
 
-void TypeFeedbackOracle::AssignmentReceiverTypes(
-    TypeFeedbackId id, Handle<String> name, SmallMapList* receiver_types) {
+void TypeFeedbackOracle::AssignmentReceiverTypes(TypeFeedbackId id,
+                                                 Handle<Name> name,
+                                                 SmallMapList* receiver_types) {
   receiver_types->Clear();
   Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
   CollectReceiverTypes(id, name, flags, receiver_types);
@@ -388,7 +380,7 @@ void TypeFeedbackOracle::CountReceiverTypes(TypeFeedbackId id,
 
 
 void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id,
-                                              Handle<String> name,
+                                              Handle<Name> name,
                                               Code::Flags flags,
                                               SmallMapList* types) {
   Handle<Object> object = GetInfo(ast_id);
@@ -401,7 +393,7 @@ void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id,
 
 
 template <class T>
-void TypeFeedbackOracle::CollectReceiverTypes(T* obj, Handle<String> name,
+void TypeFeedbackOracle::CollectReceiverTypes(T* obj, Handle<Name> name,
                                               Code::Flags flags,
                                               SmallMapList* types) {
   if (FLAG_collect_megamorphic_maps_from_stub_cache &&
@@ -415,43 +407,6 @@ void TypeFeedbackOracle::CollectReceiverTypes(T* obj, Handle<String> name,
 }
 
 
-// Check if a map originates from a given native context. We use this
-// information to filter out maps from different context to avoid
-// retaining objects from different tabs in Chrome via optimized code.
-bool TypeFeedbackOracle::CanRetainOtherContext(Map* map,
-                                               Context* native_context) {
-  Object* constructor = NULL;
-  while (!map->prototype()->IsNull()) {
-    constructor = map->constructor();
-    if (!constructor->IsNull()) {
-      // If the constructor is not null or a JSFunction, we have to
-      // conservatively assume that it may retain a native context.
-      if (!constructor->IsJSFunction()) return true;
-      // Check if the constructor directly references a foreign context.
-      if (CanRetainOtherContext(JSFunction::cast(constructor),
-                                native_context)) {
-        return true;
-      }
-    }
-    map = HeapObject::cast(map->prototype())->map();
-  }
-  constructor = map->constructor();
-  if (constructor->IsNull()) return false;
-  // If the constructor is not null or a JSFunction, we have to conservatively
-  // assume that it may retain a native context.
-  if (!constructor->IsJSFunction()) return true;
-  JSFunction* function = JSFunction::cast(constructor);
-  return CanRetainOtherContext(function, native_context);
-}
-
-
-bool TypeFeedbackOracle::CanRetainOtherContext(JSFunction* function,
-                                               Context* native_context) {
-  return function->context()->global_object() != native_context->global_object()
-      && function->context()->global_object() != native_context->builtins();
-}
-
-
 void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id,
                                               SmallMapList* types) {
   Handle<Object> object = GetInfo(ast_id);
@@ -475,8 +430,8 @@ void TypeFeedbackOracle::CollectReceiverTypes(T* obj, SmallMapList* types) {
   types->Reserve(maps.length(), zone());
   for (int i = 0; i < maps.length(); i++) {
     Handle<Map> map(maps.at(i));
-    if (!CanRetainOtherContext(*map, *native_context_)) {
-      types->AddMapIfMissing(map, zone());
+    if (IsRelevantFeedback(*map, *native_context_)) {
+      types->AddMapIfMissing(maps.at(i), zone());
     }
   }
 }
index 65af768..bd275e6 100644 (file)
@@ -42,9 +42,9 @@ class TypeFeedbackOracle: public ZoneObject {
                               IcCheckType* key_type);
   void GetLoadKeyType(TypeFeedbackId id, IcCheckType* key_type);
 
-  void PropertyReceiverTypes(TypeFeedbackId id, Handle<String> name,
+  void PropertyReceiverTypes(TypeFeedbackId id, Handle<Name> name,
                              SmallMapList* receiver_types);
-  void PropertyReceiverTypes(FeedbackVectorICSlot slot, Handle<String> name,
+  void PropertyReceiverTypes(FeedbackVectorICSlot slot, Handle<Name> name,
                              SmallMapList* receiver_types);
   void KeyedPropertyReceiverTypes(TypeFeedbackId id,
                                   SmallMapList* receiver_types,
@@ -53,8 +53,7 @@ class TypeFeedbackOracle: public ZoneObject {
   void KeyedPropertyReceiverTypes(FeedbackVectorICSlot slot,
                                   SmallMapList* receiver_types, bool* is_string,
                                   IcCheckType* key_type);
-  void AssignmentReceiverTypes(TypeFeedbackId id,
-                               Handle<String> name,
+  void AssignmentReceiverTypes(TypeFeedbackId id, Handle<Name> name,
                                SmallMapList* receiver_types);
   void KeyedAssignmentReceiverTypes(TypeFeedbackId id,
                                     SmallMapList* receiver_types,
@@ -68,9 +67,12 @@ class TypeFeedbackOracle: public ZoneObject {
   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);
+  static bool IsRelevantFeedback(Map* map, Context* native_context) {
+    Object* constructor = map->GetConstructor();
+    return !constructor->IsJSFunction() ||
+           JSFunction::cast(constructor)->context()->native_context() ==
+               native_context;
+  }
 
   Handle<JSFunction> GetCallTarget(FeedbackVectorICSlot slot);
   Handle<AllocationSite> GetCallAllocationSite(FeedbackVectorICSlot slot);
@@ -104,12 +106,10 @@ class TypeFeedbackOracle: public ZoneObject {
   Isolate* isolate() const { return isolate_; }
 
  private:
-  void CollectReceiverTypes(TypeFeedbackId id,
-                            Handle<String> name,
-                            Code::Flags flags,
-                            SmallMapList* types);
+  void CollectReceiverTypes(TypeFeedbackId id, Handle<Name> name,
+                            Code::Flags flags, SmallMapList* types);
   template <class T>
-  void CollectReceiverTypes(T* obj, Handle<String> name, Code::Flags flags,
+  void CollectReceiverTypes(T* obj, Handle<Name> name, Code::Flags flags,
                             SmallMapList* types);
 
   // Returns true if there is at least one string map and if
index 4420bce..caa428c 100644 (file)
@@ -162,16 +162,16 @@ function NAMESubArray(begin, end) {
 
   var srcLength = %_TypedArrayGetLength(this);
   if (beginInt < 0) {
-    beginInt = MathMax(0, srcLength + beginInt);
+    beginInt = $max(0, srcLength + beginInt);
   } else {
-    beginInt = MathMin(srcLength, beginInt);
+    beginInt = $min(srcLength, beginInt);
   }
 
   var endInt = IS_UNDEFINED(end) ? srcLength : end;
   if (endInt < 0) {
-    endInt = MathMax(0, srcLength + endInt);
+    endInt = $max(0, srcLength + endInt);
   } else {
-    endInt = MathMin(endInt, srcLength);
+    endInt = $min(endInt, srcLength);
   }
   if (endInt < beginInt) {
     endInt = beginInt;
index 37386cd..9116a69 100644 (file)
@@ -267,7 +267,7 @@ TypeImpl<Config>::BitsetType::Lub(i::Map* map) {
       // Also, it doesn't apply elsewhere. 8-(
       // We ought to find a cleaner solution for compiling stubs parameterised
       // over type or class variables, esp ones with bounds...
-      return kDetectable;
+      return kDetectable & kTaggedPointer;
     case DECLARED_ACCESSOR_INFO_TYPE:
     case EXECUTABLE_ACCESSOR_INFO_TYPE:
     case SHARED_FUNCTION_INFO_TYPE:
@@ -777,7 +777,7 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Intersect(
     bits &= ~number_bits;
     result->Set(0, BitsetType::New(bits, region));
   }
-  return NormalizeUnion(result, size);
+  return NormalizeUnion(result, size, region);
 }
 
 
@@ -992,7 +992,7 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Union(
 
   size = AddToUnion(type1, result, size, region);
   size = AddToUnion(type2, result, size, region);
-  return NormalizeUnion(result, size);
+  return NormalizeUnion(result, size, region);
 }
 
 
@@ -1016,9 +1016,9 @@ int TypeImpl<Config>::AddToUnion(
 }
 
 
-template<class Config>
+template <class Config>
 typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::NormalizeUnion(
-    UnionHandle unioned, int size) {
+    UnionHandle unioned, int size, Region* region) {
   DCHECK(size >= 1);
   DCHECK(unioned->Get(0)->IsBitset());
   // If the union has just one element, return it.
@@ -1032,8 +1032,11 @@ typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::NormalizeUnion(
     if (representation == unioned->Get(1)->Representation()) {
       return unioned->Get(1);
     }
-    // TODO(jarin) If the element at 1 is range of constant, slap
-    // the representation on it and return that.
+    if (unioned->Get(1)->IsRange()) {
+      return RangeType::New(unioned->Get(1)->AsRange()->Min(),
+                            unioned->Get(1)->AsRange()->Max(), unioned->Get(0),
+                            region);
+    }
   }
   unioned->Shrink(size);
   SLOW_DCHECK(unioned->Wellformed());
index 0aae064..1756229 100644 (file)
@@ -615,7 +615,8 @@ class TypeImpl : public Config::Base {
       TypeHandle type, UnionHandle result, int size, Region* region);
   static int IntersectAux(TypeHandle type, TypeHandle other, UnionHandle result,
                           int size, Limits* limits, Region* region);
-  static TypeHandle NormalizeUnion(UnionHandle unioned, int size);
+  static TypeHandle NormalizeUnion(UnionHandle unioned, int size,
+                                   Region* region);
   static TypeHandle NormalizeRangeAndBitset(RangeHandle range, bitset* bits,
                                             Region* region);
 };
index 4852870..1598c09 100644 (file)
@@ -410,7 +410,12 @@ void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) {
       if (!prop->is_computed_name() &&
           prop->key()->AsLiteral()->value()->IsInternalizedString() &&
           prop->emit_store()) {
-        prop->RecordTypeFeedback(oracle());
+        // Record type feed back for the property.
+        TypeFeedbackId id = prop->key()->AsLiteral()->LiteralFeedbackId();
+        SmallMapList maps;
+        oracle()->CollectReceiverTypes(id, &maps);
+        prop->set_receiver_type(maps.length() == 1 ? maps.at(0)
+                                                   : Handle<Map>::null());
       }
     }
 
@@ -562,7 +567,17 @@ void AstTyper::VisitCall(Call* expr) {
 
 void AstTyper::VisitCallNew(CallNew* expr) {
   // Collect type feedback.
-  expr->RecordTypeFeedback(oracle());
+  FeedbackVectorSlot allocation_site_feedback_slot =
+      FLAG_pretenuring_call_new ? expr->AllocationSiteFeedbackSlot()
+                                : expr->CallNewFeedbackSlot();
+  expr->set_allocation_site(
+      oracle()->GetCallNewAllocationSite(allocation_site_feedback_slot));
+  bool monomorphic =
+      oracle()->CallNewIsMonomorphic(expr->CallNewFeedbackSlot());
+  expr->set_is_monomorphic(monomorphic);
+  if (monomorphic) {
+    expr->set_target(oracle()->GetCallNewTarget(expr->CallNewFeedbackSlot()));
+  }
 
   RECURSE(Visit(expr->expression()));
   ZoneList<Expression*>* args = expr->arguments();
@@ -640,7 +655,7 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
   Type* type;
   Type* left_type;
   Type* right_type;
-  Maybe<int> fixed_right_arg;
+  Maybe<int> fixed_right_arg = Nothing<int>();
   Handle<AllocationSite> allocation_site;
   oracle()->BinaryType(expr->BinaryOperationFeedbackId(),
       &left_type, &right_type, &type, &fixed_right_arg,
@@ -784,7 +799,6 @@ void AstTyper::VisitModuleDeclaration(ModuleDeclaration* declaration) {
 
 
 void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) {
-  RECURSE(Visit(declaration->module()));
 }
 
 
index b56ee84..c04c966 100644 (file)
@@ -108,7 +108,12 @@ class Unique {
   }
 
   template <class S> static Unique<T> cast(Unique<S> that) {
-    return Unique<T>(that.raw_address_, Handle<T>::cast(that.handle_));
+    // Allow fetching location() to unsafe-cast the handle. This is necessary
+    // since we can't concurrently safe-cast. Safe-casting requires looking at
+    // the heap which may be moving concurrently to the compiler thread.
+    AllowHandleDereference allow_deref;
+    return Unique<T>(that.raw_address_,
+                     Handle<T>(reinterpret_cast<T**>(that.handle_.location())));
   }
 
   inline bool IsInitialized() const {
index 1c9e3a6..5c7afbe 100644 (file)
@@ -208,7 +208,7 @@ class BitFieldBase {
   static const U kNext = kShift + kSize;
 
   // Value for the field with all bits set.
-  static const T kMax = static_cast<T>((1U << size) - 1);
+  static const T kMax = static_cast<T>((kOne << size) - 1);
 
   // Tells whether the provided value fits into the bit field.
   static bool is_valid(T value) {
index 495921e..4c3c023 100644 (file)
 #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"
+#include "src/snapshot/natives.h"
+#include "src/snapshot/serialize.h"
+#include "src/snapshot/snapshot.h"
 
 
 namespace v8 {
index 2314334..1ea3f41 100644 (file)
@@ -9,9 +9,6 @@
 // var $Number = global.Number;
 // var $Function = global.Function;
 // var $Array = global.Array;
-//
-// in math.js:
-// var $floor = MathFloor
 
 var $isNaN = GlobalIsNaN;
 var $isFinite = GlobalIsFinite;
@@ -35,6 +32,17 @@ function InstallFunctions(object, attributes, functions) {
 }
 
 
+function OverrideFunction(object, name, f) {
+  ObjectDefineProperty(object, name, { value: f,
+                                       writeable: true,
+                                       configurable: true,
+                                       enumerable: false });
+  %FunctionSetName(f, name);
+  %FunctionRemovePrototype(f);
+  %SetNativeFlag(f);
+}
+
+
 // Helper function to install a getter-only accessor property.
 function InstallGetter(object, name, getter) {
   %FunctionSetName(getter, name);
@@ -210,7 +218,7 @@ var DefaultObjectToString = NoSideEffectsObjectToString;
 function NoSideEffectsObjectToString() {
   if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
   if (IS_NULL(this)) return "[object Null]";
-  return "[object " + %_ClassOf(ToObject(this)) + "]";
+  return "[object " + %_ClassOf(TO_OBJECT_INLINE(this)) + "]";
 }
 
 
@@ -223,7 +231,7 @@ function ObjectToLocaleString() {
 
 // ECMA-262 - 15.2.4.4
 function ObjectValueOf() {
-  return ToObject(this);
+  return TO_OBJECT_INLINE(this);
 }
 
 
@@ -258,7 +266,7 @@ function ObjectPropertyIsEnumerable(V) {
     var desc = GetOwnPropertyJS(this, P);
     return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
   }
-  return %IsPropertyEnumerable(ToObject(this), P);
+  return %IsPropertyEnumerable(TO_OBJECT_INLINE(this), P);
 }
 
 
@@ -276,7 +284,7 @@ function ObjectDefineGetter(name, fun) {
   desc.setGet(fun);
   desc.setEnumerable(true);
   desc.setConfigurable(true);
-  DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
+  DefineOwnProperty(TO_OBJECT_INLINE(receiver), ToName(name), desc, false);
 }
 
 
@@ -285,7 +293,7 @@ function ObjectLookupGetter(name) {
   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
     receiver = %GlobalProxy(global);
   }
-  return %LookupAccessor(ToObject(receiver), ToName(name), GETTER);
+  return %LookupAccessor(TO_OBJECT_INLINE(receiver), ToName(name), GETTER);
 }
 
 
@@ -302,7 +310,7 @@ function ObjectDefineSetter(name, fun) {
   desc.setSet(fun);
   desc.setEnumerable(true);
   desc.setConfigurable(true);
-  DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
+  DefineOwnProperty(TO_OBJECT_INLINE(receiver), ToName(name), desc, false);
 }
 
 
@@ -311,12 +319,12 @@ function ObjectLookupSetter(name) {
   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
     receiver = %GlobalProxy(global);
   }
-  return %LookupAccessor(ToObject(receiver), ToName(name), SETTER);
+  return %LookupAccessor(TO_OBJECT_INLINE(receiver), ToName(name), SETTER);
 }
 
 
 function ObjectKeys(obj) {
-  obj = ToObject(obj);
+  obj = TO_OBJECT_INLINE(obj);
   if (%_IsJSProxy(obj)) {
     var handler = %GetHandler(obj);
     var names = CallTrap0(handler, "keys", DerivedKeysTrap);
@@ -633,7 +641,7 @@ function GetOwnPropertyJS(obj, v) {
   // GetOwnProperty returns an array indexed by the constants
   // defined in macros.py.
   // If p is not a property on obj undefined is returned.
-  var props = %GetOwnProperty(ToObject(obj), p);
+  var props = %GetOwnProperty(TO_OBJECT_INLINE(obj), p);
 
   return ConvertDescriptorArrayToDescriptor(props);
 }
@@ -684,9 +692,9 @@ function DefineProxyProperty(obj, p, attributes, should_throw) {
 
 // ES5 8.12.9.
 function DefineObjectProperty(obj, p, desc, should_throw) {
-  var current_array = %GetOwnProperty(ToObject(obj), ToName(p));
+  var current_array = %GetOwnProperty(obj, ToName(p));
   var current = ConvertDescriptorArrayToDescriptor(current_array);
-  var extensible = %IsExtensible(ToObject(obj));
+  var extensible = %IsExtensible(obj);
 
   // Error handling according to spec.
   // Step 3
@@ -1097,7 +1105,7 @@ function ObjectGetOwnPropertyKeys(obj, filter) {
 
 // ES5 section 15.2.3.4.
 function ObjectGetOwnPropertyNames(obj) {
-  obj = ToObject(obj);
+  obj = TO_OBJECT_INLINE(obj);
   // Special handling for proxies.
   if (%_IsJSProxy(obj)) {
     var handler = %GetHandler(obj);
@@ -1189,7 +1197,7 @@ function ObjectDefineProperties(obj, properties) {
   if (!IS_SPEC_OBJECT(obj)) {
     throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
   }
-  var props = ToObject(properties);
+  var props = TO_OBJECT_INLINE(properties);
   var names = GetOwnEnumerablePropertyNames(props);
   var descriptors = new InternalArray();
   for (var i = 0; i < names.length; i++) {
@@ -1368,7 +1376,7 @@ function ObjectIs(obj1, obj2) {
 
 // ECMA-262, Edition 6, section B.2.2.1.1
 function ObjectGetProto() {
-  return %_GetPrototype(ToObject(this));
+  return %_GetPrototype(TO_OBJECT_INLINE(this));
 }
 
 
@@ -1385,10 +1393,10 @@ function ObjectSetProto(proto) {
 function ObjectConstructor(x) {
   if (%_IsConstructCall()) {
     if (x == null) return this;
-    return ToObject(x);
+    return TO_OBJECT_INLINE(x);
   } else {
     if (x == null) return { };
-    return ToObject(x);
+    return TO_OBJECT_INLINE(x);
   }
 }
 
@@ -1514,7 +1522,7 @@ function NumberConstructor(x) {
 
 
 // ECMA-262 section 15.7.4.2.
-function NumberToString(radix) {
+function NumberToStringJS(radix) {
   // NOTE: Both Number objects and values can enter here as
   // 'this'. This is not as dictated by ECMA-262.
   var number = this;
@@ -1542,7 +1550,7 @@ function NumberToString(radix) {
 
 // ECMA-262 section 15.7.4.3
 function NumberToLocaleString() {
-  return %_CallFunction(this, NumberToString);
+  return %_CallFunction(this, NumberToStringJS);
 }
 
 
@@ -1655,8 +1663,7 @@ function NumberIsNaN(number) {
 function NumberIsSafeInteger(number) {
   if (NumberIsFinite(number)) {
     var integral = TO_INTEGER(number);
-    if (integral == number)
-      return MathAbs(integral) <= $Number.MAX_SAFE_INTEGER;
+    if (integral == number) return $abs(integral) <= $Number.MAX_SAFE_INTEGER;
   }
   return false;
 }
@@ -1695,7 +1702,7 @@ function SetUpNumber() {
 
   // Set up non-enumerable functions on the Number prototype object.
   InstallFunctions($Number.prototype, DONT_ENUM, $Array(
-    "toString", NumberToString,
+    "toString", NumberToStringJS,
     "toLocaleString", NumberToLocaleString,
     "valueOf", NumberValueOf,
     "toFixed", NumberToFixedJS,
@@ -1836,7 +1843,7 @@ function NewFunctionFromString(arguments, function_token) {
     // If the formal parameters string include ) - an illegal
     // character - it may make the combined function expression
     // compile. We avoid this problem by checking for this early on.
-    if (%_CallFunction(p, ')', StringIndexOfJS) != -1) {
+    if (%_CallFunction(p, ')', $stringIndexOf) != -1) {
       throw MakeSyntaxError('paren_in_arg_string', []);
     }
     // If the formal parameters include an unbalanced block comment, the
@@ -1879,21 +1886,11 @@ SetUpFunction();
 // ----------------------------------------------------------------------------
 // Iterator related spec functions.
 
-// ES6 rev 26, 2014-07-18
-// 7.4.1 CheckIterable ( obj )
-function ToIterable(obj) {
-  if (!IS_SPEC_OBJECT(obj)) {
-    return UNDEFINED;
-  }
-  return obj[symbolIterator];
-}
-
-
-// ES6 rev 26, 2014-07-18
-// 7.4.2 GetIterator ( obj, method )
+// ES6 rev 33, 2015-02-12
+// 7.4.1 GetIterator ( obj, method )
 function GetIterator(obj, method) {
   if (IS_UNDEFINED(method)) {
-    method = ToIterable(obj);
+    method = obj[symbolIterator];
   }
   if (!IS_SPEC_FUNCTION(method)) {
     throw MakeTypeError('not_iterable', [obj]);
index 2351e52..c0b8bd7 100644 (file)
@@ -20,6 +20,7 @@ const char* Variable::Mode2String(VariableMode mode) {
     case CONST_LEGACY: return "CONST_LEGACY";
     case LET: return "LET";
     case CONST: return "CONST";
+    case IMPORT: return "IMPORT";
     case DYNAMIC: return "DYNAMIC";
     case DYNAMIC_GLOBAL: return "DYNAMIC_GLOBAL";
     case DYNAMIC_LOCAL: return "DYNAMIC_LOCAL";
@@ -32,8 +33,7 @@ const char* Variable::Mode2String(VariableMode mode) {
 
 
 Variable::Variable(Scope* scope, const AstRawString* name, VariableMode mode,
-                   bool is_valid_ref, Kind kind,
-                   InitializationFlag initialization_flag,
+                   Kind kind, InitializationFlag initialization_flag,
                    MaybeAssignedFlag maybe_assigned_flag)
     : scope_(scope),
       name_(name),
@@ -42,8 +42,10 @@ Variable::Variable(Scope* scope, const AstRawString* name, VariableMode mode,
       location_(UNALLOCATED),
       index_(-1),
       initializer_position_(RelocInfo::kNoPosition),
+      has_strong_mode_reference_(false),
+      strong_mode_reference_start_position_(RelocInfo::kNoPosition),
+      strong_mode_reference_end_position_(RelocInfo::kNoPosition),
       local_if_not_shadowed_(NULL),
-      is_valid_ref_(is_valid_ref),
       force_context_allocation_(false),
       is_used_(false),
       initialization_flag_(initialization_flag),
index 1adeb1f..545c3bd 100644 (file)
@@ -18,7 +18,7 @@ namespace internal {
 
 class Variable: public ZoneObject {
  public:
-  enum Kind { NORMAL, THIS, NEW_TARGET, ARGUMENTS };
+  enum Kind { NORMAL, FUNCTION, THIS, NEW_TARGET, ARGUMENTS };
 
   enum Location {
     // Before and during variable allocation, a variable whose location is
@@ -47,15 +47,13 @@ class Variable: public ZoneObject {
     LOOKUP
   };
 
-  Variable(Scope* scope, const AstRawString* name, VariableMode mode,
-           bool is_valid_ref, Kind kind, InitializationFlag initialization_flag,
+  Variable(Scope* scope, const AstRawString* name, VariableMode mode, Kind kind,
+           InitializationFlag initialization_flag,
            MaybeAssignedFlag maybe_assigned_flag = kNotAssigned);
 
   // Printing support
   static const char* Mode2String(VariableMode mode);
 
-  bool IsValidReference() { return is_valid_ref_; }
-
   // 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 script scope). scope() is NULL in that case. Currently the
@@ -98,6 +96,7 @@ class Variable: public ZoneObject {
     return initialization_flag_ == kNeedsInitialization;
   }
 
+  bool is_function() const { return kind_ == FUNCTION; }
   bool is_this() const { return kind_ == THIS; }
   bool is_new_target() const { return kind_ == NEW_TARGET; }
   bool is_arguments() const { return kind_ == ARGUMENTS; }
@@ -129,6 +128,25 @@ class Variable: public ZoneObject {
 
   static int CompareIndex(Variable* const* v, Variable* const* w);
 
+  void RecordStrongModeReference(int start_position, int end_position) {
+    // Record the earliest reference to the variable. Used in error messages for
+    // strong mode references to undeclared variables.
+    if (has_strong_mode_reference_ &&
+        strong_mode_reference_start_position_ < start_position)
+      return;
+    has_strong_mode_reference_ = true;
+    strong_mode_reference_start_position_ = start_position;
+    strong_mode_reference_end_position_ = end_position;
+  }
+
+  bool has_strong_mode_reference() const { return has_strong_mode_reference_; }
+  int strong_mode_reference_start_position() const {
+    return strong_mode_reference_start_position_;
+  }
+  int strong_mode_reference_end_position() const {
+    return strong_mode_reference_end_position_;
+  }
+
  private:
   Scope* scope_;
   const AstRawString* name_;
@@ -137,6 +155,11 @@ class Variable: public ZoneObject {
   Location location_;
   int index_;
   int initializer_position_;
+  // Tracks whether the variable is bound to a VariableProxy which is in strong
+  // mode, and if yes, the source location of the reference.
+  bool has_strong_mode_reference_;
+  int strong_mode_reference_start_position_;
+  int strong_mode_reference_end_position_;
 
   // If this field is set, this variable references the stored locally bound
   // variable, but it might be shadowed by variable bindings introduced by
@@ -144,9 +167,6 @@ class Variable: public ZoneObject {
   // binding scope (exclusive).
   Variable* local_if_not_shadowed_;
 
-  // Valid as a reference? (const and this are not valid, for example)
-  bool is_valid_ref_;
-
   // Usage info.
   bool force_context_allocation_;  // set by variable resolver
   bool is_used_;
index a44c3d7..776043d 100644 (file)
@@ -20,30 +20,19 @@ function WeakMapConstructor(iterable) {
     throw MakeTypeError('constructor_not_function', ['WeakMap']);
   }
 
-  var iter, adder;
+  %WeakCollectionInitialize(this);
 
   if (!IS_NULL_OR_UNDEFINED(iterable)) {
-    iter = GetIterator(ToObject(iterable));
-    adder = this.set;
+    var adder = this.set;
     if (!IS_SPEC_FUNCTION(adder)) {
       throw MakeTypeError('property_not_function', ['set', this]);
     }
-  }
-
-  %WeakCollectionInitialize(this);
-
-  if (IS_UNDEFINED(iter)) return;
-
-  var next, done, nextItem;
-  while (!(next = iter.next()).done) {
-    if (!IS_SPEC_OBJECT(next)) {
-      throw MakeTypeError('iterator_result_not_an_object', [next]);
-    }
-    nextItem = next.value;
-    if (!IS_SPEC_OBJECT(nextItem)) {
-      throw MakeTypeError('iterator_value_not_an_object', [nextItem]);
+    for (var nextItem of iterable) {
+      if (!IS_SPEC_OBJECT(nextItem)) {
+        throw MakeTypeError('iterator_value_not_an_object', [nextItem]);
+      }
+      %_CallFunction(this, nextItem[0], nextItem[1], adder);
     }
-    %_CallFunction(this, nextItem[0], nextItem[1], adder);
   }
 }
 
@@ -53,9 +42,7 @@ function WeakMapGet(key) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['WeakMap.prototype.get', this]);
   }
-  if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) {
-    throw %MakeTypeError('invalid_weakmap_key', [this, key]);
-  }
+  if (!IS_SPEC_OBJECT(key)) return UNDEFINED;
   return %WeakCollectionGet(this, key);
 }
 
@@ -65,7 +52,7 @@ function WeakMapSet(key, value) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['WeakMap.prototype.set', this]);
   }
-  if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) {
+  if (!IS_SPEC_OBJECT(key)) {
     throw %MakeTypeError('invalid_weakmap_key', [this, key]);
   }
   return %WeakCollectionSet(this, key, value);
@@ -77,9 +64,7 @@ function WeakMapHas(key) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['WeakMap.prototype.has', this]);
   }
-  if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) {
-    throw %MakeTypeError('invalid_weakmap_key', [this, key]);
-  }
+  if (!IS_SPEC_OBJECT(key)) return false;
   return %WeakCollectionHas(this, key);
 }
 
@@ -89,9 +74,7 @@ function WeakMapDelete(key) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['WeakMap.prototype.delete', this]);
   }
-  if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) {
-    throw %MakeTypeError('invalid_weakmap_key', [this, key]);
-  }
+  if (!IS_SPEC_OBJECT(key)) return false;
   return %WeakCollectionDelete(this, key);
 }
 
@@ -127,26 +110,16 @@ function WeakSetConstructor(iterable) {
     throw MakeTypeError('constructor_not_function', ['WeakSet']);
   }
 
-  var iter, adder;
+  %WeakCollectionInitialize(this);
 
   if (!IS_NULL_OR_UNDEFINED(iterable)) {
-    iter = GetIterator(ToObject(iterable));
-    adder = this.add;
+    var adder = this.add;
     if (!IS_SPEC_FUNCTION(adder)) {
       throw MakeTypeError('property_not_function', ['add', this]);
     }
-  }
-
-  %WeakCollectionInitialize(this);
-
-  if (IS_UNDEFINED(iter)) return;
-
-  var next, done;
-  while (!(next = iter.next()).done) {
-    if (!IS_SPEC_OBJECT(next)) {
-      throw MakeTypeError('iterator_result_not_an_object', [next]);
+    for (var value of iterable) {
+      %_CallFunction(this, value, adder);
     }
-    %_CallFunction(this, next.value, adder);
   }
 }
 
@@ -156,7 +129,7 @@ function WeakSetAdd(value) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['WeakSet.prototype.add', this]);
   }
-  if (!(IS_SPEC_OBJECT(value) || IS_SYMBOL(value))) {
+  if (!IS_SPEC_OBJECT(value)) {
     throw %MakeTypeError('invalid_weakset_value', [this, value]);
   }
   return %WeakCollectionSet(this, value, true);
@@ -168,9 +141,7 @@ function WeakSetHas(value) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['WeakSet.prototype.has', this]);
   }
-  if (!(IS_SPEC_OBJECT(value) || IS_SYMBOL(value))) {
-    throw %MakeTypeError('invalid_weakset_value', [this, value]);
-  }
+  if (!IS_SPEC_OBJECT(value)) return false;
   return %WeakCollectionHas(this, value);
 }
 
@@ -180,9 +151,7 @@ function WeakSetDelete(value) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['WeakSet.prototype.delete', this]);
   }
-  if (!(IS_SPEC_OBJECT(value) || IS_SYMBOL(value))) {
-    throw %MakeTypeError('invalid_weakset_value', [this, value]);
-  }
+  if (!IS_SPEC_OBJECT(value)) return false;
   return %WeakCollectionDelete(this, value);
 }
 
index 64c71cf..df0c7d2 100644 (file)
@@ -265,6 +265,12 @@ void Assembler::set_target_address_at(Address pc,
 }
 
 
+void Assembler::deserialization_set_target_internal_reference_at(
+    Address pc, Address target, RelocInfo::Mode mode) {
+  Memory::Address_at(pc) = target;
+}
+
+
 Address Assembler::target_address_from_return_address(Address pc) {
   return pc - kCallTargetAddressOffset;
 }
@@ -366,12 +372,24 @@ Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
 }
 
 
-Address RelocInfo::target_reference() {
+Address RelocInfo::target_external_reference() {
   DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
   return Memory::Address_at(pc_);
 }
 
 
+Address RelocInfo::target_internal_reference() {
+  DCHECK(rmode_ == INTERNAL_REFERENCE);
+  return Memory::Address_at(pc_);
+}
+
+
+Address RelocInfo::target_internal_reference_address() {
+  DCHECK(rmode_ == INTERNAL_REFERENCE);
+  return reinterpret_cast<Address>(pc_);
+}
+
+
 void RelocInfo::set_target_object(Object* target,
                                   WriteBarrierMode write_barrier_mode,
                                   ICacheFlushMode icache_flush_mode) {
@@ -438,7 +456,8 @@ void RelocInfo::set_target_cell(Cell* cell,
 
 
 void RelocInfo::WipeOut() {
-  if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_)) {
+  if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
+      IsInternalReference(rmode_)) {
     Memory::Address_at(pc_) = NULL;
   } else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
     // Effectively write zero into the relocation.
@@ -542,7 +561,8 @@ void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
     visitor->VisitCell(this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     visitor->VisitExternalReference(this);
-    CpuFeatures::FlushICache(pc_, sizeof(Address));
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
+    visitor->VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     visitor->VisitCodeAgeSequence(this);
   } else if (((RelocInfo::IsJSReturn(mode) &&
@@ -569,7 +589,8 @@ void RelocInfo::Visit(Heap* heap) {
     StaticVisitor::VisitCell(heap, this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     StaticVisitor::VisitExternalReference(this);
-    CpuFeatures::FlushICache(pc_, sizeof(Address));
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
+    StaticVisitor::VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     StaticVisitor::VisitCodeAgeSequence(heap, this);
   } else if (heap->isolate()->debug()->has_break_points() &&
index dcfa01f..abdf7a5 100644 (file)
@@ -108,60 +108,16 @@ void CpuFeatures::PrintFeatures() {
 
 
 // -----------------------------------------------------------------------------
-// Implementation of RelocInfo
-
-// Patch the code at the current PC with a call to the target address.
-// Additional guard int3 instructions can be added if required.
-void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
-  int code_size = Assembler::kCallSequenceLength + guard_bytes;
-
-  // Create a code patcher.
-  CodePatcher patcher(pc_, code_size);
-
-  // Add a label for checking the size of the code used for returning.
-#ifdef DEBUG
-  Label check_codesize;
-  patcher.masm()->bind(&check_codesize);
-#endif
-
-  // Patch the code.
-  patcher.masm()->movp(kScratchRegister, reinterpret_cast<void*>(target),
-                       Assembler::RelocInfoNone());
-  patcher.masm()->call(kScratchRegister);
-
-  // Check that the size of the code generated is as expected.
-  DCHECK_EQ(Assembler::kCallSequenceLength,
-            patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
-
-  // Add the requested number of int3 instructions after the call.
-  for (int i = 0; i < guard_bytes; i++) {
-    patcher.masm()->int3();
-  }
-}
-
-
-void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
-  // Patch the code at the current address with the supplied instructions.
-  for (int i = 0; i < instruction_count; i++) {
-    *(pc_ + i) = *(instructions + i);
-  }
-
-  // Indicate that code has changed.
-  CpuFeatures::FlushICache(pc_, instruction_count);
-}
-
-
-// -----------------------------------------------------------------------------
 // Register constants.
 
 const int
     Register::kRegisterCodeByAllocationIndex[kMaxNumAllocatableRegisters] = {
-  // rax, rbx, rdx, rcx, rsi, rdi, r8, r9, r11, r14, r15
-  0, 3, 2, 1, 6, 7, 8, 9, 11, 14, 15
+  // rax, rbx, rdx, rcx, rsi, rdi, r8, r9, r11, r12, r14, r15
+  0, 3, 2, 1, 6, 7, 8, 9, 11, 12, 14, 15
 };
 
 const int Register::kAllocationIndexByRegisterCode[kNumRegisters] = {
-  0, 3, 2, 1, -1, -1, 4, 5, 6, 7, -1, 8, -1, -1, 9, 10
+  0, 3, 2, 1, -1, -1, 4, 5, 6, 7, -1, 8, 9, -1, 10, 11
 };
 
 
@@ -786,6 +742,15 @@ void Assembler::bsrl(Register dst, Register src) {
 }
 
 
+void Assembler::bsrl(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0xBD);
+  emit_operand(dst, src);
+}
+
+
 void Assembler::call(Label* L) {
   positions_recorder()->WriteRecordedPositions();
   EnsureSpace ensure_space(this);
@@ -2573,6 +2538,16 @@ void Assembler::movd(XMMRegister dst, Register src) {
 }
 
 
+void Assembler::movd(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x6E);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::movd(Register dst, XMMRegister src) {
   EnsureSpace ensure_space(this);
   emit(0x66);
@@ -2676,6 +2651,45 @@ void Assembler::extractps(Register dst, XMMRegister src, byte imm8) {
 }
 
 
+void Assembler::pextrd(Register dst, XMMRegister src, int8_t imm8) {
+  DCHECK(IsEnabled(SSE4_1));
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(src, dst);
+  emit(0x0F);
+  emit(0x3A);
+  emit(0x16);
+  emit_sse_operand(src, dst);
+  emit(imm8);
+}
+
+
+void Assembler::pinsrd(XMMRegister dst, Register src, int8_t imm8) {
+  DCHECK(IsEnabled(SSE4_1));
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x3A);
+  emit(0x22);
+  emit_sse_operand(dst, src);
+  emit(imm8);
+}
+
+
+void Assembler::pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) {
+  DCHECK(IsEnabled(SSE4_1));
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x3A);
+  emit(0x22);
+  emit_sse_operand(dst, src);
+  emit(imm8);
+}
+
+
 void Assembler::movsd(const Operand& dst, XMMRegister src) {
   EnsureSpace ensure_space(this);
   emit(0xF2);  // double
@@ -3246,8 +3260,7 @@ void Assembler::cmpltsd(XMMRegister dst, XMMRegister src) {
 }
 
 
-void Assembler::roundsd(XMMRegister dst, XMMRegister src,
-                        Assembler::RoundingMode mode) {
+void Assembler::roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode) {
   DCHECK(IsEnabled(SSE4_1));
   EnsureSpace ensure_space(this);
   emit(0x66);
@@ -3290,6 +3303,66 @@ void Assembler::pcmpeqd(XMMRegister dst, XMMRegister src) {
 }
 
 
+void Assembler::punpckldq(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x62);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::punpckhdq(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x6A);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::maxsd(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF2);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5F);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::maxsd(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF2);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5F);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::minsd(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF2);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5D);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::minsd(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF2);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5D);
+  emit_sse_operand(dst, src);
+}
+
+
 // AVX instructions
 void Assembler::vfmasd(byte op, XMMRegister dst, XMMRegister src1,
                        XMMRegister src2) {
index 116816c..cfb89c8 100644 (file)
@@ -40,7 +40,7 @@
 #include <deque>
 
 #include "src/assembler.h"
-#include "src/serialize.h"
+#include "src/compiler.h"
 
 namespace v8 {
 namespace internal {
@@ -74,9 +74,8 @@ struct Register {
   //  rsp - stack pointer
   //  rbp - frame pointer
   //  r10 - fixed scratch register
-  //  r12 - smi constant register
   //  r13 - root register
-  static const int kMaxNumAllocatableRegisters = 11;
+  static const int kMaxNumAllocatableRegisters = 12;
   static int NumAllocatableRegisters() {
     return kMaxNumAllocatableRegisters;
   }
@@ -104,6 +103,7 @@ struct Register {
       "r8",
       "r9",
       "r11",
+      "r12",
       "r14",
       "r15"
     };
@@ -359,6 +359,14 @@ inline Condition CommuteCondition(Condition cc) {
 }
 
 
+enum RoundingMode {
+  kRoundToNearest = 0x0,
+  kRoundDown = 0x1,
+  kRoundUp = 0x2,
+  kRoundToZero = 0x3
+};
+
+
 // -----------------------------------------------------------------------------
 // Machine instruction Immediates
 
@@ -561,6 +569,11 @@ class Assembler : public AssemblerBase {
     set_target_address_at(instruction_payload, code, target);
   }
 
+  // This sets the internal reference at the pc.
+  inline static void deserialization_set_target_internal_reference_at(
+      Address pc, Address target,
+      RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
+
   static inline RelocInfo::Mode RelocInfoNone() {
     if (kPointerSize == kInt64Size) {
       return RelocInfo::NONE64;
@@ -886,6 +899,7 @@ class Assembler : public AssemblerBase {
   void bt(const Operand& dst, Register src);
   void bts(const Operand& dst, Register src);
   void bsrl(Register dst, Register src);
+  void bsrl(Register dst, const Operand& src);
 
   // Miscellaneous
   void clc();
@@ -1063,6 +1077,7 @@ class Assembler : public AssemblerBase {
 
   // SSE2 instructions
   void movd(XMMRegister dst, Register src);
+  void movd(XMMRegister dst, const Operand& src);
   void movd(Register dst, XMMRegister src);
   void movq(XMMRegister dst, Register src);
   void movq(Register dst, XMMRegister src);
@@ -1131,15 +1146,21 @@ class Assembler : public AssemblerBase {
 
   void movmskpd(Register dst, XMMRegister src);
 
+  void punpckldq(XMMRegister dst, XMMRegister src);
+  void punpckhdq(XMMRegister dst, XMMRegister src);
+
+  void maxsd(XMMRegister dst, XMMRegister src);
+  void maxsd(XMMRegister dst, const Operand& src);
+  void minsd(XMMRegister dst, XMMRegister src);
+  void minsd(XMMRegister dst, const Operand& src);
+
   // SSE 4.1 instruction
   void extractps(Register dst, XMMRegister src, byte imm8);
 
-  enum RoundingMode {
-    kRoundToNearest = 0x0,
-    kRoundDown      = 0x1,
-    kRoundUp        = 0x2,
-    kRoundToZero    = 0x3
-  };
+  void pextrd(Register dst, XMMRegister src, int8_t imm8);
+
+  void pinsrd(XMMRegister dst, Register src, int8_t imm8);
+  void pinsrd(XMMRegister dst, const Operand& src, int8_t imm8);
 
   void roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode);
 
@@ -1318,6 +1339,18 @@ class Assembler : public AssemblerBase {
   void vdivsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
     vsd(0x5e, dst, src1, src2);
   }
+  void vmaxsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vsd(0x5f, dst, src1, src2);
+  }
+  void vmaxsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vsd(0x5f, dst, src1, src2);
+  }
+  void vminsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vsd(0x5d, dst, src1, src2);
+  }
+  void vminsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vsd(0x5d, dst, src1, src2);
+  }
   void vsd(byte op, XMMRegister dst, XMMRegister src1, XMMRegister src2);
   void vsd(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);
 
@@ -1341,7 +1374,7 @@ class Assembler : public AssemblerBase {
 
   // Record a deoptimization reason that can be used by a log or cpu profiler.
   // Use --trace-deopt to enable.
-  void RecordDeoptReason(const int reason, const int raw_position);
+  void RecordDeoptReason(const int reason, const SourcePosition position);
 
   // Allocate a constant pool of the correct size for the generated code.
   Handle<ConstantPoolArray> NewConstantPool(Isolate* isolate);
index f43084b..3141c17 100644 (file)
@@ -1051,7 +1051,87 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
 }
 
 
-void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+static void Generate_CheckStackOverflow(MacroAssembler* masm,
+                                        const int calleeOffset) {
+  // rax   : the number of items to be pushed to the stack
+  //
+  // 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(kScratchRegister, Heap::kRealStackLimitRootIndex);
+  __ movp(rcx, rsp);
+  // Make rcx the space we have left. The stack might already be overflowed
+  // here which will cause rcx to become negative.
+  __ subp(rcx, kScratchRegister);
+  // Make rdx the space we need for the array when it is unrolled onto the
+  // stack.
+  __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rax, kPointerSizeLog2);
+  // Check if the arguments will overflow the stack.
+  __ cmpp(rcx, rdx);
+  __ j(greater, &okay);  // Signed comparison.
+
+  // Out of stack space.
+  __ Push(Operand(rbp, calleeOffset));
+  __ Push(rax);
+  __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+
+  __ bind(&okay);
+}
+
+
+static void Generate_PushAppliedArguments(MacroAssembler* masm,
+                                          const int argumentsOffset,
+                                          const int indexOffset,
+                                          const int limitOffset) {
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register key = LoadDescriptor::NameRegister();
+
+  // Copy all arguments from the array to the stack.
+  Label entry, loop;
+  __ movp(key, Operand(rbp, indexOffset));
+  __ jmp(&entry);
+  __ bind(&loop);
+  __ movp(receiver, Operand(rbp, argumentsOffset));  // load arguments
+
+  // Use inline caching to speed up access to arguments.
+  if (FLAG_vector_ics) {
+    // 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.
+  }
+
+  // Push the nth argument.
+  __ Push(rax);
+
+  // Update the index on the stack and in register key.
+  __ movp(key, Operand(rbp, indexOffset));
+  __ SmiAddConstant(key, key, Smi::FromInt(1));
+  __ movp(Operand(rbp, indexOffset), key);
+
+  __ bind(&entry);
+  __ cmpp(key, Operand(rbp, limitOffset));
+  __ j(not_equal, &loop);
+
+  // On exit, the pushed arguments count is in rax, untagged
+  __ SmiToInteger64(rax, key);
+}
+
+
+// Used by FunctionApply and ReflectApply
+static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
+  const int kFormalParameters = targetIsArgument ? 3 : 2;
+  const int kStackSize = kFormalParameters + 1;
+
   // Stack at entry:
   // rsp     : return address
   // rsp[8]  : arguments
@@ -1071,30 +1151,13 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
 
     __ Push(Operand(rbp, kFunctionOffset));
     __ Push(Operand(rbp, kArgumentsOffset));
-    __ 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(kScratchRegister, Heap::kRealStackLimitRootIndex);
-    __ movp(rcx, rsp);
-    // Make rcx the space we have left. The stack might already be overflowed
-    // here which will cause rcx to become negative.
-    __ subp(rcx, kScratchRegister);
-    // Make rdx the space we need for the array when it is unrolled onto the
-    // stack.
-    __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rax, kPointerSizeLog2);
-    // Check if the arguments will overflow the stack.
-    __ cmpp(rcx, rdx);
-    __ j(greater, &okay);  // Signed comparison.
-
-    // Out of stack space.
-    __ Push(Operand(rbp, kFunctionOffset));
-    __ Push(rax);
-    __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
-    __ bind(&okay);
-    // End of stack check.
+    if (targetIsArgument) {
+      __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION);
+    } else {
+      __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
+    }
+
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
 
     // Push current index and limit.
     const int kLimitOffset =
@@ -1156,54 +1219,20 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
     __ bind(&push_receiver);
     __ Push(rbx);
 
-    // Copy all arguments from the array to the stack.
-    Label entry, loop;
-    Register receiver = LoadDescriptor::ReceiverRegister();
-    Register key = LoadDescriptor::NameRegister();
-    __ movp(key, Operand(rbp, kIndexOffset));
-    __ jmp(&entry);
-    __ bind(&loop);
-    __ movp(receiver, Operand(rbp, kArgumentsOffset));  // load arguments
-
-    // Use inline caching to speed up access to arguments.
-    if (FLAG_vector_ics) {
-      // 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.
-    }
-
-    // Push the nth argument.
-    __ Push(rax);
-
-    // Update the index on the stack and in register key.
-    __ movp(key, Operand(rbp, kIndexOffset));
-    __ SmiAddConstant(key, key, Smi::FromInt(1));
-    __ movp(Operand(rbp, kIndexOffset), key);
-
-    __ bind(&entry);
-    __ cmpp(key, Operand(rbp, kLimitOffset));
-    __ j(not_equal, &loop);
+    // Loop over the arguments array, pushing each value to the stack
+    Generate_PushAppliedArguments(
+        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
 
     // Call the function.
     Label call_proxy;
     ParameterCount actual(rax);
-    __ SmiToInteger32(rax, key);
     __ movp(rdi, Operand(rbp, kFunctionOffset));
     __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
     __ j(not_equal, &call_proxy);
     __ InvokeFunction(rdi, actual, CALL_FUNCTION, NullCallWrapper());
 
     frame_scope.GenerateLeaveFrame();
-    __ ret(3 * kPointerSize);  // remove this, receiver, and arguments
+    __ ret(kStackSize * kPointerSize);  // remove this, receiver, and arguments
 
     // Call the function proxy.
     __ bind(&call_proxy);
@@ -1216,7 +1245,92 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
 
     // Leave internal frame.
   }
-  __ ret(3 * kPointerSize);  // remove this, receiver, and arguments
+  __ ret(kStackSize * kPointerSize);  // remove this, receiver, and arguments
+}
+
+
+// Used by ReflectConstruct
+static void Generate_ConstructHelper(MacroAssembler* masm) {
+  const int kFormalParameters = 3;
+  const int kStackSize = kFormalParameters + 1;
+
+  // Stack at entry:
+  // rsp     : return address
+  // rsp[8]  : original constructor (new.target)
+  // rsp[16] : arguments
+  // rsp[24] : constructor
+  {
+    FrameScope frame_scope(masm, StackFrame::INTERNAL);
+    // Stack frame:
+    // rbp     : Old base pointer
+    // rbp[8]  : return address
+    // rbp[16] : original constructor (new.target)
+    // rbp[24] : arguments
+    // rbp[32] : constructor
+    static const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize;
+    static const int kArgumentsOffset = kNewTargetOffset + kPointerSize;
+    static const int kFunctionOffset = kArgumentsOffset + kPointerSize;
+
+    // If newTarget is not supplied, set it to constructor
+    Label validate_arguments;
+    __ movp(rax, Operand(rbp, kNewTargetOffset));
+    __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
+    __ j(not_equal, &validate_arguments, Label::kNear);
+    __ movp(rax, Operand(rbp, kFunctionOffset));
+    __ movp(Operand(rbp, kNewTargetOffset), rax);
+
+    // Validate arguments
+    __ bind(&validate_arguments);
+    __ Push(Operand(rbp, kFunctionOffset));
+    __ Push(Operand(rbp, kArgumentsOffset));
+    __ Push(Operand(rbp, kNewTargetOffset));
+    __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION);
+
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
+
+    // Push current index and limit.
+    const int kLimitOffset =
+        StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
+    const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
+    __ Push(rax);  // limit
+    __ Push(Immediate(0));  // index
+    // Push newTarget and callee functions
+    __ Push(Operand(rbp, kNewTargetOffset));
+    __ Push(Operand(rbp, kFunctionOffset));
+
+    // Loop over the arguments array, pushing each value to the stack
+    Generate_PushAppliedArguments(
+        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
+
+    // Use undefined feedback vector
+    __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
+    __ movp(rdi, Operand(rbp, kFunctionOffset));
+
+    // Call the function.
+    CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
+    __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
+
+    __ Drop(1);
+
+    // Leave internal frame.
+  }
+  // remove this, target, arguments and newTarget
+  __ ret(kStackSize * kPointerSize);
+}
+
+
+void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+  Generate_ApplyHelper(masm, false);
+}
+
+
+void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
+  Generate_ApplyHelper(masm, true);
+}
+
+
+void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
+  Generate_ConstructHelper(masm);
 }
 
 
index 2a28767..6ca81fe 100644 (file)
@@ -11,6 +11,7 @@
 #include "src/codegen.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
@@ -929,7 +930,7 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
   __ ret(0);
 
   StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
+  char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&miss);
   PropertyAccessCompiler::TailCallBuiltin(
@@ -961,10 +962,17 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
   __ movp(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset));
 
   if (has_new_target()) {
+    // If the constructor was [[Call]]ed, the call will not push a new.target
+    // onto the stack. In that case the arguments array we construct is bogus,
+    // bu we do not care as the constructor throws immediately.
+    __ Cmp(rcx, Smi::FromInt(0));
+    Label skip_decrement;
+    __ j(equal, &skip_decrement);
     // Subtract 1 from smi-tagged arguments count.
     __ SmiToInteger32(rcx, rcx);
     __ decl(rcx);
     __ Integer32ToSmi(rcx, rcx);
+    __ bind(&skip_decrement);
   }
   __ movp(args.GetArgumentOperand(2), rcx);
   __ SmiToInteger64(rcx, rcx);
@@ -1048,7 +1056,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   // 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);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 #else  // V8_INTERPRETED_REGEXP
 
   // Stack frame on entry.
@@ -1429,19 +1437,13 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
   __ cmpp(rax, rdx);
   __ j(equal, &runtime);
-  __ movp(pending_exception_operand, rdx);
 
-  __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex);
-  Label termination_exception;
-  __ j(equal, &termination_exception, Label::kNear);
-  __ Throw(rax);
-
-  __ bind(&termination_exception);
-  __ ThrowUncatchable(rax);
+  // For exception, throw the exception again.
+  __ TailCallRuntime(Runtime::kRegExpExecReThrow, 4, 1);
 
   // Do the runtime call to execute the regexp.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 
   // Deferred code for string handling.
   // (7) Not a long external string?  If yes, go to (10).
@@ -2427,14 +2429,13 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   __ CompareRoot(rax, Heap::kExceptionRootIndex);
   __ j(equal, &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;
     __ LoadRoot(r14, Heap::kTheHoleValueRootIndex);
+    ExternalReference pending_exception_address(
+        Isolate::kPendingExceptionAddress, isolate());
     Operand pending_exception_operand =
         masm->ExternalOperand(pending_exception_address);
     __ cmpp(r14, pending_exception_operand);
@@ -2450,26 +2451,47 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // Handling of exception.
   __ bind(&exception_returned);
 
-  // Retrieve the pending exception.
-  Operand pending_exception_operand =
-      masm->ExternalOperand(pending_exception_address);
-  __ movp(rax, pending_exception_operand);
-
-  // Clear the pending exception.
-  __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
-  __ movp(pending_exception_operand, rdx);
-
-  // Special handling of termination exceptions which are uncatchable
-  // by javascript code.
-  Label throw_termination_exception;
-  __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex);
-  __ j(equal, &throw_termination_exception);
-
-  // Handle normal exception.
-  __ Throw(rax);
+  ExternalReference pending_handler_context_address(
+      Isolate::kPendingHandlerContextAddress, isolate());
+  ExternalReference pending_handler_code_address(
+      Isolate::kPendingHandlerCodeAddress, isolate());
+  ExternalReference pending_handler_offset_address(
+      Isolate::kPendingHandlerOffsetAddress, isolate());
+  ExternalReference pending_handler_fp_address(
+      Isolate::kPendingHandlerFPAddress, isolate());
+  ExternalReference pending_handler_sp_address(
+      Isolate::kPendingHandlerSPAddress, isolate());
+
+  // Ask the runtime for help to determine the handler. This will set rax to
+  // contain the current pending exception, don't clobber it.
+  ExternalReference find_handler(Runtime::kFindExceptionHandler, isolate());
+  {
+    FrameScope scope(masm, StackFrame::MANUAL);
+    __ movp(arg_reg_1, Immediate(0));  // argc.
+    __ movp(arg_reg_2, Immediate(0));  // argv.
+    __ Move(arg_reg_3, ExternalReference::isolate_address(isolate()));
+    __ PrepareCallCFunction(3);
+    __ CallCFunction(find_handler, 3);
+  }
 
-  __ bind(&throw_termination_exception);
-  __ ThrowUncatchable(rax);
+  // Retrieve the handler context, SP and FP.
+  __ movp(rsi, masm->ExternalOperand(pending_handler_context_address));
+  __ movp(rsp, masm->ExternalOperand(pending_handler_sp_address));
+  __ movp(rbp, masm->ExternalOperand(pending_handler_fp_address));
+
+  // If the handler is a JS frame, restore the context to the frame. Note that
+  // the context will be set to (rsi == 0) for non-JS frames.
+  Label skip;
+  __ testp(rsi, rsi);
+  __ j(zero, &skip, Label::kNear);
+  __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
+  __ bind(&skip);
+
+  // Compute the handler entry address and jump to it.
+  __ movp(rdi, masm->ExternalOperand(pending_handler_code_address));
+  __ movp(rdx, masm->ExternalOperand(pending_handler_offset_address));
+  __ leap(rdi, FieldOperand(rdi, rdx, times_1, Code::kHeaderSize));
+  __ jmp(rdi);
 }
 
 
@@ -2521,7 +2543,6 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
 
     // Set up the roots and smi constant registers.
     // Needs to be done before any further smi loads.
-    __ InitializeSmiConstantRegister();
     __ InitializeRootRegister();
   }
 
@@ -2559,10 +2580,9 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ LoadRoot(rax, Heap::kExceptionRootIndex);
   __ jmp(&exit);
 
-  // Invoke: Link this frame into the handler chain.  There's only one
-  // handler block in this code object, so its index is 0.
+  // Invoke: Link this frame into the handler chain.
   __ bind(&invoke);
-  __ PushTryHandler(StackHandler::JS_ENTRY, 0);
+  __ PushStackHandler();
 
   // Clear any pending exceptions.
   __ LoadRoot(rax, Heap::kTheHoleValueRootIndex);
@@ -2588,7 +2608,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ call(kScratchRegister);
 
   // Unlink this frame from the handler chain.
-  __ PopTryHandler();
+  __ PopStackHandler();
 
   __ bind(&exit);
   // Check if the current stack frame is marked as the outermost JS frame.
@@ -2884,7 +2904,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
 
 
 void StringCharCodeAtGenerator::GenerateSlow(
-    MacroAssembler* masm,
+    MacroAssembler* masm, EmbedMode embed_mode,
     const RuntimeCallHelper& call_helper) {
   __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
 
@@ -2897,6 +2917,10 @@ void StringCharCodeAtGenerator::GenerateSlow(
               index_not_number_,
               DONT_DO_SMI_CHECK);
   call_helper.BeforeCall(masm);
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ Push(VectorLoadICDescriptor::VectorRegister());
+    __ Push(VectorLoadICDescriptor::SlotRegister());
+  }
   __ Push(object_);
   __ Push(index_);  // Consumed by runtime conversion function.
   if (index_flags_ == STRING_INDEX_IS_NUMBER) {
@@ -2912,6 +2936,10 @@ void StringCharCodeAtGenerator::GenerateSlow(
     __ movp(index_, rax);
   }
   __ Pop(object_);
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ Pop(VectorLoadICDescriptor::SlotRegister());
+    __ Pop(VectorLoadICDescriptor::VectorRegister());
+  }
   // Reload the instance type.
   __ movp(result_, FieldOperand(object_, HeapObject::kMapOffset));
   __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
@@ -3214,7 +3242,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
 
   // Just jump to runtime to create the sub string.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kSubString, 3, 1);
+  __ TailCallRuntime(Runtime::kSubStringRT, 3, 1);
 
   __ bind(&single_char);
   // rax: string
@@ -3451,7 +3479,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
   // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
   // tagged as a small integer.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+  __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
 }
 
 
@@ -3749,7 +3777,7 @@ void CompareICStub::GenerateStrings(MacroAssembler* masm) {
   if (equality) {
     __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
   } else {
-    __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+    __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
   }
 
   __ bind(&miss);
@@ -4316,15 +4344,228 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
 
 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorLoadStub stub(isolate(), state());
-  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawLoadStub stub(isolate(), state());
+  stub.GenerateForTrampoline(masm);
 }
 
 
 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorKeyedLoadStub stub(isolate());
-  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawKeyedLoadStub stub(isolate());
+  stub.GenerateForTrampoline(masm);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+                             Register key, Register vector, Register slot,
+                             Register feedback, Register scratch1,
+                             Register scratch2, Register scratch3,
+                             Register scratch4, bool is_polymorphic,
+                             Label* miss) {
+  // feedback initially contains the feedback array
+  Label next_loop, prepare_next;
+  Label load_smi_map, compare_map;
+  Label start_polymorphic;
+
+  Register receiver_map = scratch1;
+  Register counter = scratch2;
+  Register length = scratch3;
+  Register cached_map = scratch4;
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &load_smi_map);
+  __ movp(receiver_map, FieldOperand(receiver, 0));
+  __ bind(&compare_map);
+  __ movp(cached_map, FieldOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+  __ cmpp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
+  __ j(not_equal, &start_polymorphic);
+
+  // found, now call handler.
+  Register handler = feedback;
+  __ movp(handler, FieldOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+  __ leap(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+
+  // Polymorphic, we have to loop from 2 to N
+  __ bind(&start_polymorphic);
+  __ SmiToInteger32(length, FieldOperand(feedback, FixedArray::kLengthOffset));
+  if (!is_polymorphic) {
+    // If the IC could be monomorphic we have to make sure we don't go past the
+    // end of the feedback array.
+    __ cmpl(length, Immediate(2));
+    __ j(equal, miss);
+  }
+  __ movl(counter, Immediate(2));
+
+  __ bind(&next_loop);
+  __ movp(cached_map, FieldOperand(feedback, counter, times_pointer_size,
+                                   FixedArray::kHeaderSize));
+  __ cmpp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
+  __ j(not_equal, &prepare_next);
+  __ movp(handler, FieldOperand(feedback, counter, times_pointer_size,
+                                FixedArray::kHeaderSize + kPointerSize));
+  __ leap(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+
+  __ bind(&prepare_next);
+  __ addl(counter, Immediate(2));
+  __ cmpl(counter, length);
+  __ j(less, &next_loop);
+
+  // We exhausted our array of map handler pairs.
+  __ jmp(miss);
+
+  __ bind(&load_smi_map);
+  __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
+  __ jmp(&compare_map);
+}
+
+
+static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+                                  Register key, Register vector, Register slot,
+                                  Register weak_cell, Register integer_slot,
+                                  Label* miss) {
+  // feedback initially contains the feedback array
+  Label compare_smi_map;
+
+  // Move the weak map into the weak_cell register.
+  Register ic_map = weak_cell;
+  __ movp(ic_map, FieldOperand(weak_cell, WeakCell::kValueOffset));
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &compare_smi_map);
+  __ cmpp(ic_map, FieldOperand(receiver, 0));
+  __ j(not_equal, miss);
+  Register handler = weak_cell;
+  __ movp(handler, FieldOperand(vector, integer_slot, times_pointer_size,
+                                FixedArray::kHeaderSize + kPointerSize));
+  __ leap(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+
+  // In microbenchmarks, it made sense to unroll this code so that the call to
+  // the handler is duplicated for a HeapObject receiver and a Smi receiver.
+  __ bind(&compare_smi_map);
+  __ CompareRoot(ic_map, Heap::kHeapNumberMapRootIndex);
+  __ j(not_equal, miss);
+  __ movp(handler, FieldOperand(vector, integer_slot, times_pointer_size,
+                                FixedArray::kHeaderSize + kPointerSize));
+  __ leap(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+}
+
+
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // rdx
+  Register name = VectorLoadICDescriptor::NameRegister();          // rcx
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // rbx
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // rax
+  Register feedback = rdi;
+  Register integer_slot = r8;
+
+  __ SmiToInteger32(integer_slot, slot);
+  __ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
+                                 FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ CompareRoot(FieldOperand(feedback, 0), Heap::kWeakCellMapRootIndex);
+  __ j(not_equal, &try_array);
+  HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback,
+                        integer_slot, &miss);
+
+  // Is it a fixed array?
+  __ bind(&try_array);
+  __ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
+  __ j(not_equal, &not_array);
+  HandleArrayCases(masm, receiver, name, vector, slot, feedback, integer_slot,
+                   r9, r11, r15, true, &miss);
+
+  __ bind(&not_array);
+  __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+  __ j(not_equal, &miss);
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::LOAD_IC, code_flags, false, receiver, name, feedback, no_reg);
+
+  __ bind(&miss);
+  LoadIC::GenerateMiss(masm);
+}
+
+
+void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // rdx
+  Register key = VectorLoadICDescriptor::NameRegister();           // rcx
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // rbx
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // rax
+  Register feedback = rdi;
+  Register integer_slot = r8;
+
+  __ SmiToInteger32(integer_slot, slot);
+  __ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
+                                 FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ CompareRoot(FieldOperand(feedback, 0), Heap::kWeakCellMapRootIndex);
+  __ j(not_equal, &try_array);
+  HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback,
+                        integer_slot, &miss);
+
+  __ bind(&try_array);
+  // Is it a fixed array?
+  __ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
+  __ j(not_equal, &not_array);
+
+  // We have a polymorphic element handler.
+  Label polymorphic, try_poly_name;
+  __ bind(&polymorphic);
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, integer_slot,
+                   r9, r11, r15, true, &miss);
+
+  __ bind(&not_array);
+  // Is it generic?
+  __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+  __ j(not_equal, &try_poly_name);
+  Handle<Code> megamorphic_stub =
+      KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+  __ jmp(megamorphic_stub, RelocInfo::CODE_TARGET);
+
+  __ bind(&try_poly_name);
+  // We might have a name in feedback, and a fixed array in the next slot.
+  __ cmpp(key, feedback);
+  __ j(not_equal, &miss);
+  // If the name comparison succeeded, we know we have a fixed array with
+  // at least one map/handler pair.
+  __ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
+                                 FixedArray::kHeaderSize + kPointerSize));
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, integer_slot,
+                   r9, r11, r15, false, &miss);
+
+  __ bind(&miss);
+  KeyedLoadIC::GenerateMiss(masm);
 }
 
 
@@ -4761,7 +5002,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
                                      Operand* context_restore_operand) {
   Label prologue;
   Label promote_scheduled_exception;
-  Label exception_handled;
   Label delete_allocated_handles;
   Label leave_exit_frame;
   Label write_back;
@@ -4838,13 +5078,22 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
   __ movp(Operand(base_reg, kNextOffset), prev_next_address_reg);
   __ cmpp(prev_limit_reg, Operand(base_reg, kLimitOffset));
   __ j(not_equal, &delete_allocated_handles);
+
+  // Leave the API exit frame.
   __ bind(&leave_exit_frame);
+  bool restore_context = context_restore_operand != NULL;
+  if (restore_context) {
+    __ movp(rsi, *context_restore_operand);
+  }
+  if (stack_space_operand != nullptr) {
+    __ movp(rbx, *stack_space_operand);
+  }
+  __ LeaveApiExitFrame(!restore_context);
 
   // Check if the function scheduled an exception.
-  __ Move(rsi, scheduled_exception_address);
-  __ Cmp(Operand(rsi, 0), factory->the_hole_value());
+  __ Move(rdi, scheduled_exception_address);
+  __ Cmp(Operand(rdi, 0), factory->the_hole_value());
   __ j(not_equal, &promote_scheduled_exception);
-  __ bind(&exception_handled);
 
 #if DEBUG
   // Check if the function returned a valid JavaScript value.
@@ -4881,14 +5130,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
   __ bind(&ok);
 #endif
 
-  bool restore_context = context_restore_operand != NULL;
-  if (restore_context) {
-    __ movp(rsi, *context_restore_operand);
-  }
-  if (stack_space_operand != nullptr) {
-    __ movp(rbx, *stack_space_operand);
-  }
-  __ LeaveApiExitFrame(!restore_context);
   if (stack_space_operand != nullptr) {
     DCHECK_EQ(stack_space, 0);
     __ PopReturnAddressTo(rcx);
@@ -4898,12 +5139,9 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
     __ ret(stack_space * kPointerSize);
   }
 
+  // Re-throw by promoting a scheduled exception.
   __ bind(&promote_scheduled_exception);
-  {
-    FrameScope frame(masm, StackFrame::INTERNAL);
-    __ CallRuntime(Runtime::kPromoteScheduledException, 0);
-  }
-  __ jmp(&exception_handled);
+  __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
 
   // HandleScope limit has changed. Delete allocated extensions.
   __ bind(&delete_allocated_handles);
index c8f9456..ee2b5c5 100644 (file)
 namespace v8 {
 namespace internal {
 
-bool BreakLocationIterator::IsDebugBreakAtReturn()  {
-  return Debug::IsDebugBreakAtReturn(rinfo());
-}
+// Patch the code at the current PC with a call to the target address.
+// Additional guard int3 instructions can be added if required.
+void PatchCodeWithCall(Address pc, Address target, int guard_bytes) {
+  int code_size = Assembler::kCallSequenceLength + guard_bytes;
 
+  // Create a code patcher.
+  CodePatcher patcher(pc, code_size);
 
-// Patch the JS frame exit code with a debug break call. See
-// CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x64.cc
-// for the precise return instructions sequence.
-void BreakLocationIterator::SetDebugBreakAtReturn()  {
-  DCHECK(Assembler::kJSReturnSequenceLength >= Assembler::kCallSequenceLength);
-  rinfo()->PatchCodeWithCall(
-      debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
-      Assembler::kJSReturnSequenceLength - Assembler::kCallSequenceLength);
-}
+// Add a label for checking the size of the code used for returning.
+#ifdef DEBUG
+  Label check_codesize;
+  patcher.masm()->bind(&check_codesize);
+#endif
 
+  // Patch the code.
+  patcher.masm()->movp(kScratchRegister, reinterpret_cast<void*>(target),
+                       Assembler::RelocInfoNone());
+  patcher.masm()->call(kScratchRegister);
 
-// Restore the JS frame exit code.
-void BreakLocationIterator::ClearDebugBreakAtReturn() {
-  rinfo()->PatchCode(original_rinfo()->pc(),
-                     Assembler::kJSReturnSequenceLength);
-}
+  // Check that the size of the code generated is as expected.
+  DCHECK_EQ(Assembler::kCallSequenceLength,
+            patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
 
+  // Add the requested number of int3 instructions after the call.
+  for (int i = 0; i < guard_bytes; i++) {
+    patcher.masm()->int3();
+  }
 
-// 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(v8::internal::RelocInfo* rinfo) {
-  DCHECK(RelocInfo::IsJSReturn(rinfo->rmode()));
-  return rinfo->IsPatchedReturnSequence();
+  CpuFeatures::FlushICache(pc, code_size);
 }
 
 
-bool BreakLocationIterator::IsDebugBreakAtSlot() {
-  DCHECK(IsDebugBreakSlot());
-  // Check whether the debug break slot instructions have been patched.
-  return rinfo()->IsPatchedDebugBreakSlotSequence();
+// Patch the JS frame exit code with a debug break call. See
+// CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x64.cc
+// for the precise return instructions sequence.
+void BreakLocation::SetDebugBreakAtReturn() {
+  DCHECK(Assembler::kJSReturnSequenceLength >= Assembler::kCallSequenceLength);
+  PatchCodeWithCall(
+      pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
+      Assembler::kJSReturnSequenceLength - Assembler::kCallSequenceLength);
 }
 
 
-void BreakLocationIterator::SetDebugBreakAtSlot() {
+void BreakLocation::SetDebugBreakAtSlot() {
   DCHECK(IsDebugBreakSlot());
-  rinfo()->PatchCodeWithCall(
-      debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry(),
+  PatchCodeWithCall(
+      pc(), debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry(),
       Assembler::kDebugBreakSlotLength - Assembler::kCallSequenceLength);
 }
 
 
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
-  DCHECK(IsDebugBreakSlot());
-  rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
-}
-
-
 #define __ ACCESS_MASM(masm)
 
 
index 2fc6181..02e9d2e 100644 (file)
@@ -134,7 +134,7 @@ bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
 
 #define __ masm()->
 
-void Deoptimizer::EntryGenerator::Generate() {
+void Deoptimizer::TableEntryGenerator::Generate() {
   GeneratePrologue();
 
   // Save all general purpose registers before messing with them.
@@ -307,7 +307,6 @@ void Deoptimizer::EntryGenerator::Generate() {
 
   // Set up the roots register.
   __ InitializeRootRegister();
-  __ InitializeSmiConstantRegister();
 
   // Return to the continuation point.
   __ ret(0);
index bed99d1..4f5e74f 100644 (file)
@@ -956,11 +956,21 @@ int DisassemblerX64::AVXInstruction(byte* data) {
                        NameOfXMMRegister(vvvv));
         current += PrintRightXMMOperand(current);
         break;
+      case 0x5d:
+        AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
       case 0x5e:
         AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
                        NameOfXMMRegister(vvvv));
         current += PrintRightXMMOperand(current);
         break;
+      case 0x5f:
+        AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
       default:
         UnimplementedInstruction();
     }
@@ -1179,6 +1189,19 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
         current += PrintRightXMMOperand(current);
         AppendToBuffer(",%d", (*current) & 3);
         current += 1;
+      } else if (third_byte == 0x16) {
+        get_modrm(*current, &mod, &regop, &rm);
+        AppendToBuffer("pextrd ");  // reg/m32, xmm, imm8
+        current += PrintRightOperand(current);
+        AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
+        current += 1;
+      } else if (third_byte == 0x22) {
+        get_modrm(*current, &mod, &regop, &rm);
+        AppendToBuffer("pinsrd ");  // xmm, reg/m32, imm8
+        AppendToBuffer(" %s,", NameOfXMMRegister(regop));
+        current += PrintRightOperand(current);
+        AppendToBuffer(",%d", (*current) & 3);
+        current += 1;
       } else {
         UnimplementedInstruction();
       }
@@ -1229,12 +1252,12 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
         current += PrintRightXMMOperand(current);
       } else if (opcode == 0x72) {
         current += 1;
-        AppendToBuffer("%s,%s,%d", (regop == 6) ? "pslld" : "psrld",
+        AppendToBuffer("%s %s,%d", (regop == 6) ? "pslld" : "psrld",
                        NameOfXMMRegister(rm), *current & 0x7f);
         current += 1;
       } else if (opcode == 0x73) {
         current += 1;
-        AppendToBuffer("%s,%s,%d", (regop == 6) ? "psllq" : "psrlq",
+        AppendToBuffer("%s %s,%d", (regop == 6) ? "psllq" : "psrlq",
                        NameOfXMMRegister(rm), *current & 0x7f);
         current += 1;
       } else {
@@ -1251,6 +1274,10 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
           mnemonic = "comisd";
         } else if (opcode == 0x76) {
           mnemonic = "pcmpeqd";
+        } else if (opcode == 0x62) {
+          mnemonic = "punpckldq";
+        } else if (opcode == 0x6A) {
+          mnemonic = "punpckhdq";
         } else {
           UnimplementedInstruction();
         }
@@ -1526,10 +1553,14 @@ const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
       return "mulsd";
     case 0x5A:  // F2 prefix.
       return "cvtsd2ss";
+    case 0x5D:  // F2 prefix.
+      return "minsd";
     case 0x5C:  // F2 prefix.
       return "subsd";
     case 0x5E:  // F2 prefix.
       return "divsd";
+    case 0x5F:  // F2 prefix.
+      return "maxsd";
     case 0xA2:
       return "cpuid";
     case 0xA5:
index 8813030..1f8612a 100644 (file)
@@ -107,15 +107,6 @@ inline Object* JavaScriptFrame::function_slot_object() const {
 }
 
 
-inline void StackHandler::SetFp(Address slot, Address fp) {
-  if (kFPOnStackSize == 2 * kPointerSize) {
-    // Zero out the high-32 bit of FP for x32 port.
-    Memory::Address_at(slot + kPointerSize) = 0;
-  }
-  Memory::Address_at(slot) = fp;
-}
-
-
 } }  // namespace v8::internal
 
 #endif  // V8_X64_FRAMES_X64_H_
index 9d70abf..5861327 100644 (file)
@@ -95,7 +95,8 @@ class JumpPatchSite BASE_EMBEDDED {
 void FullCodeGenerator::Generate() {
   CompilationInfo* info = info_;
   handler_table_ =
-      isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
+      Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray(
+          HandlerTable::LengthForRange(function()->handler_count()), TENURED));
 
   profiling_counter_ = isolate()->factory()->NewCell(
       Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
@@ -187,7 +188,7 @@ void FullCodeGenerator::Generate() {
     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_script_scope()) {
+    if (info->scope()->is_script_scope()) {
       __ Push(rdi);
       __ Push(info->scope()->GetScopeInfo(info->isolate()));
       __ CallRuntime(Runtime::kNewScriptContext, 2);
@@ -232,6 +233,11 @@ void FullCodeGenerator::Generate() {
     }
   }
 
+ArgumentsAccessStub::HasNewTarget has_new_target =
+    IsSubclassConstructor(info->function()->kind())
+        ? ArgumentsAccessStub::HAS_NEW_TARGET
+        : ArgumentsAccessStub::NO_NEW_TARGET;
+
   // Possibly allocate RestParameters
   int rest_index;
   Variable* rest_param = scope()->rest_parameter(&rest_index);
@@ -240,6 +246,11 @@ void FullCodeGenerator::Generate() {
 
     int num_parameters = info->scope()->num_parameters();
     int offset = num_parameters * kPointerSize;
+    if (has_new_target == ArgumentsAccessStub::HAS_NEW_TARGET) {
+      --num_parameters;
+      ++rest_index;
+    }
+
     __ leap(rdx,
             Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset));
     __ Push(rdx);
@@ -275,10 +286,6 @@ void FullCodeGenerator::Generate() {
     // The stub will rewrite receiver and parameter count if the previous
     // stack frame was an arguments adapter frame.
 
-    ArgumentsAccessStub::HasNewTarget has_new_target =
-        IsSubclassConstructor(info->function()->kind())
-            ? ArgumentsAccessStub::HAS_NEW_TARGET
-            : ArgumentsAccessStub::NO_NEW_TARGET;
     ArgumentsAccessStub::Type type;
     if (is_strict(language_mode()) || !is_simple_parameter_list()) {
       type = ArgumentsAccessStub::NEW_STRICT;
@@ -1489,7 +1496,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
         __ Move(VectorLoadICDescriptor::SlotRegister(),
                 SmiFromSlot(proxy->VariableFeedbackSlot()));
       }
-      CallLoadIC(CONTEXTUAL);
+      CallGlobalLoadIC(var->name());
       context()->Plug(rax);
       break;
     }
@@ -2132,7 +2139,6 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
 
       // 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"
       __ Push(load_name);
       __ Push(Operand(rsp, 2 * kPointerSize));               // iter
@@ -2144,16 +2150,17 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       // re-boxing.
       __ bind(&l_try);
       __ Pop(rax);                                       // result
-      __ PushTryHandler(StackHandler::CATCH, expr->index());
-      const int handler_size = StackHandlerConstants::kSize;
+      EnterTryBlock(expr->index(), &l_catch);
+      const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ Push(rax);                                      // result
       __ jmp(&l_suspend);
       __ bind(&l_continuation);
       __ jmp(&l_resume);
       __ bind(&l_suspend);
-      const int generator_object_depth = kPointerSize + handler_size;
+      const int generator_object_depth = kPointerSize + try_block_size;
       __ movp(rax, Operand(rsp, generator_object_depth));
       __ Push(rax);                                      // g
+      __ Push(Smi::FromInt(expr->index()));              // handler-index
       DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
       __ Move(FieldOperand(rax, JSGeneratorObject::kContinuationOffset),
               Smi::FromInt(l_continuation.pos()));
@@ -2161,13 +2168,13 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       __ movp(rcx, rsi);
       __ RecordWriteField(rax, JSGeneratorObject::kContextOffset, rcx, rdx,
                           kDontSaveFPRegs);
-      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 2);
       __ movp(context_register(),
               Operand(rbp, StandardFrameConstants::kContextOffset));
       __ Pop(rax);                                       // result
       EmitReturnSequence();
       __ bind(&l_resume);                                // received in rax
-      __ PopTryHandler();
+      ExitTryBlock(expr->index());
 
       // receiver = iter; f = 'next'; arg = received;
       __ bind(&l_next);
@@ -2478,6 +2485,16 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
       __ Push(Operand(rsp, 0));  // prototype
     }
     EmitPropertyKey(property, lit->GetIdForProperty(i));
+
+    // The static prototype property is read only. We handle the non computed
+    // property name case in the parser. Since this is the only case where we
+    // need to check for an own read only property we special case this so we do
+    // not need to do this for every property.
+    if (property->is_static() && property->is_computed_name()) {
+      __ CallRuntime(Runtime::kThrowIfStaticPrototype, 1);
+      __ Push(rax);
+    }
+
     VisitForStackValue(value);
     EmitSetHomeObjectIfNeeded(value, 2);
 
@@ -2618,25 +2635,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
     __ movp(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(rax);
-      __ Push(rsi);
-      __ Push(var->name());
-      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
-    } else {
-      DCHECK(var->IsStackLocal() || var->IsContextSlot());
-      Label skip;
-      MemOperand location = VarOperand(var, rcx);
-      __ movp(rdx, location);
-      __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
-      __ j(not_equal, &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());
@@ -2651,6 +2649,20 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
     __ bind(&assign);
     EmitStoreToStackLocalOrContextSlot(var, location);
 
+  } else if (var->mode() == CONST && op != Token::INIT_CONST) {
+    // Assignment to const variable needs a write barrier.
+    DCHECK(!var->IsLookupSlot());
+    DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+    Label const_error;
+    MemOperand location = VarOperand(var, rcx);
+    __ movp(rdx, location);
+    __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
+    __ j(not_equal, &const_error, Label::kNear);
+    __ Push(var->name());
+    __ CallRuntime(Runtime::kThrowReferenceError, 1);
+    __ bind(&const_error);
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
   } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
     if (var->IsLookupSlot()) {
       // Assignment to var.
@@ -2672,8 +2684,33 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
-  } else if (IsSignallingAssignmentToConst(var, op, language_mode())) {
-    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
+  } else if (op == Token::INIT_CONST_LEGACY) {
+    // Const initializers need a write barrier.
+    DCHECK(var->mode() == CONST_LEGACY);
+    DCHECK(!var->IsParameter());  // No const parameters.
+    if (var->IsLookupSlot()) {
+      __ Push(rax);
+      __ Push(rsi);
+      __ Push(var->name());
+      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
+    } else {
+      DCHECK(var->IsStackLocal() || var->IsContextSlot());
+      Label skip;
+      MemOperand location = VarOperand(var, rcx);
+      __ movp(rdx, location);
+      __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
+      __ j(not_equal, &skip);
+      EmitStoreToStackLocalOrContextSlot(var, location);
+      __ bind(&skip);
+    }
+
+  } else {
+    DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT_CONST_LEGACY);
+    if (is_strict(language_mode())) {
+      __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+    }
+    // Silently ignore store in sloppy mode.
   }
 }
 
@@ -3143,8 +3180,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
 
 
 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
-  if (!ValidateSuperCall(expr)) return;
-
   Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
   GetVar(result_register(), new_target_var);
   __ Push(result_register());
@@ -3649,8 +3684,8 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 
   // Check if the constructor in the map is a JS function.
-  __ movp(rax, FieldOperand(rax, Map::kConstructorOffset));
-  __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
+  __ GetMapConstructor(rax, rax, rbx);
+  __ CmpInstanceType(rbx, JS_FUNCTION_TYPE);
   __ j(not_equal, &non_function_constructor);
 
   // rax now contains the constructor function. Grab the
@@ -3950,7 +3985,7 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
   __ jmp(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&done);
   context()->Plug(result);
@@ -3998,7 +4033,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
   __ jmp(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&done);
   context()->Plug(result);
@@ -4177,7 +4212,7 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
   // Call runtime to perform the lookup.
   __ Push(cache);
   __ Push(key);
-  __ CallRuntime(Runtime::kGetFromCache, 2);
+  __ CallRuntime(Runtime::kGetFromCacheRT, 2);
 
   __ bind(&done);
   context()->Plug(rax);
@@ -4519,18 +4554,11 @@ void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
 
 
 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()) {
+    Comment cmnt(masm_, "[ CallRuntime");
     // Push the builtins object as receiver.
     __ movp(rax, GlobalObjectOperand());
     __ Push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
@@ -4566,14 +4594,27 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     context()->DropAndPlug(1, rax);
 
   } else {
-    // Push the arguments ("left-to-right").
-    for (int i = 0; i < arg_count; i++) {
-      VisitForStackValue(args->at(i));
-    }
+    const Runtime::Function* function = expr->function();
+    switch (function->function_id) {
+#define CALL_INTRINSIC_GENERATOR(Name)     \
+  case Runtime::kInline##Name: {           \
+    Comment cmnt(masm_, "[ Inline" #Name); \
+    return Emit##Name(expr);               \
+  }
+      FOR_EACH_FULL_CODE_INTRINSIC(CALL_INTRINSIC_GENERATOR)
+#undef CALL_INTRINSIC_GENERATOR
+      default: {
+        Comment cmnt(masm_, "[ CallRuntime for unhandled intrinsic");
+        // Push the arguments ("left-to-right").
+        for (int i = 0; i < arg_count; i++) {
+          VisitForStackValue(args->at(i));
+        }
 
-    // Call the C runtime.
-    __ CallRuntime(expr->function(), arg_count);
-    context()->Plug(rax);
+        // Call the C runtime.
+        __ CallRuntime(function, arg_count);
+        context()->Plug(rax);
+      }
+    }
   }
 }
 
@@ -5221,17 +5262,6 @@ void FullCodeGenerator::EnterFinallyBlock() {
       ExternalReference::address_of_pending_message_obj(isolate());
   __ Load(rdx, pending_message_obj);
   __ Push(rdx);
-
-  ExternalReference has_pending_message =
-      ExternalReference::address_of_has_pending_message(isolate());
-  __ Load(rdx, has_pending_message);
-  __ Integer32ToSmi(rdx, rdx);
-  __ Push(rdx);
-
-  ExternalReference pending_message_script =
-      ExternalReference::address_of_pending_message_script(isolate());
-  __ Load(rdx, pending_message_script);
-  __ Push(rdx);
 }
 
 
@@ -5240,17 +5270,6 @@ void FullCodeGenerator::ExitFinallyBlock() {
   DCHECK(!result_register().is(rcx));
   // Restore pending message from stack.
   __ Pop(rdx);
-  ExternalReference pending_message_script =
-      ExternalReference::address_of_pending_message_script(isolate());
-  __ Store(pending_message_script, rdx);
-
-  __ Pop(rdx);
-  __ SmiToInteger32(rdx, rdx);
-  ExternalReference has_pending_message =
-      ExternalReference::address_of_has_pending_message(isolate());
-  __ Store(has_pending_message, rdx);
-
-  __ Pop(rdx);
   ExternalReference pending_message_obj =
       ExternalReference::address_of_pending_message_obj(isolate());
   __ Store(pending_message_obj, rdx);
@@ -5269,34 +5288,6 @@ void FullCodeGenerator::ExitFinallyBlock() {
 
 #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.
-    __ movp(rsi, Operand(rsp, StackHandlerConstants::kContextOffset));
-    __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
-  }
-  __ PopTryHandler();
-  __ call(finally_entry_);
-
-  *stack_depth = 0;
-  *context_length = 0;
-  return previous_;
-}
-
-
-#undef __
-
 
 static const byte kJnsInstruction = 0x79;
 static const byte kNopByteOne = 0x66;
index 1ca0c85..0cef86e 100644 (file)
@@ -229,6 +229,12 @@ void InternalArrayConstructorDescriptor::Initialize(
 }
 
 
+void CompareDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {rsi, rdx, rax};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
 void CompareNilDescriptor::Initialize(CallInterfaceDescriptorData* data) {
   Register registers[] = {rsi, rax};
   data->Initialize(arraysize(registers), registers, NULL);
index f4d7577..bfbadeb 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/base/bits.h"
 #include "src/code-factory.h"
 #include "src/code-stubs.h"
+#include "src/cpu-profiler.h"
 #include "src/hydrogen-osr.h"
 #include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
@@ -128,7 +129,7 @@ bool LCodeGen::GeneratePrologue() {
 
     // Sloppy mode functions need to replace the receiver with the global proxy
     // when called as functions (without an explicit receiver object).
-    if (info_->this_has_uses() && is_sloppy(info_->language_mode()) &&
+    if (graph()->this_has_uses() && is_sloppy(info_->language_mode()) &&
         !info_->is_native()) {
       Label ok;
       StackArgumentsAccessor args(rsp, scope()->num_parameters());
@@ -296,10 +297,10 @@ void LCodeGen::GenerateBodyInstructionPost(LInstruction* instr) {
 
 
 bool LCodeGen::GenerateJumpTable() {
+  if (jump_table_.length() == 0) return !is_aborted();
+
   Label needs_frame;
-  if (jump_table_.length() > 0) {
-    Comment(";;; -------------------- Jump table --------------------");
-  }
+  Comment(";;; -------------------- Jump table --------------------");
   for (int i = 0; i < jump_table_.length(); i++) {
     Deoptimizer::JumpTableEntry* table_entry = &jump_table_[i];
     __ bind(&table_entry->label);
@@ -308,23 +309,7 @@ bool LCodeGen::GenerateJumpTable() {
     if (table_entry->needs_frame) {
       DCHECK(!info()->saves_caller_doubles());
       __ Move(kScratchRegister, ExternalReference::ForDeoptEntry(entry));
-      if (needs_frame.is_bound()) {
-        __ jmp(&needs_frame);
-      } else {
-        __ bind(&needs_frame);
-        __ movp(rsi, MemOperand(rbp, StandardFrameConstants::kContextOffset));
-        __ pushq(rbp);
-        __ movp(rbp, rsp);
-        __ Push(rsi);
-        // 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());
-        __ Move(rsi, Smi::FromInt(StackFrame::STUB));
-        __ Push(rsi);
-        __ movp(rsi, MemOperand(rsp, kPointerSize));
-        __ call(kScratchRegister);
-      }
+      __ call(&needs_frame);
     } else {
       if (info()->saves_caller_doubles()) {
         DCHECK(info()->IsStub());
@@ -332,7 +317,58 @@ bool LCodeGen::GenerateJumpTable() {
       }
       __ call(entry, RelocInfo::RUNTIME_ENTRY);
     }
+    info()->LogDeoptCallPosition(masm()->pc_offset(),
+                                 table_entry->deopt_info.inlining_id);
+  }
+
+  if (needs_frame.is_linked()) {
+    __ bind(&needs_frame);
+    /* stack layout
+       4: return address  <-- rsp
+       3: garbage
+       2: garbage
+       1: garbage
+       0: garbage
+    */
+    // Reserve space for context and stub marker.
+    __ subp(rsp, Immediate(2 * kPointerSize));
+    __ Push(MemOperand(rsp, 2 * kPointerSize));  // Copy return address.
+    __ Push(kScratchRegister);  // Save entry address for ret(0)
+
+    /* stack layout
+       4: return address
+       3: garbage
+       2: garbage
+       1: return address
+       0: entry address  <-- rsp
+    */
+
+    // Remember context pointer.
+    __ movp(kScratchRegister,
+            MemOperand(rbp, StandardFrameConstants::kContextOffset));
+    // Save context pointer into the stack frame.
+    __ movp(MemOperand(rsp, 3 * kPointerSize), kScratchRegister);
+
+    // Create a stack frame.
+    __ movp(MemOperand(rsp, 4 * kPointerSize), rbp);
+    __ leap(rbp, MemOperand(rsp, 4 * kPointerSize));
+
+    // 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());
+    __ Move(MemOperand(rsp, 2 * kPointerSize), Smi::FromInt(StackFrame::STUB));
+
+    /* stack layout
+       4: old rbp
+       3: context pointer
+       2: stub marker
+       1: return address
+       0: entry address  <-- rsp
+    */
+    __ ret(0);
   }
+
   return !is_aborted();
 }
 
@@ -768,8 +804,8 @@ void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
     __ bind(&done);
   }
 
-  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
-                                    instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info = MakeDeoptInfo(instr, deopt_reason);
+
   DCHECK(info()->IsStub() || frame_is_built_);
   // Go through jump table if we need to handle condition, build frame, or
   // restore caller doubles.
@@ -777,6 +813,7 @@ void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
       !info()->saves_caller_doubles()) {
     DeoptComment(deopt_info);
     __ call(entry, RelocInfo::RUNTIME_ENTRY);
+    info()->LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
   } else {
     Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
                                             !frame_is_built_);
@@ -2614,10 +2651,10 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
 
   // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
   // Check if the constructor in the map is a function.
-  __ movp(temp, FieldOperand(temp, Map::kConstructorOffset));
+  __ GetMapConstructor(temp, temp, kScratchRegister);
 
   // Objects with a non-function constructor have class 'Object'.
-  __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister);
+  __ CmpInstanceType(kScratchRegister, JS_FUNCTION_TYPE);
   if (String::Equals(class_name, isolate()->factory()->Object_string())) {
     __ j(not_equal, is_true);
   } else {
@@ -2847,16 +2884,6 @@ void LCodeGen::DoReturn(LReturn* instr) {
 }
 
 
-void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
-  Register result = ToRegister(instr->result());
-  __ LoadGlobalCell(result, instr->hydrogen()->cell().handle());
-  if (instr->hydrogen()->RequiresHoleCheck()) {
-    __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(equal, instr, Deoptimizer::kHole);
-  }
-}
-
-
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
@@ -2886,37 +2913,12 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
   }
   ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
-  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode,
+                                                       PREMONOMORPHIC).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
 
-void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
-  Register value = ToRegister(instr->value());
-  Handle<Cell> cell_handle = 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. We deoptimize in that case.
-  if (instr->hydrogen()->RequiresHoleCheck()) {
-    // We have a temp because CompareRoot might clobber kScratchRegister.
-    Register cell = ToRegister(instr->temp());
-    DCHECK(!value.is(cell));
-    __ Move(cell, cell_handle, RelocInfo::CELL);
-    __ CompareRoot(Operand(cell, 0), Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(equal, instr, Deoptimizer::kHole);
-    // Store the value.
-    __ movp(Operand(cell, 0), value);
-  } else {
-    // Store the value.
-    __ Move(kScratchRegister, cell_handle, RelocInfo::CELL);
-    __ movp(Operand(kScratchRegister, 0), value);
-  }
-  // Cells are always rescanned, so no write barrier here.
-}
-
-
 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
   Register context = ToRegister(instr->context());
   Register result = ToRegister(instr->result());
@@ -3029,8 +3031,9 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
   if (FLAG_vector_ics) {
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
-  Handle<Code> ic =
-      CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(
+                        isolate(), NOT_CONTEXTUAL,
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3310,7 +3313,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code();
+  Handle<Code> ic =
+      CodeFactory::KeyedLoadICInOptimizedCode(
+          isolate(), instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3761,7 +3766,7 @@ void LCodeGen::DoMathFloor(LMathFloor* instr) {
       __ subq(output_reg, Immediate(1));
       DeoptimizeIf(overflow, instr, Deoptimizer::kMinusZero);
     }
-    __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
+    __ roundsd(xmm_scratch, input_reg, kRoundDown);
     __ cvttsd2si(output_reg, xmm_scratch);
     __ cmpl(output_reg, Immediate(0x1));
     DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow);
@@ -3996,14 +4001,8 @@ void LCodeGen::DoMathLog(LMathLog* instr) {
 void LCodeGen::DoMathClz32(LMathClz32* instr) {
   Register input = ToRegister(instr->value());
   Register result = ToRegister(instr->result());
-  Label not_zero_input;
-  __ bsrl(result, input);
 
-  __ j(not_zero, &not_zero_input);
-  __ Set(result, 63);  // 63^31 == 32
-
-  __ bind(&not_zero_input);
-  __ xorl(result, Immediate(31));  // for x in [0..31], 31^x == 31-x.
+  __ Lzcntl(result, input);
 }
 
 
@@ -4270,7 +4269,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
   __ Move(StoreDescriptor::NameRegister(), instr->hydrogen()->name());
-  Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->language_mode());
+  Handle<Code> ic =
+      StoreIC::initialize_stub(isolate(), instr->language_mode(),
+                               instr->hydrogen()->initialization_state());
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -4529,8 +4530,9 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
   DCHECK(ToRegister(instr->key()).is(StoreDescriptor::NameRegister()));
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
-  Handle<Code> ic =
-      CodeFactory::KeyedStoreIC(isolate(), instr->language_mode()).code();
+  Handle<Code> ic = CodeFactory::KeyedStoreICInOptimizedCode(
+                        isolate(), instr->language_mode(),
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
index 2b67ce9..9e6a655 100644 (file)
@@ -2083,14 +2083,6 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
 }
 
 
-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(), rsi);
   LOperand* global_object =
@@ -2106,16 +2098,6 @@ LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
-  LOperand* value = UseRegister(instr->value());
-  // Use a temp to avoid reloading the cell value address 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 =
index ec54c7d..a7a1fe8 100644 (file)
@@ -100,7 +100,6 @@ class LCodeGen;
   V(LoadRoot)                                \
   V(LoadFieldByIndex)                        \
   V(LoadFunctionPrototype)                   \
-  V(LoadGlobalCell)                          \
   V(LoadGlobalGeneric)                       \
   V(LoadKeyed)                               \
   V(LoadKeyedGeneric)                        \
@@ -140,7 +139,6 @@ class LCodeGen;
   V(StoreCodeEntry)                          \
   V(StoreContextSlot)                        \
   V(StoreFrameContext)                       \
-  V(StoreGlobalCell)                         \
   V(StoreKeyed)                              \
   V(StoreKeyedGeneric)                       \
   V(StoreNamedField)                         \
@@ -1695,13 +1693,6 @@ class LLoadKeyedGeneric FINAL : public LTemplateInstruction<1, 3, 1> {
 };
 
 
-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:
   explicit LLoadGlobalGeneric(LOperand* context, LOperand* global_object,
@@ -1723,21 +1714,6 @@ class LLoadGlobalGeneric FINAL : public LTemplateInstruction<1, 2, 1> {
 };
 
 
-class LStoreGlobalCell FINAL : public LTemplateInstruction<0, 1, 1> {
- public:
-  explicit 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) {
index a117226..65b65a3 100644 (file)
@@ -14,7 +14,6 @@
 #include "src/debug.h"
 #include "src/heap/heap.h"
 #include "src/isolate-inl.h"
-#include "src/serialize.h"
 #include "src/x64/assembler-x64.h"
 #include "src/x64/macro-assembler-x64.h"
 
@@ -177,6 +176,7 @@ void MacroAssembler::LoadRootIndexed(Register destination,
 
 
 void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index) {
+  DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
   DCHECK(root_array_available_);
   movp(Operand(kRootRegister, (index << kPointerSizeLog2) - kRootRegisterBias),
        source);
@@ -920,67 +920,13 @@ Register MacroAssembler::GetSmiConstant(Smi* source) {
     xorl(kScratchRegister, kScratchRegister);
     return kScratchRegister;
   }
-  if (value == 1) {
-    return kSmiConstantRegister;
-  }
   LoadSmiConstant(kScratchRegister, source);
   return kScratchRegister;
 }
 
 
 void MacroAssembler::LoadSmiConstant(Register dst, Smi* source) {
-  if (emit_debug_code()) {
-    Move(dst, Smi::FromInt(kSmiConstantRegisterValue),
-         Assembler::RelocInfoNone());
-    cmpp(dst, kSmiConstantRegister);
-    Assert(equal, kUninitializedKSmiConstantRegister);
-  }
-  int value = source->value();
-  if (value == 0) {
-    xorl(dst, dst);
-    return;
-  }
-  bool negative = value < 0;
-  unsigned int uvalue = negative ? -value : value;
-
-  switch (uvalue) {
-    case 9:
-      leap(dst,
-           Operand(kSmiConstantRegister, kSmiConstantRegister, times_8, 0));
-      break;
-    case 8:
-      xorl(dst, dst);
-      leap(dst, Operand(dst, kSmiConstantRegister, times_8, 0));
-      break;
-    case 4:
-      xorl(dst, dst);
-      leap(dst, Operand(dst, kSmiConstantRegister, times_4, 0));
-      break;
-    case 5:
-      leap(dst,
-           Operand(kSmiConstantRegister, kSmiConstantRegister, times_4, 0));
-      break;
-    case 3:
-      leap(dst,
-           Operand(kSmiConstantRegister, kSmiConstantRegister, times_2, 0));
-      break;
-    case 2:
-      leap(dst,
-           Operand(kSmiConstantRegister, kSmiConstantRegister, times_1, 0));
-      break;
-    case 1:
-      movp(dst, kSmiConstantRegister);
-      break;
-    case 0:
-      UNREACHABLE();
-      return;
-    default:
-      Move(dst, source, Assembler::RelocInfoNone());
-      return;
-  }
-  if (negative) {
-    negp(dst);
-  }
+  Move(dst, source, Assembler::RelocInfoNone());
 }
 
 
@@ -1273,14 +1219,6 @@ Condition MacroAssembler::CheckEitherSmi(Register first,
 }
 
 
-Condition MacroAssembler::CheckIsMinSmi(Register src) {
-  DCHECK(!src.is(kScratchRegister));
-  // If we overflow by subtracting one, it's the minimal smi value.
-  cmpp(src, kSmiConstantRegister);
-  return overflow;
-}
-
-
 Condition MacroAssembler::CheckInteger32ValidSmiValue(Register src) {
   if (SmiValuesAre32Bits()) {
     // A 32-bit integer value can always be converted to a smi.
@@ -1419,43 +1357,11 @@ void MacroAssembler::SmiAddConstant(Register dst, Register src, Smi* constant) {
     return;
   } else if (dst.is(src)) {
     DCHECK(!dst.is(kScratchRegister));
-    switch (constant->value()) {
-      case 1:
-        addp(dst, kSmiConstantRegister);
-        return;
-      case 2:
-        leap(dst, Operand(src, kSmiConstantRegister, times_2, 0));
-        return;
-      case 4:
-        leap(dst, Operand(src, kSmiConstantRegister, times_4, 0));
-        return;
-      case 8:
-        leap(dst, Operand(src, kSmiConstantRegister, times_8, 0));
-        return;
-      default:
-        Register constant_reg = GetSmiConstant(constant);
-        addp(dst, constant_reg);
-        return;
-    }
+    Register constant_reg = GetSmiConstant(constant);
+    addp(dst, constant_reg);
   } else {
-    switch (constant->value()) {
-      case 1:
-        leap(dst, Operand(src, kSmiConstantRegister, times_1, 0));
-        return;
-      case 2:
-        leap(dst, Operand(src, kSmiConstantRegister, times_2, 0));
-        return;
-      case 4:
-        leap(dst, Operand(src, kSmiConstantRegister, times_4, 0));
-        return;
-      case 8:
-        leap(dst, Operand(src, kSmiConstantRegister, times_8, 0));
-        return;
-      default:
-        LoadSmiConstant(dst, constant);
-        addp(dst, src);
-        return;
-    }
+    LoadSmiConstant(dst, constant);
+    addp(dst, src);
   }
 }
 
@@ -2578,24 +2484,43 @@ void MacroAssembler::Move(XMMRegister dst, uint32_t src) {
   if (src == 0) {
     xorps(dst, dst);
   } else {
-    movl(kScratchRegister, Immediate(src));
-    movq(dst, kScratchRegister);
+    unsigned pop = base::bits::CountPopulation32(src);
+    DCHECK_NE(0u, pop);
+    if (pop == 32) {
+      pcmpeqd(dst, dst);
+    } 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);
+  if (src == 0) {
+    xorps(dst, dst);
   } else {
-    if (lower == 0) {
-      Move(dst, upper);
-      psllq(dst, 32);
+    unsigned nlz = base::bits::CountLeadingZeros64(src);
+    unsigned ntz = base::bits::CountTrailingZeros64(src);
+    unsigned pop = base::bits::CountPopulation64(src);
+    DCHECK_NE(0u, pop);
+    if (pop == 64) {
+      pcmpeqd(dst, dst);
+    } else if (pop + ntz == 64) {
+      pcmpeqd(dst, dst);
+      psllq(dst, ntz);
+    } else if (pop + nlz == 64) {
+      pcmpeqd(dst, dst);
+      psrlq(dst, nlz);
     } else {
-      movq(kScratchRegister, src);
-      movq(dst, kScratchRegister);
+      uint32_t lower = static_cast<uint32_t>(src);
+      uint32_t upper = static_cast<uint32_t>(src >> 32);
+      if (upper == 0) {
+        Move(dst, lower);
+      } else {
+        movq(kScratchRegister, src);
+        movq(dst, kScratchRegister);
+      }
     }
   }
 }
@@ -2770,15 +2695,13 @@ void MacroAssembler::Pop(const Operand& dst) {
     popq(dst);
   } else {
     Register scratch = dst.AddressUsesRegister(kScratchRegister)
-        ? kSmiConstantRegister : kScratchRegister;
+        ? kRootRegister : kScratchRegister;
     movp(scratch, Operand(rsp, 0));
     movp(dst, scratch);
     leal(rsp, Operand(rsp, 4));
-    if (scratch.is(kSmiConstantRegister)) {
-      // Restore kSmiConstantRegister.
-      movp(kSmiConstantRegister,
-           reinterpret_cast<void*>(Smi::FromInt(kSmiConstantRegisterValue)),
-           Assembler::RelocInfoNone());
+    if (scratch.is(kRootRegister)) {
+      // Restore kRootRegister.
+      InitializeRootRegister();
     }
   }
 }
@@ -2909,6 +2832,81 @@ void MacroAssembler::Call(Handle<Code> code_object,
 }
 
 
+void MacroAssembler::Pextrd(Register dst, XMMRegister src, int8_t imm8) {
+  if (imm8 == 0) {
+    movd(dst, src);
+    return;
+  }
+  DCHECK_EQ(1, imm8);
+  if (CpuFeatures::IsSupported(SSE4_1)) {
+    CpuFeatureScope sse_scope(this, SSE4_1);
+    pextrd(dst, src, imm8);
+    return;
+  }
+  movq(dst, src);
+  shrq(dst, Immediate(32));
+}
+
+
+void MacroAssembler::Pinsrd(XMMRegister dst, Register src, int8_t imm8) {
+  if (CpuFeatures::IsSupported(SSE4_1)) {
+    CpuFeatureScope sse_scope(this, SSE4_1);
+    pinsrd(dst, src, imm8);
+    return;
+  }
+  movd(xmm0, src);
+  if (imm8 == 1) {
+    punpckldq(dst, xmm0);
+  } else {
+    DCHECK_EQ(0, imm8);
+    psrlq(dst, 32);
+    punpckldq(xmm0, dst);
+    movaps(dst, xmm0);
+  }
+}
+
+
+void MacroAssembler::Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) {
+  DCHECK(imm8 == 0 || imm8 == 1);
+  if (CpuFeatures::IsSupported(SSE4_1)) {
+    CpuFeatureScope sse_scope(this, SSE4_1);
+    pinsrd(dst, src, imm8);
+    return;
+  }
+  movd(xmm0, src);
+  if (imm8 == 1) {
+    punpckldq(dst, xmm0);
+  } else {
+    DCHECK_EQ(0, imm8);
+    psrlq(dst, 32);
+    punpckldq(xmm0, dst);
+    movaps(dst, xmm0);
+  }
+}
+
+
+void MacroAssembler::Lzcntl(Register dst, Register src) {
+  // TODO(intel): Add support for LZCNT (BMI1/ABM).
+  Label not_zero_src;
+  bsrl(dst, src);
+  j(not_zero, &not_zero_src, Label::kNear);
+  Set(dst, 63);  // 63^31 == 32
+  bind(&not_zero_src);
+  xorl(dst, Immediate(31));  // for x in [0..31], 31^x == 31 - x
+}
+
+
+void MacroAssembler::Lzcntl(Register dst, const Operand& src) {
+  // TODO(intel): Add support for LZCNT (BMI1/ABM).
+  Label not_zero_src;
+  bsrl(dst, src);
+  j(not_zero, &not_zero_src, Label::kNear);
+  Set(dst, 63);  // 63^31 == 32
+  bind(&not_zero_src);
+  xorl(dst, Immediate(31));  // for x in [0..31], 31^x == 31 - x
+}
+
+
 void MacroAssembler::Pushad() {
   Push(rax);
   Push(rcx);
@@ -2921,11 +2919,11 @@ void MacroAssembler::Pushad() {
   Push(r9);
   // r10 is kScratchRegister.
   Push(r11);
-  // r12 is kSmiConstantRegister.
+  Push(r12);
   // r13 is kRootRegister.
   Push(r14);
   Push(r15);
-  STATIC_ASSERT(11 == kNumSafepointSavedRegisters);
+  STATIC_ASSERT(12 == kNumSafepointSavedRegisters);
   // Use lea for symmetry with Popad.
   int sp_delta =
       (kNumSafepointRegisters - kNumSafepointSavedRegisters) * kPointerSize;
@@ -2940,6 +2938,7 @@ void MacroAssembler::Popad() {
   leap(rsp, Operand(rsp, sp_delta));
   Pop(r15);
   Pop(r14);
+  Pop(r12);
   Pop(r11);
   Pop(r9);
   Pop(r8);
@@ -2973,10 +2972,10 @@ MacroAssembler::kSafepointPushRegisterIndices[Register::kNumRegisters] = {
     7,
     -1,
     8,
-    -1,
-    -1,
     9,
-    10
+    -1,
+    10,
+    11
 };
 
 
@@ -3001,46 +3000,21 @@ Operand MacroAssembler::SafepointRegisterSlot(Register reg) {
 }
 
 
-void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
-                                    int handler_index) {
+void MacroAssembler::PushStackHandler() {
   // Adjust this code if not the case.
-  STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize +
-                                                kFPOnStackSize);
+  STATIC_ASSERT(StackHandlerConstants::kSize == 1 * 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);
-
-  // We will build up the handler from the bottom by pushing on the stack.
-  // First push the frame pointer and context.
-  if (kind == StackHandler::JS_ENTRY) {
-    // The frame pointer does not point to a JS frame so we save NULL for
-    // rbp. We expect the code throwing an exception to check rbp before
-    // dereferencing it to restore the context.
-    pushq(Immediate(0));  // NULL frame pointer.
-    Push(Smi::FromInt(0));  // No context.
-  } else {
-    pushq(rbp);
-    Push(rsi);
-  }
-
-  // Push the state and the code object.
-  unsigned state =
-      StackHandler::IndexField::encode(handler_index) |
-      StackHandler::KindField::encode(kind);
-  Push(Immediate(state));
-  Push(CodeObject());
 
   // Link the current handler as the next handler.
   ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
   Push(ExternalOperand(handler_address));
+
   // Set this new handler as the current one.
   movp(ExternalOperand(handler_address), rsp);
 }
 
 
-void MacroAssembler::PopTryHandler() {
+void MacroAssembler::PopStackHandler() {
   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
   ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
   Pop(ExternalOperand(handler_address));
@@ -3048,106 +3022,6 @@ void MacroAssembler::PopTryHandler() {
 }
 
 
-void MacroAssembler::JumpToHandlerEntry() {
-  // Compute the handler entry address and jump to it.  The handler table is
-  // a fixed array of (smi-tagged) code offsets.
-  // rax = exception, rdi = code object, rdx = state.
-  movp(rbx, FieldOperand(rdi, Code::kHandlerTableOffset));
-  shrp(rdx, Immediate(StackHandler::kKindWidth));
-  movp(rdx,
-       FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize));
-  SmiToInteger64(rdx, rdx);
-  leap(rdi, FieldOperand(rdi, rdx, times_1, Code::kHeaderSize));
-  jmp(rdi);
-}
-
-
-void MacroAssembler::Throw(Register value) {
-  // Adjust this code if not the case.
-  STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize +
-                                                kFPOnStackSize);
-  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);
-
-  // The exception is expected in rax.
-  if (!value.is(rax)) {
-    movp(rax, value);
-  }
-  // Drop the stack pointer to the top of the top handler.
-  ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
-  movp(rsp, ExternalOperand(handler_address));
-  // Restore the next handler.
-  Pop(ExternalOperand(handler_address));
-
-  // Remove the code object and state, compute the handler address in rdi.
-  Pop(rdi);  // Code object.
-  Pop(rdx);  // Offset and state.
-
-  // Restore the context and frame pointer.
-  Pop(rsi);  // Context.
-  popq(rbp);  // Frame pointer.
-
-  // If the handler is a JS frame, restore the context to the frame.
-  // (kind == ENTRY) == (rbp == 0) == (rsi == 0), so we could test either
-  // rbp or rsi.
-  Label skip;
-  testp(rsi, rsi);
-  j(zero, &skip, Label::kNear);
-  movp(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
-  bind(&skip);
-
-  JumpToHandlerEntry();
-}
-
-
-void MacroAssembler::ThrowUncatchable(Register value) {
-  // Adjust this code if not the case.
-  STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize +
-                                                kFPOnStackSize);
-  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);
-
-  // The exception is expected in rax.
-  if (!value.is(rax)) {
-    movp(rax, value);
-  }
-  // Drop the stack pointer to the top of the top stack handler.
-  ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
-  Load(rsp, handler_address);
-
-  // Unwind the handlers until the top ENTRY handler is found.
-  Label fetch_next, check_kind;
-  jmp(&check_kind, Label::kNear);
-  bind(&fetch_next);
-  movp(rsp, Operand(rsp, StackHandlerConstants::kNextOffset));
-
-  bind(&check_kind);
-  STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
-  testl(Operand(rsp, StackHandlerConstants::kStateOffset),
-        Immediate(StackHandler::KindField::kMask));
-  j(not_zero, &fetch_next);
-
-  // Set the top handler address to next handler past the top ENTRY handler.
-  Pop(ExternalOperand(handler_address));
-
-  // Remove the code object and state, compute the handler address in rdi.
-  Pop(rdi);  // Code object.
-  Pop(rdx);  // Offset and state.
-
-  // Clear the context pointer and frame pointer (0 was saved in the handler).
-  Pop(rsi);
-  popq(rbp);
-
-  JumpToHandlerEntry();
-}
-
-
 void MacroAssembler::Ret() {
   ret(0);
 }
@@ -3565,6 +3439,20 @@ Condition MacroAssembler::IsObjectNameType(Register heap_object,
 }
 
 
+void MacroAssembler::GetMapConstructor(Register result, Register map,
+                                       Register temp) {
+  Label done, loop;
+  movp(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
+  bind(&loop);
+  JumpIfSmi(result, &done);
+  CmpObjectType(result, MAP_TYPE, temp);
+  j(not_equal, &done);
+  movp(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
+  jmp(&loop);
+  bind(&done);
+}
+
+
 void MacroAssembler::TryGetFunctionPrototype(Register function,
                                              Register result,
                                              Label* miss,
@@ -3618,7 +3506,7 @@ void MacroAssembler::TryGetFunctionPrototype(Register function,
     // Non-instance prototype: Fetch prototype from constructor field
     // in initial map.
     bind(&non_instance);
-    movp(result, FieldOperand(result, Map::kConstructorOffset));
+    GetMapConstructor(result, result, kScratchRegister);
   }
 
   // All done.
index 9f25d60..a851a46 100644 (file)
@@ -17,10 +17,7 @@ namespace internal {
 // a spare register). The register isn't callee save, and not used by the
 // function calling convention.
 const Register kScratchRegister = { 10 };      // r10.
-const Register kSmiConstantRegister = { 12 };  // r12 (callee save).
 const Register kRootRegister = { 13 };         // r13 (callee save).
-// Value of smi in kSmiConstantRegister.
-const int kSmiConstantRegisterValue = 1;
 // Actual value of root register is offset from the root array's start
 // to take advantage of negitive 8-bit displacement values.
 const int kRootRegisterBias = 128;
@@ -390,11 +387,6 @@ class MacroAssembler: public Assembler {
   void SafeMove(Register dst, Smi* src);
   void SafePush(Smi* src);
 
-  void InitializeSmiConstantRegister() {
-    Move(kSmiConstantRegister, Smi::FromInt(kSmiConstantRegisterValue),
-         Assembler::RelocInfoNone());
-  }
-
   // Conversions between tagged smi values and non-tagged integer values.
 
   // Tag an integer value. The result must be known to be a valid smi value.
@@ -474,11 +466,6 @@ class MacroAssembler: public Assembler {
                            Register second,
                            Register scratch = kScratchRegister);
 
-  // Is the value the minimum smi value (since we are using
-  // two's complement numbers, negating the value is known to yield
-  // a non-smi value).
-  Condition CheckIsMinSmi(Register src);
-
   // Checks whether an 32-bit integer value is a valid for conversion
   // to a smi.
   Condition CheckInteger32ValidSmiValue(Register src);
@@ -935,10 +922,18 @@ class MacroAssembler: public Assembler {
     Call(self, RelocInfo::CODE_TARGET);
   }
 
+  // Non-SSE2 instructions.
+  void Pextrd(Register dst, XMMRegister src, int8_t imm8);
+  void Pinsrd(XMMRegister dst, Register src, int8_t imm8);
+  void Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8);
+
+  void Lzcntl(Register dst, Register src);
+  void Lzcntl(Register dst, const Operand& src);
+
   // Non-x64 instructions.
   // Push/pop all general purpose registers.
   // Does not push rsp/rbp nor any of the assembler's special purpose registers
-  // (kScratchRegister, kSmiConstantRegister, kRootRegister).
+  // (kScratchRegister, kRootRegister).
   void Pushad();
   void Popad();
   // Sets the stack as after performing Popad, without actually loading the
@@ -1114,18 +1109,11 @@ class MacroAssembler: public Assembler {
   // ---------------------------------------------------------------------------
   // Exception handling
 
-  // Push a new try handler and link it into try handler chain.
-  void PushTryHandler(StackHandler::Kind kind, int handler_index);
+  // Push a new stack handler and link it into stack handler chain.
+  void PushStackHandler();
 
-  // Unlink the stack handler on top of the stack from the try handler chain.
-  void PopTryHandler();
-
-  // Activate the top handler in the try hander chain and pass the
-  // thrown value.
-  void Throw(Register value);
-
-  // Propagate an uncatchable exception out of the current JS stack.
-  void ThrowUncatchable(Register value);
+  // Unlink the stack handler on top of the stack from the stack handler chain.
+  void PopStackHandler();
 
   // ---------------------------------------------------------------------------
   // Inline caching support
@@ -1246,6 +1234,10 @@ class MacroAssembler: public Assembler {
   void NegativeZeroTest(Register result, Register op1, Register op2,
                         Register scratch, Label* then_label);
 
+  // Machine code version of Map::GetConstructor().
+  // |temp| holds |result|'s map when done.
+  void GetMapConstructor(Register result, Register map, Register temp);
+
   // 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
@@ -1464,9 +1456,9 @@ class MacroAssembler: public Assembler {
 
  private:
   // Order general registers are pushed by Pushad.
-  // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r14, r15.
+  // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r12, r14, r15.
   static const int kSafepointPushRegisterIndices[Register::kNumRegisters];
-  static const int kNumSafepointSavedRegisters = 11;
+  static const int kNumSafepointSavedRegisters = 12;
   static const int kSmiShift = kSmiTagSize + kSmiShiftSize;
 
   bool generating_stub_;
@@ -1538,10 +1530,6 @@ class MacroAssembler: public Assembler {
                           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.
   Operand SafepointRegisterSlot(Register reg);
   static int SafepointRegisterStackIndex(int reg_code) {
index 1818dbb..da55112 100644 (file)
@@ -11,7 +11,6 @@
 #include "src/macro-assembler.h"
 #include "src/regexp-macro-assembler.h"
 #include "src/regexp-stack.h"
-#include "src/serialize.h"
 #include "src/unicode.h"
 #include "src/x64/regexp-macro-assembler-x64.h"
 
@@ -43,10 +42,9 @@ namespace internal {
  *
  * The registers rax, rbx, r9 and r11 are free to use for computations.
  * If changed to use r12+, they should be saved as callee-save registers.
- * The macro assembler special registers r12 and r13 (kSmiConstantRegister,
- * kRootRegister) aren't special during execution of RegExp code (they don't
- * hold the values assumed when creating JS code), so no Smi or Root related
- * macro operations can be used.
+ * The macro assembler special register r13 (kRootRegister) isn't special
+ * during execution of RegExp code (it doesn't hold the value assumed when
+ * creating JS code), so Root related macro operations can be used.
  *
  * Each call to a C++ method should retain these registers.
  *
index 6555ccd..800ead2 100644 (file)
@@ -155,12 +155,24 @@ void RelocInfo::set_target_object(Object* target,
 }
 
 
-Address RelocInfo::target_reference() {
+Address RelocInfo::target_external_reference() {
   DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
   return Memory::Address_at(pc_);
 }
 
 
+Address RelocInfo::target_internal_reference() {
+  DCHECK(rmode_ == INTERNAL_REFERENCE);
+  return Memory::Address_at(pc_);
+}
+
+
+Address RelocInfo::target_internal_reference_address() {
+  DCHECK(rmode_ == INTERNAL_REFERENCE);
+  return reinterpret_cast<Address>(pc_);
+}
+
+
 Address RelocInfo::target_runtime_entry(Assembler* origin) {
   DCHECK(IsRuntimeEntry(rmode_));
   return reinterpret_cast<Address>(*reinterpret_cast<int32_t*>(pc_));
@@ -269,7 +281,8 @@ Object** RelocInfo::call_object_address() {
 
 
 void RelocInfo::WipeOut() {
-  if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_)) {
+  if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
+      IsInternalReference(rmode_)) {
     Memory::Address_at(pc_) = NULL;
   } else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
     // Effectively write zero into the relocation.
@@ -301,7 +314,8 @@ void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
     visitor->VisitCell(this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     visitor->VisitExternalReference(this);
-    CpuFeatures::FlushICache(pc_, sizeof(Address));
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
+    visitor->VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     visitor->VisitCodeAgeSequence(this);
   } else if (((RelocInfo::IsJSReturn(mode) &&
@@ -328,7 +342,8 @@ void RelocInfo::Visit(Heap* heap) {
     StaticVisitor::VisitCell(heap, this);
   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
     StaticVisitor::VisitExternalReference(this);
-    CpuFeatures::FlushICache(pc_, sizeof(Address));
+  } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
+    StaticVisitor::VisitInternalReference(this);
   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
     StaticVisitor::VisitCodeAgeSequence(heap, this);
   } else if (heap->isolate()->debug()->has_break_points() &&
@@ -517,6 +532,12 @@ void Assembler::emit_near_disp(Label* L) {
 }
 
 
+void Assembler::deserialization_set_target_internal_reference_at(
+    Address pc, Address target, RelocInfo::Mode mode) {
+  Memory::Address_at(pc) = target;
+}
+
+
 void Operand::set_modrm(int mod, Register rm) {
   DCHECK((mod & -4) == 0);
   buf_[0] = mod << 6 | rm.code();
index f2db021..43694de 100644 (file)
@@ -42,7 +42,6 @@
 #include "src/base/cpu.h"
 #include "src/disassembler.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
 
 namespace v8 {
 namespace internal {
@@ -102,17 +101,6 @@ bool RelocInfo::IsInConstantPool() {
 }
 
 
-void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
-  // Patch the code at the current address with the supplied instructions.
-  for (int i = 0; i < instruction_count; i++) {
-    *(pc_ + i) = *(instructions + i);
-  }
-
-  // Indicate that code has changed.
-  CpuFeatures::FlushICache(pc_, instruction_count);
-}
-
-
 // Patch the code at the current PC with a call to the target address.
 // Additional guard int3 instructions can be added if required.
 void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
@@ -123,7 +111,7 @@ void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
   // Create a code patcher.
   CodePatcher patcher(pc_, code_size);
 
-  // Add a label for checking the size of the code used for returning.
+// Add a label for checking the size of the code used for returning.
 #ifdef DEBUG
   Label check_codesize;
   patcher.masm()->bind(&check_codesize);
index 0535964..67af72e 100644 (file)
@@ -40,8 +40,8 @@
 #include <deque>
 
 #include "src/assembler.h"
+#include "src/compiler.h"
 #include "src/isolate.h"
-#include "src/serialize.h"
 
 namespace v8 {
 namespace internal {
@@ -529,6 +529,11 @@ class Assembler : public AssemblerBase {
     set_target_address_at(instruction_payload, code, target);
   }
 
+  // This sets the internal reference at the pc.
+  inline static void deserialization_set_target_internal_reference_at(
+      Address pc, Address target,
+      RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
+
   static const int kSpecialTargetSize = kPointerSize;
 
   // Distance between the address of the code target in the call instruction
@@ -941,7 +946,7 @@ class Assembler : public AssemblerBase {
 
   // Record a deoptimization reason that can be used by a log or cpu profiler.
   // Use --trace-deopt to enable.
-  void RecordDeoptReason(const int reason, const int raw_position);
+  void RecordDeoptReason(const int reason, const SourcePosition position);
 
   // Writes a single byte or word of data in the code stream.  Used for
   // inline tables, e.g., jump-tables.
index 9fda5a7..50c3c67 100644 (file)
@@ -990,42 +990,116 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
 }
 
 
-void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
-  static const int kArgumentsOffset = 2 * kPointerSize;
-  static const int kReceiverOffset = 3 * kPointerSize;
-  static const int kFunctionOffset = 4 * kPointerSize;
+static void Generate_CheckStackOverflow(MacroAssembler* masm,
+                                        const int calleeOffset) {
+  // eax   : the number of items to be pushed to the stack
+  //
+  // 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;
+  ExternalReference real_stack_limit =
+      ExternalReference::address_of_real_stack_limit(masm->isolate());
+  __ mov(edi, Operand::StaticVariable(real_stack_limit));
+  // Make ecx the space we have left. The stack might already be overflowed
+  // here which will cause ecx to become negative.
+  __ mov(ecx, esp);
+  __ sub(ecx, edi);
+  // Make edx the space we need for the array when it is unrolled onto the
+  // stack.
+  __ mov(edx, eax);
+  __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
+  // Check if the arguments will overflow the stack.
+  __ cmp(ecx, edx);
+  __ j(greater, &okay);  // Signed comparison.
+
+  // Out of stack space.
+  __ push(Operand(ebp, calleeOffset));  // push this
+  __ push(eax);
+  __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+
+  __ bind(&okay);
+}
+
+
+static void Generate_PushAppliedArguments(MacroAssembler* masm,
+                                          const int argumentsOffset,
+                                          const int indexOffset,
+                                          const int limitOffset) {
+  // Copy all arguments from the array to the stack.
+  Label entry, loop;
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register key = LoadDescriptor::NameRegister();
+  __ mov(key, Operand(ebp, indexOffset));
+  __ jmp(&entry);
+  __ bind(&loop);
+  __ mov(receiver, Operand(ebp, argumentsOffset));  // load arguments
+
+  if (FLAG_vector_ics) {
+    // 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.
+  }
+
+  // Push the nth argument.
+  __ push(eax);
+
+  // Update the index on the stack and in register key.
+  __ mov(key, Operand(ebp, indexOffset));
+  __ add(key, Immediate(1 << kSmiTagSize));
+  __ mov(Operand(ebp, indexOffset), key);
+
+  __ bind(&entry);
+  __ cmp(key, Operand(ebp, limitOffset));
+  __ j(not_equal, &loop);
+
+  // On exit, the pushed arguments count is in eax, untagged
+  __ Move(eax, key);
+  __ SmiUntag(eax);
+}
+
+
+// Used by FunctionApply and ReflectApply
+static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
+  const int kFormalParameters = targetIsArgument ? 3 : 2;
+  const int kStackSize = kFormalParameters + 1;
+
+  // Stack at entry:
+  // esp     : return address
+  // esp[4]  : arguments
+  // esp[8]  : receiver ("this")
+  // esp[12] : function
   {
     FrameScope frame_scope(masm, StackFrame::INTERNAL);
+    // Stack frame:
+    // ebp     : Old base pointer
+    // ebp[4]  : return address
+    // ebp[8]  : function arguments
+    // ebp[12] : receiver
+    // ebp[16] : function
+    static const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize;
+    static const int kReceiverOffset = kArgumentsOffset + kPointerSize;
+    static const int kFunctionOffset = kReceiverOffset + kPointerSize;
 
     __ push(Operand(ebp, kFunctionOffset));  // push this
     __ push(Operand(ebp, kArgumentsOffset));  // push arguments
-    __ 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;
-    ExternalReference real_stack_limit =
-        ExternalReference::address_of_real_stack_limit(masm->isolate());
-    __ mov(edi, Operand::StaticVariable(real_stack_limit));
-    // Make ecx the space we have left. The stack might already be overflowed
-    // here which will cause ecx to become negative.
-    __ mov(ecx, esp);
-    __ sub(ecx, edi);
-    // Make edx the space we need for the array when it is unrolled onto the
-    // stack.
-    __ mov(edx, eax);
-    __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
-    // Check if the arguments will overflow the stack.
-    __ cmp(ecx, edx);
-    __ j(greater, &okay);  // Signed comparison.
-
-    // Out of stack space.
-    __ push(Operand(ebp, 4 * kPointerSize));  // push this
-    __ push(eax);
-    __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
-    __ bind(&okay);
-    // End of stack check.
+    if (targetIsArgument) {
+      __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION);
+    } else {
+      __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
+    }
+
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
 
     // Push current index and limit.
     const int kLimitOffset =
@@ -1088,55 +1162,20 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
     __ bind(&push_receiver);
     __ push(ebx);
 
-    // Copy all arguments from the array to the stack.
-    Label entry, loop;
-    Register receiver = LoadDescriptor::ReceiverRegister();
-    Register key = LoadDescriptor::NameRegister();
-    __ mov(key, Operand(ebp, kIndexOffset));
-    __ jmp(&entry);
-    __ bind(&loop);
-    __ mov(receiver, Operand(ebp, kArgumentsOffset));  // load arguments
-
-    if (FLAG_vector_ics) {
-      // 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.
-    }
-
-    // Push the nth argument.
-    __ push(eax);
-
-    // Update the index on the stack and in register key.
-    __ mov(key, Operand(ebp, kIndexOffset));
-    __ add(key, Immediate(1 << kSmiTagSize));
-    __ mov(Operand(ebp, kIndexOffset), key);
-
-    __ bind(&entry);
-    __ cmp(key, Operand(ebp, kLimitOffset));
-    __ j(not_equal, &loop);
+    // Loop over the arguments array, pushing each value to the stack
+    Generate_PushAppliedArguments(
+        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
 
     // Call the function.
     Label call_proxy;
     ParameterCount actual(eax);
-    __ Move(eax, key);
-    __ SmiUntag(eax);
     __ mov(edi, Operand(ebp, kFunctionOffset));
     __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
     __ j(not_equal, &call_proxy);
     __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper());
 
     frame_scope.GenerateLeaveFrame();
-    __ ret(3 * kPointerSize);  // remove this, receiver, and arguments
+    __ ret(kStackSize * kPointerSize);  // remove this, receiver, and arguments
 
     // Call the function proxy.
     __ bind(&call_proxy);
@@ -1149,7 +1188,92 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
 
     // Leave internal frame.
   }
-  __ ret(3 * kPointerSize);  // remove this, receiver, and arguments
+  __ ret(kStackSize * kPointerSize);  // remove this, receiver, and arguments
+}
+
+
+// Used by ReflectConstruct
+static void Generate_ConstructHelper(MacroAssembler* masm) {
+  const int kFormalParameters = 3;
+  const int kStackSize = kFormalParameters + 1;
+
+  // Stack at entry:
+  // esp     : return address
+  // esp[4]  : original constructor (new.target)
+  // esp[8]  : arguments
+  // esp[16] : constructor
+  {
+    FrameScope frame_scope(masm, StackFrame::INTERNAL);
+    // Stack frame:
+    // ebp     : Old base pointer
+    // ebp[4]  : return address
+    // ebp[8]  : original constructor (new.target)
+    // ebp[12] : arguments
+    // ebp[16] : constructor
+    static const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize;
+    static const int kArgumentsOffset = kNewTargetOffset + kPointerSize;
+    static const int kFunctionOffset = kArgumentsOffset + kPointerSize;
+
+    // If newTarget is not supplied, set it to constructor
+    Label validate_arguments;
+    __ mov(eax, Operand(ebp, kNewTargetOffset));
+    __ CompareRoot(eax, Heap::kUndefinedValueRootIndex);
+    __ j(not_equal, &validate_arguments, Label::kNear);
+    __ mov(eax, Operand(ebp, kFunctionOffset));
+    __ mov(Operand(ebp, kNewTargetOffset), eax);
+
+    // Validate arguments
+    __ bind(&validate_arguments);
+    __ push(Operand(ebp, kFunctionOffset));
+    __ push(Operand(ebp, kArgumentsOffset));
+    __ push(Operand(ebp, kNewTargetOffset));
+    __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION);
+
+    Generate_CheckStackOverflow(masm, kFunctionOffset);
+
+    // Push current index and limit.
+    const int kLimitOffset =
+        StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
+    const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
+    __ Push(eax);  // limit
+    __ push(Immediate(0));  // index
+    // Push newTarget and callee functions
+    __ push(Operand(ebp, kNewTargetOffset));
+    __ push(Operand(ebp, kFunctionOffset));
+
+    // Loop over the arguments array, pushing each value to the stack
+    Generate_PushAppliedArguments(
+        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
+
+    // Use undefined feedback vector
+    __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
+    __ mov(edi, Operand(ebp, kFunctionOffset));
+
+    // Call the function.
+    CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
+    __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
+
+    __ Drop(1);
+
+    // Leave internal frame.
+  }
+  // remove this, target, arguments, and newTarget
+  __ ret(kStackSize * kPointerSize);
+}
+
+
+void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+  Generate_ApplyHelper(masm, false);
+}
+
+
+void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
+  Generate_ApplyHelper(masm, true);
+}
+
+
+void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
+  Generate_ConstructHelper(masm);
 }
 
 
index 58200bc..841e0f1 100644 (file)
@@ -12,6 +12,7 @@
 #include "src/codegen.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
@@ -410,7 +411,7 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
   __ ret(0);
 
   StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
+  char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&miss);
   PropertyAccessCompiler::TailCallBuiltin(
@@ -759,8 +760,15 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
   __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
 
   if (has_new_target()) {
+    // If the constructor was [[Call]]ed, the call will not push a new.target
+    // onto the stack. In that case the arguments array we construct is bogus,
+    // bu we do not care as the constructor throws immediately.
+    __ cmp(ecx, Immediate(Smi::FromInt(0)));
+    Label skip_decrement;
+    __ j(equal, &skip_decrement);
     // Subtract 1 from smi-tagged arguments count.
     __ sub(ecx, Immediate(2));
+    __ bind(&skip_decrement);
   }
 
   __ lea(edx, Operand(edx, ecx, times_2,
@@ -870,7 +878,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   // 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);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 #else  // V8_INTERPRETED_REGEXP
 
   // Stack frame on entry.
@@ -1146,22 +1154,9 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   __ mov(eax, Operand::StaticVariable(pending_exception));
   __ cmp(edx, eax);
   __ j(equal, &runtime);
-  // For exception, throw the exception again.
-
-  // Clear the pending exception variable.
-  __ mov(Operand::StaticVariable(pending_exception), edx);
 
-  // Special handling of termination exceptions which are uncatchable
-  // by javascript code.
-  __ cmp(eax, factory->termination_exception());
-  Label throw_termination_exception;
-  __ j(equal, &throw_termination_exception, Label::kNear);
-
-  // Handle normal exception by following handler chain.
-  __ Throw(eax);
-
-  __ bind(&throw_termination_exception);
-  __ ThrowUncatchable(eax);
+  // For exception, throw the exception again.
+  __ TailCallRuntime(Runtime::kRegExpExecReThrow, 4, 1);
 
   __ bind(&failure);
   // For failure to match, return null.
@@ -1247,7 +1242,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
 
   // Do the runtime call to execute the regexp.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
+  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
 
   // Deferred code for string handling.
   // (7) Not a long external string?  If yes, go to (10).
@@ -2208,15 +2203,14 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   __ cmp(eax, isolate()->factory()->exception());
   __ j(equal, &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) {
     __ push(edx);
     __ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
     Label okay;
+    ExternalReference pending_exception_address(
+        Isolate::kPendingExceptionAddress, isolate());
     __ cmp(edx, Operand::StaticVariable(pending_exception_address));
     // Cannot use check here as it attempts to generate call into runtime.
     __ j(equal, &okay, Label::kNear);
@@ -2232,24 +2226,48 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // Handling of exception.
   __ bind(&exception_returned);
 
-  // Retrieve the pending exception.
-  __ mov(eax, Operand::StaticVariable(pending_exception_address));
-
-  // Clear the pending exception.
-  __ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
-  __ mov(Operand::StaticVariable(pending_exception_address), edx);
-
-  // Special handling of termination exceptions which are uncatchable
-  // by javascript code.
-  Label throw_termination_exception;
-  __ cmp(eax, isolate()->factory()->termination_exception());
-  __ j(equal, &throw_termination_exception);
-
-  // Handle normal exception.
-  __ Throw(eax);
+  ExternalReference pending_handler_context_address(
+      Isolate::kPendingHandlerContextAddress, isolate());
+  ExternalReference pending_handler_code_address(
+      Isolate::kPendingHandlerCodeAddress, isolate());
+  ExternalReference pending_handler_offset_address(
+      Isolate::kPendingHandlerOffsetAddress, isolate());
+  ExternalReference pending_handler_fp_address(
+      Isolate::kPendingHandlerFPAddress, isolate());
+  ExternalReference pending_handler_sp_address(
+      Isolate::kPendingHandlerSPAddress, isolate());
+
+  // Ask the runtime for help to determine the handler. This will set eax to
+  // contain the current pending exception, don't clobber it.
+  ExternalReference find_handler(Runtime::kFindExceptionHandler, isolate());
+  {
+    FrameScope scope(masm, StackFrame::MANUAL);
+    __ PrepareCallCFunction(3, eax);
+    __ mov(Operand(esp, 0 * kPointerSize), Immediate(0));  // argc.
+    __ mov(Operand(esp, 1 * kPointerSize), Immediate(0));  // argv.
+    __ mov(Operand(esp, 2 * kPointerSize),
+           Immediate(ExternalReference::isolate_address(isolate())));
+    __ CallCFunction(find_handler, 3);
+  }
 
-  __ bind(&throw_termination_exception);
-  __ ThrowUncatchable(eax);
+  // Retrieve the handler context, SP and FP.
+  __ mov(esi, Operand::StaticVariable(pending_handler_context_address));
+  __ mov(esp, Operand::StaticVariable(pending_handler_sp_address));
+  __ mov(ebp, Operand::StaticVariable(pending_handler_fp_address));
+
+  // If the handler is a JS frame, restore the context to the frame. Note that
+  // the context will be set to (esi == 0) for non-JS frames.
+  Label skip;
+  __ test(esi, esi);
+  __ j(zero, &skip, Label::kNear);
+  __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
+  __ bind(&skip);
+
+  // Compute the handler entry address and jump to it.
+  __ mov(edi, Operand::StaticVariable(pending_handler_code_address));
+  __ mov(edx, Operand::StaticVariable(pending_handler_offset_address));
+  __ lea(edi, FieldOperand(edi, edx, times_1, Code::kHeaderSize));
+  __ jmp(edi);
 }
 
 
@@ -2299,10 +2317,9 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ mov(eax, Immediate(isolate()->factory()->exception()));
   __ jmp(&exit);
 
-  // Invoke: Link this frame into the handler chain.  There's only one
-  // handler block in this code object, so its index is 0.
+  // Invoke: Link this frame into the handler chain.
   __ bind(&invoke);
-  __ PushTryHandler(StackHandler::JS_ENTRY, 0);
+  __ PushStackHandler();
 
   // Clear any pending exceptions.
   __ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
@@ -2328,7 +2345,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
   __ call(edx);
 
   // Unlink this frame from the handler chain.
-  __ PopTryHandler();
+  __ PopStackHandler();
 
   __ bind(&exit);
   // Check if the current stack frame is marked as the outermost JS frame.
@@ -2614,7 +2631,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
 
 
 void StringCharCodeAtGenerator::GenerateSlow(
-    MacroAssembler* masm,
+    MacroAssembler* masm, EmbedMode embed_mode,
     const RuntimeCallHelper& call_helper) {
   __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
 
@@ -2626,6 +2643,10 @@ void StringCharCodeAtGenerator::GenerateSlow(
               index_not_number_,
               DONT_DO_SMI_CHECK);
   call_helper.BeforeCall(masm);
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ push(VectorLoadICDescriptor::VectorRegister());
+    __ push(VectorLoadICDescriptor::SlotRegister());
+  }
   __ push(object_);
   __ push(index_);  // Consumed by runtime conversion function.
   if (index_flags_ == STRING_INDEX_IS_NUMBER) {
@@ -2641,6 +2662,10 @@ void StringCharCodeAtGenerator::GenerateSlow(
     __ mov(index_, eax);
   }
   __ pop(object_);
+  if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
+    __ pop(VectorLoadICDescriptor::SlotRegister());
+    __ pop(VectorLoadICDescriptor::VectorRegister());
+  }
   // Reload the instance type.
   __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
   __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
@@ -2956,7 +2981,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
 
   // Just jump to runtime to create the sub string.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kSubString, 3, 1);
+  __ TailCallRuntime(Runtime::kSubStringRT, 3, 1);
 
   __ bind(&single_char);
   // eax: string
@@ -3179,7 +3204,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
   // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
   // tagged as a small integer.
   __ bind(&runtime);
-  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+  __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
 }
 
 
@@ -3240,7 +3265,7 @@ void CompareICStub::GenerateSmis(MacroAssembler* masm) {
 void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
   DCHECK(state() == CompareICState::NUMBER);
 
-  Label generic_stub;
+  Label generic_stub, check_left;
   Label unordered, maybe_undefined1, maybe_undefined2;
   Label miss;
 
@@ -3253,13 +3278,13 @@ void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
 
   // Inlining the double comparison and falling back to the general compare
   // stub if NaN is involved or SSE2 or CMOV is unsupported.
-  __ mov(ecx, edx);
-  __ and_(ecx, eax);
-  __ JumpIfSmi(ecx, &generic_stub, Label::kNear);
-
+  __ JumpIfSmi(eax, &check_left, Label::kNear);
   __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
          isolate()->factory()->heap_number_map());
   __ j(not_equal, &maybe_undefined1, Label::kNear);
+
+  __ bind(&check_left);
+  __ JumpIfSmi(edx, &generic_stub, Label::kNear);
   __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
          isolate()->factory()->heap_number_map());
   __ j(not_equal, &maybe_undefined2, Label::kNear);
@@ -3463,7 +3488,7 @@ void CompareICStub::GenerateStrings(MacroAssembler* masm) {
   if (equality) {
     __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
   } else {
-    __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+    __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
   }
 
   __ bind(&miss);
@@ -4041,15 +4066,234 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
 
 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorLoadStub stub(isolate(), state());
-  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawLoadStub stub(isolate(), state());
+  stub.GenerateForTrampoline(masm);
 }
 
 
 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorKeyedLoadStub stub(isolate());
-  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawKeyedLoadStub stub(isolate());
+  stub.GenerateForTrampoline(masm);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+                             Register key, Register vector, Register slot,
+                             Register feedback, bool is_polymorphic,
+                             Label* miss) {
+  // feedback initially contains the feedback array
+  Label next, next_loop, prepare_next;
+  Label load_smi_map, compare_map;
+  Label start_polymorphic;
+
+  __ push(receiver);
+  __ push(vector);
+
+  Register receiver_map = receiver;
+  Register cached_map = vector;
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &load_smi_map);
+  __ mov(receiver_map, FieldOperand(receiver, 0));
+  __ bind(&compare_map);
+  __ mov(cached_map, FieldOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+
+  // A named keyed load might have a 2 element array, all other cases can count
+  // on an array with at least 2 {map, handler} pairs, so they can go right
+  // into polymorphic array handling.
+  __ cmp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
+  __ j(not_equal, is_polymorphic ? &start_polymorphic : &next);
+
+  // found, now call handler.
+  Register handler = feedback;
+  __ mov(handler, FieldOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+  __ pop(vector);
+  __ pop(receiver);
+  __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+
+  if (!is_polymorphic) {
+    __ bind(&next);
+    __ cmp(FieldOperand(feedback, FixedArray::kLengthOffset),
+           Immediate(Smi::FromInt(2)));
+    __ j(not_equal, &start_polymorphic);
+    __ pop(vector);
+    __ pop(receiver);
+    __ jmp(miss);
+  }
+
+  // Polymorphic, we have to loop from 2 to N
+  __ bind(&start_polymorphic);
+  __ push(key);
+  Register counter = key;
+  __ mov(counter, Immediate(Smi::FromInt(2)));
+  __ bind(&next_loop);
+  __ mov(cached_map, FieldOperand(feedback, counter, times_half_pointer_size,
+                                  FixedArray::kHeaderSize));
+  __ cmp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
+  __ j(not_equal, &prepare_next);
+  __ mov(handler, FieldOperand(feedback, counter, times_half_pointer_size,
+                               FixedArray::kHeaderSize + kPointerSize));
+  __ pop(key);
+  __ pop(vector);
+  __ pop(receiver);
+  __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+
+  __ bind(&prepare_next);
+  __ add(counter, Immediate(Smi::FromInt(2)));
+  __ cmp(counter, FieldOperand(feedback, FixedArray::kLengthOffset));
+  __ j(less, &next_loop);
+
+  // We exhausted our array of map handler pairs.
+  __ pop(key);
+  __ pop(vector);
+  __ pop(receiver);
+  __ jmp(miss);
+
+  __ bind(&load_smi_map);
+  __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
+  __ jmp(&compare_map);
+}
+
+
+static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+                                  Register key, Register vector, Register slot,
+                                  Register weak_cell, Label* miss) {
+  // feedback initially contains the feedback array
+  Label compare_smi_map;
+
+  // Move the weak map into the weak_cell register.
+  Register ic_map = weak_cell;
+  __ mov(ic_map, FieldOperand(weak_cell, WeakCell::kValueOffset));
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &compare_smi_map);
+  __ cmp(ic_map, FieldOperand(receiver, 0));
+  __ j(not_equal, miss);
+  Register handler = weak_cell;
+  __ mov(handler, FieldOperand(vector, slot, times_half_pointer_size,
+                               FixedArray::kHeaderSize + kPointerSize));
+  __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+
+  // In microbenchmarks, it made sense to unroll this code so that the call to
+  // the handler is duplicated for a HeapObject receiver and a Smi receiver.
+  __ bind(&compare_smi_map);
+  __ CompareRoot(ic_map, Heap::kHeapNumberMapRootIndex);
+  __ j(not_equal, miss);
+  __ mov(handler, FieldOperand(vector, slot, times_half_pointer_size,
+                               FixedArray::kHeaderSize + kPointerSize));
+  __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+}
+
+
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // edx
+  Register name = VectorLoadICDescriptor::NameRegister();          // ecx
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // ebx
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // eax
+  Register scratch = edi;
+  __ mov(scratch, FieldOperand(vector, slot, times_half_pointer_size,
+                               FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ CompareRoot(FieldOperand(scratch, 0), Heap::kWeakCellMapRootIndex);
+  __ j(not_equal, &try_array);
+  HandleMonomorphicCase(masm, receiver, name, vector, slot, scratch, &miss);
+
+  // Is it a fixed array?
+  __ bind(&try_array);
+  __ CompareRoot(FieldOperand(scratch, 0), Heap::kFixedArrayMapRootIndex);
+  __ j(not_equal, &not_array);
+  HandleArrayCases(masm, receiver, name, vector, slot, scratch, true, &miss);
+
+  __ bind(&not_array);
+  __ CompareRoot(scratch, Heap::kmegamorphic_symbolRootIndex);
+  __ j(not_equal, &miss);
+  __ push(slot);
+  __ push(vector);
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::LOAD_IC, code_flags, false, receiver, name, vector, scratch);
+  __ pop(vector);
+  __ pop(slot);
+
+  __ bind(&miss);
+  LoadIC::GenerateMiss(masm);
+}
+
+
+void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // edx
+  Register key = VectorLoadICDescriptor::NameRegister();           // ecx
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // ebx
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // eax
+  Register feedback = edi;
+  __ mov(feedback, FieldOperand(vector, slot, times_half_pointer_size,
+                                FixedArray::kHeaderSize));
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ CompareRoot(FieldOperand(feedback, 0), Heap::kWeakCellMapRootIndex);
+  __ j(not_equal, &try_array);
+  HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, &miss);
+
+  __ bind(&try_array);
+  // Is it a fixed array?
+  __ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
+  __ j(not_equal, &not_array);
+
+  // We have a polymorphic element handler.
+  Label polymorphic, try_poly_name;
+  __ bind(&polymorphic);
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, true, &miss);
+
+  __ bind(&not_array);
+  // Is it generic?
+  __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+  __ j(not_equal, &try_poly_name);
+  Handle<Code> megamorphic_stub =
+      KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+  __ jmp(megamorphic_stub, RelocInfo::CODE_TARGET);
+
+  __ bind(&try_poly_name);
+  // We might have a name in feedback, and a fixed array in the next slot.
+  __ cmp(key, feedback);
+  __ j(not_equal, &miss);
+  // If the name comparison succeeded, we know we have a fixed array with
+  // at least one map/handler pair.
+  __ mov(feedback, FieldOperand(vector, slot, times_half_pointer_size,
+                                FixedArray::kHeaderSize + kPointerSize));
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, false, &miss);
+
+  __ bind(&miss);
+  KeyedLoadIC::GenerateMiss(masm);
 }
 
 
@@ -4535,7 +4779,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
   __ mov(eax, return_value_operand);
 
   Label promote_scheduled_exception;
-  Label exception_handled;
   Label delete_allocated_handles;
   Label leave_exit_frame;
 
@@ -4547,7 +4790,17 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
   __ Assert(above_equal, kInvalidHandleScopeLevel);
   __ cmp(edi, Operand::StaticVariable(limit_address));
   __ j(not_equal, &delete_allocated_handles);
+
+  // Leave the API exit frame.
   __ bind(&leave_exit_frame);
+  bool restore_context = context_restore_operand != NULL;
+  if (restore_context) {
+    __ mov(esi, *context_restore_operand);
+  }
+  if (stack_space_operand != nullptr) {
+    __ mov(ebx, *stack_space_operand);
+  }
+  __ LeaveApiExitFrame(!restore_context);
 
   // Check if the function scheduled an exception.
   ExternalReference scheduled_exception_address =
@@ -4555,7 +4808,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
   __ cmp(Operand::StaticVariable(scheduled_exception_address),
          Immediate(isolate->factory()->the_hole_value()));
   __ j(not_equal, &promote_scheduled_exception);
-  __ bind(&exception_handled);
 
 #if DEBUG
   // Check if the function returned a valid JavaScript value.
@@ -4592,14 +4844,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
   __ bind(&ok);
 #endif
 
-  bool restore_context = context_restore_operand != NULL;
-  if (restore_context) {
-    __ mov(esi, *context_restore_operand);
-  }
-  if (stack_space_operand != nullptr) {
-    __ mov(ebx, *stack_space_operand);
-  }
-  __ LeaveApiExitFrame(!restore_context);
   if (stack_space_operand != nullptr) {
     DCHECK_EQ(0, stack_space);
     __ pop(ecx);
@@ -4609,12 +4853,9 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
     __ ret(stack_space * kPointerSize);
   }
 
+  // Re-throw by promoting a scheduled exception.
   __ bind(&promote_scheduled_exception);
-  {
-    FrameScope frame(masm, StackFrame::INTERNAL);
-    __ CallRuntime(Runtime::kPromoteScheduledException, 0);
-  }
-  __ jmp(&exception_handled);
+  __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
 
   // HandleScope limit has changed. Delete allocated extensions.
   ExternalReference delete_extensions =
index cdbcbad..0bbee14 100644 (file)
 namespace v8 {
 namespace internal {
 
-bool BreakLocationIterator::IsDebugBreakAtReturn() {
-  return Debug::IsDebugBreakAtReturn(rinfo());
-}
+// Patch the code at the current PC with a call to the target address.
+// Additional guard int3 instructions can be added if required.
+void PatchCodeWithCall(Address pc, Address target, int guard_bytes) {
+  // Call instruction takes up 5 bytes and int3 takes up one byte.
+  static const int kCallCodeSize = 5;
+  int code_size = kCallCodeSize + guard_bytes;
 
+  // Create a code patcher.
+  CodePatcher patcher(pc, code_size);
 
-// Patch the JS frame exit code with a debug break call. See
-// CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x87.cc
-// for the precise return instructions sequence.
-void BreakLocationIterator::SetDebugBreakAtReturn() {
-  DCHECK(Assembler::kJSReturnSequenceLength >=
-         Assembler::kCallInstructionLength);
-  rinfo()->PatchCodeWithCall(
-      debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
-      Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
-}
+// Add a label for checking the size of the code used for returning.
+#ifdef DEBUG
+  Label check_codesize;
+  patcher.masm()->bind(&check_codesize);
+#endif
 
+  // Patch the code.
+  patcher.masm()->call(target, RelocInfo::NONE32);
 
-// Restore the JS frame exit code.
-void BreakLocationIterator::ClearDebugBreakAtReturn() {
-  rinfo()->PatchCode(original_rinfo()->pc(),
-                     Assembler::kJSReturnSequenceLength);
-}
+  // Check that the size of the code generated is as expected.
+  DCHECK_EQ(kCallCodeSize,
+            patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
 
+  // Add the requested number of int3 instructions after the call.
+  DCHECK_GE(guard_bytes, 0);
+  for (int i = 0; i < guard_bytes; i++) {
+    patcher.masm()->int3();
+  }
 
-// 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();
+  CpuFeatures::FlushICache(pc, code_size);
 }
 
 
-bool BreakLocationIterator::IsDebugBreakAtSlot() {
-  DCHECK(IsDebugBreakSlot());
-  // Check whether the debug break slot instructions have been patched.
-  return rinfo()->IsPatchedDebugBreakSlotSequence();
+// Patch the JS frame exit code with a debug break call. See
+// CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x87.cc
+// for the precise return instructions sequence.
+void BreakLocation::SetDebugBreakAtReturn() {
+  DCHECK(Assembler::kJSReturnSequenceLength >=
+         Assembler::kCallInstructionLength);
+  PatchCodeWithCall(
+      pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
+      Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
 }
 
 
-void BreakLocationIterator::SetDebugBreakAtSlot() {
+void BreakLocation::SetDebugBreakAtSlot() {
   DCHECK(IsDebugBreakSlot());
   Isolate* isolate = debug_info_->GetIsolate();
-  rinfo()->PatchCodeWithCall(
-      isolate->builtins()->Slot_DebugBreak()->entry(),
+  PatchCodeWithCall(
+      pc(), isolate->builtins()->Slot_DebugBreak()->entry(),
       Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength);
 }
 
 
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
-  DCHECK(IsDebugBreakSlot());
-  rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
-}
-
-
 #define __ ACCESS_MASM(masm)
 
 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
index ffd2fa8..edc08ab 100644 (file)
@@ -228,7 +228,7 @@ bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
 
 #define __ masm()->
 
-void Deoptimizer::EntryGenerator::Generate() {
+void Deoptimizer::TableEntryGenerator::Generate() {
   GeneratePrologue();
 
   // Save all general purpose registers before messing with them.
index 5b91baf..e3876bc 100644 (file)
@@ -115,11 +115,6 @@ inline Object* JavaScriptFrame::function_slot_object() const {
 }
 
 
-inline void StackHandler::SetFp(Address slot, Address fp) {
-  Memory::Address_at(slot) = fp;
-}
-
-
 } }  // namespace v8::internal
 
 #endif  // V8_X87_FRAMES_X87_H_
index 4ec21ae..59ff09f 100644 (file)
@@ -95,7 +95,8 @@ class JumpPatchSite BASE_EMBEDDED {
 void FullCodeGenerator::Generate() {
   CompilationInfo* info = info_;
   handler_table_ =
-      isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
+      Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray(
+          HandlerTable::LengthForRange(function()->handler_count()), TENURED));
 
   profiling_counter_ = isolate()->factory()->NewCell(
       Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
@@ -188,7 +189,7 @@ void FullCodeGenerator::Generate() {
     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_script_scope()) {
+    if (info->scope()->is_script_scope()) {
       __ push(edi);
       __ Push(info->scope()->GetScopeInfo(info->isolate()));
       __ CallRuntime(Runtime::kNewScriptContext, 2);
@@ -233,6 +234,11 @@ void FullCodeGenerator::Generate() {
     }
   }
 
+  ArgumentsAccessStub::HasNewTarget has_new_target =
+      IsSubclassConstructor(info->function()->kind())
+          ? ArgumentsAccessStub::HAS_NEW_TARGET
+          : ArgumentsAccessStub::NO_NEW_TARGET;
+
   // Possibly allocate RestParameters
   int rest_index;
   Variable* rest_param = scope()->rest_parameter(&rest_index);
@@ -241,6 +247,11 @@ void FullCodeGenerator::Generate() {
 
     int num_parameters = info->scope()->num_parameters();
     int offset = num_parameters * kPointerSize;
+    if (has_new_target == ArgumentsAccessStub::HAS_NEW_TARGET) {
+      --num_parameters;
+      ++rest_index;
+    }
+
     __ lea(edx,
            Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
     __ push(edx);
@@ -281,10 +292,7 @@ void FullCodeGenerator::Generate() {
     } else {
       type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
     }
-    ArgumentsAccessStub::HasNewTarget has_new_target =
-        IsSubclassConstructor(info->function()->kind())
-            ? ArgumentsAccessStub::HAS_NEW_TARGET
-            : ArgumentsAccessStub::NO_NEW_TARGET;
+
     ArgumentsAccessStub stub(isolate(), type, has_new_target);
     __ CallStub(&stub);
 
@@ -1442,7 +1450,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
                Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
       }
-      CallLoadIC(CONTEXTUAL);
+      CallGlobalLoadIC(var->name());
       context()->Plug(eax);
       break;
     }
@@ -2101,7 +2109,6 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
 
       // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
       __ bind(&l_catch);
-      handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
       __ mov(load_name, isolate()->factory()->throw_string());  // "throw"
       __ push(load_name);                                       // "throw"
       __ push(Operand(esp, 2 * kPointerSize));                  // iter
@@ -2113,16 +2120,17 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       // re-boxing.
       __ bind(&l_try);
       __ pop(eax);                                       // result
-      __ PushTryHandler(StackHandler::CATCH, expr->index());
-      const int handler_size = StackHandlerConstants::kSize;
+      EnterTryBlock(expr->index(), &l_catch);
+      const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ push(eax);                                      // result
       __ jmp(&l_suspend);
       __ bind(&l_continuation);
       __ jmp(&l_resume);
       __ bind(&l_suspend);
-      const int generator_object_depth = kPointerSize + handler_size;
+      const int generator_object_depth = kPointerSize + try_block_size;
       __ mov(eax, Operand(esp, generator_object_depth));
       __ push(eax);                                      // g
+      __ push(Immediate(Smi::FromInt(expr->index())));   // handler-index
       DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
       __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
              Immediate(Smi::FromInt(l_continuation.pos())));
@@ -2130,13 +2138,13 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       __ mov(ecx, esi);
       __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
                           kDontSaveFPRegs);
-      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 2);
       __ mov(context_register(),
              Operand(ebp, StandardFrameConstants::kContextOffset));
       __ pop(eax);                                       // result
       EmitReturnSequence();
       __ bind(&l_resume);                                // received in eax
-      __ PopTryHandler();
+      ExitTryBlock(expr->index());
 
       // receiver = iter; f = iter.next; arg = received;
       __ bind(&l_next);
@@ -2482,6 +2490,16 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
       __ push(Operand(esp, 0));  // prototype
     }
     EmitPropertyKey(property, lit->GetIdForProperty(i));
+
+    // The static prototype property is read only. We handle the non computed
+    // property name case in the parser. Since this is the only case where we
+    // need to check for an own read only property we special case this so we do
+    // not need to do this for every property.
+    if (property->is_static() && property->is_computed_name()) {
+      __ CallRuntime(Runtime::kThrowIfStaticPrototype, 1);
+      __ push(eax);
+    }
+
     VisitForStackValue(value);
     EmitSetHomeObjectIfNeeded(value, 2);
 
@@ -2619,25 +2637,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
     __ mov(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(eax);
-      __ push(esi);
-      __ push(Immediate(var->name()));
-      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
-    } else {
-      DCHECK(var->IsStackLocal() || var->IsContextSlot());
-      Label skip;
-      MemOperand location = VarOperand(var, ecx);
-      __ mov(edx, location);
-      __ cmp(edx, isolate()->factory()->the_hole_value());
-      __ j(not_equal, &skip, Label::kNear);
-      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());
@@ -2651,6 +2650,21 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
     __ CallRuntime(Runtime::kThrowReferenceError, 1);
     __ bind(&assign);
     EmitStoreToStackLocalOrContextSlot(var, location);
+
+  } else if (var->mode() == CONST && op != Token::INIT_CONST) {
+    // Assignment to const variable needs a write barrier.
+    DCHECK(!var->IsLookupSlot());
+    DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+    Label const_error;
+    MemOperand location = VarOperand(var, ecx);
+    __ mov(edx, location);
+    __ cmp(edx, isolate()->factory()->the_hole_value());
+    __ j(not_equal, &const_error, Label::kNear);
+    __ push(Immediate(var->name()));
+    __ CallRuntime(Runtime::kThrowReferenceError, 1);
+    __ bind(&const_error);
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
   } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
     if (var->IsLookupSlot()) {
       // Assignment to var.
@@ -2672,8 +2686,33 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
-  } else if (IsSignallingAssignmentToConst(var, op, language_mode())) {
-    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+
+  } else if (op == Token::INIT_CONST_LEGACY) {
+    // Const initializers need a write barrier.
+    DCHECK(var->mode() == CONST_LEGACY);
+    DCHECK(!var->IsParameter());  // No const parameters.
+    if (var->IsLookupSlot()) {
+      __ push(eax);
+      __ push(esi);
+      __ push(Immediate(var->name()));
+      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
+    } else {
+      DCHECK(var->IsStackLocal() || var->IsContextSlot());
+      Label skip;
+      MemOperand location = VarOperand(var, ecx);
+      __ mov(edx, location);
+      __ cmp(edx, isolate()->factory()->the_hole_value());
+      __ j(not_equal, &skip, Label::kNear);
+      EmitStoreToStackLocalOrContextSlot(var, location);
+      __ bind(&skip);
+    }
+
+  } else {
+    DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT_CONST_LEGACY);
+    if (is_strict(language_mode())) {
+      __ CallRuntime(Runtime::kThrowConstAssignError, 0);
+    }
+    // Silently ignore store in sloppy mode.
   }
 }
 
@@ -3141,8 +3180,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
 
 
 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
-  if (!ValidateSuperCall(expr)) return;
-
   Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
   GetVar(eax, new_target_var);
   __ push(eax);
@@ -3654,8 +3691,8 @@ void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 
   // Check if the constructor in the map is a JS function.
-  __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
-  __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
+  __ GetMapConstructor(eax, eax, ebx);
+  __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
   __ j(not_equal, &non_function_constructor);
 
   // eax now contains the constructor function. Grab the
@@ -3957,7 +3994,7 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
   __ jmp(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&done);
   context()->Plug(result);
@@ -4005,7 +4042,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
   __ jmp(&done);
 
   NopRuntimeCallHelper call_helper;
-  generator.GenerateSlow(masm_, call_helper);
+  generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
 
   __ bind(&done);
   context()->Plug(result);
@@ -4177,7 +4214,7 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
   // Call runtime to perform the lookup.
   __ push(cache);
   __ push(key);
-  __ CallRuntime(Runtime::kGetFromCache, 2);
+  __ CallRuntime(Runtime::kGetFromCacheRT, 2);
 
   __ bind(&done);
   context()->Plug(eax);
@@ -4497,17 +4534,11 @@ void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
 
 
 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()) {
+    Comment cmnt(masm_, "[ CallRuntime");
     // Push the builtins object as receiver.
     __ mov(eax, GlobalObjectOperand());
     __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
@@ -4527,9 +4558,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     __ push(Operand(esp, 0));
     __ mov(Operand(esp, kPointerSize), eax);
 
-    // Code common for calls using the IC.
-    ZoneList<Expression*>* args = expr->arguments();
-    int arg_count = args->length();
+    // Push the arguments ("left-to-right").
     for (int i = 0; i < arg_count; i++) {
       VisitForStackValue(args->at(i));
     }
@@ -4544,16 +4573,27 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     context()->DropAndPlug(1, eax);
 
   } else {
-    // Push the arguments ("left-to-right").
-    int arg_count = args->length();
-    for (int i = 0; i < arg_count; i++) {
-      VisitForStackValue(args->at(i));
-    }
-
-    // Call the C runtime function.
-    __ CallRuntime(expr->function(), arg_count);
+    const Runtime::Function* function = expr->function();
+    switch (function->function_id) {
+#define CALL_INTRINSIC_GENERATOR(Name)     \
+  case Runtime::kInline##Name: {           \
+    Comment cmnt(masm_, "[ Inline" #Name); \
+    return Emit##Name(expr);               \
+  }
+      FOR_EACH_FULL_CODE_INTRINSIC(CALL_INTRINSIC_GENERATOR)
+#undef CALL_INTRINSIC_GENERATOR
+      default: {
+        Comment cmnt(masm_, "[ CallRuntime for unhandled intrinsic");
+        // Push the arguments ("left-to-right").
+        for (int i = 0; i < arg_count; i++) {
+          VisitForStackValue(args->at(i));
+        }
 
-    context()->Plug(eax);
+        // Call the C runtime function.
+        __ CallRuntime(expr->function(), arg_count);
+        context()->Plug(eax);
+      }
+    }
   }
 }
 
@@ -5205,17 +5245,6 @@ void FullCodeGenerator::EnterFinallyBlock() {
       ExternalReference::address_of_pending_message_obj(isolate());
   __ mov(edx, Operand::StaticVariable(pending_message_obj));
   __ push(edx);
-
-  ExternalReference has_pending_message =
-      ExternalReference::address_of_has_pending_message(isolate());
-  __ mov(edx, Operand::StaticVariable(has_pending_message));
-  __ SmiTag(edx);
-  __ push(edx);
-
-  ExternalReference pending_message_script =
-      ExternalReference::address_of_pending_message_script(isolate());
-  __ mov(edx, Operand::StaticVariable(pending_message_script));
-  __ push(edx);
 }
 
 
@@ -5223,17 +5252,6 @@ void FullCodeGenerator::ExitFinallyBlock() {
   DCHECK(!result_register().is(edx));
   // Restore pending message from stack.
   __ pop(edx);
-  ExternalReference pending_message_script =
-      ExternalReference::address_of_pending_message_script(isolate());
-  __ mov(Operand::StaticVariable(pending_message_script), edx);
-
-  __ pop(edx);
-  __ SmiUntag(edx);
-  ExternalReference has_pending_message =
-      ExternalReference::address_of_has_pending_message(isolate());
-  __ mov(Operand::StaticVariable(has_pending_message), edx);
-
-  __ pop(edx);
   ExternalReference pending_message_obj =
       ExternalReference::address_of_pending_message_obj(isolate());
   __ mov(Operand::StaticVariable(pending_message_obj), edx);
@@ -5251,33 +5269,6 @@ void FullCodeGenerator::ExitFinallyBlock() {
 
 #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.
-    __ mov(esi, Operand(esp, StackHandlerConstants::kContextOffset));
-    __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
-  }
-  __ PopTryHandler();
-  __ call(finally_entry_);
-
-  *stack_depth = 0;
-  *context_length = 0;
-  return previous_;
-}
-
-#undef __
-
 
 static const byte kJnsInstruction = 0x79;
 static const byte kJnsOffset = 0x11;
index c9ef8d1..506ed47 100644 (file)
@@ -228,6 +228,12 @@ void InternalArrayConstructorDescriptor::Initialize(
 }
 
 
+void CompareDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {esi, edx, eax};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
 void CompareNilDescriptor::Initialize(CallInterfaceDescriptorData* data) {
   Register registers[] = {esi, eax};
   data->Initialize(arraysize(registers), registers, NULL);
index 07be757..05944f9 100644 (file)
@@ -10,6 +10,7 @@
 #include "src/code-factory.h"
 #include "src/code-stubs.h"
 #include "src/codegen.h"
+#include "src/cpu-profiler.h"
 #include "src/deoptimizer.h"
 #include "src/hydrogen-osr.h"
 #include "src/ic/ic.h"
@@ -109,7 +110,7 @@ bool LCodeGen::GeneratePrologue() {
     // 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() && is_sloppy(info_->language_mode()) &&
+    if (graph()->this_has_uses() && is_sloppy(info_->language_mode()) &&
         !info_->is_native()) {
       Label ok;
       // +1 for return address.
@@ -373,10 +374,11 @@ void LCodeGen::GenerateBodyInstructionPost(LInstruction* instr) {
 
 
 bool LCodeGen::GenerateJumpTable() {
+  if (!jump_table_.length()) return !is_aborted();
+
   Label needs_frame;
-  if (jump_table_.length() > 0) {
-    Comment(";;; -------------------- Jump table --------------------");
-  }
+  Comment(";;; -------------------- Jump table --------------------");
+
   for (int i = 0; i < jump_table_.length(); i++) {
     Deoptimizer::JumpTableEntry* table_entry = &jump_table_[i];
     __ bind(&table_entry->label);
@@ -385,33 +387,57 @@ bool LCodeGen::GenerateJumpTable() {
     if (table_entry->needs_frame) {
       DCHECK(!info()->saves_caller_doubles());
       __ push(Immediate(ExternalReference::ForDeoptEntry(entry)));
-      if (needs_frame.is_bound()) {
-        __ jmp(&needs_frame);
-      } else {
-        __ bind(&needs_frame);
-        __ push(MemOperand(ebp, StandardFrameConstants::kContextOffset));
-        // 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());
-        __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
-        // Push a PC inside the function so that the deopt code can find where
-        // the deopt comes from. It doesn't have to be the precise return
-        // address of a "calling" LAZY deopt, it only has to be somewhere
-        // inside the code body.
-        Label push_approx_pc;
-        __ call(&push_approx_pc);
-        __ bind(&push_approx_pc);
-        // Push the continuation which was stashed were the ebp should
-        // be. Replace it with the saved ebp.
-        __ push(MemOperand(esp, 3 * kPointerSize));
-        __ mov(MemOperand(esp, 4 * kPointerSize), ebp);
-        __ lea(ebp, MemOperand(esp, 4 * kPointerSize));
-        __ ret(0);  // Call the continuation without clobbering registers.
-      }
+      __ call(&needs_frame);
     } else {
       __ call(entry, RelocInfo::RUNTIME_ENTRY);
     }
+    info()->LogDeoptCallPosition(masm()->pc_offset(),
+                                 table_entry->deopt_info.inlining_id);
+  }
+  if (needs_frame.is_linked()) {
+    __ bind(&needs_frame);
+
+    /* stack layout
+       4: entry address
+       3: return address  <-- esp
+       2: garbage
+       1: garbage
+       0: garbage
+    */
+    __ sub(esp, Immediate(kPointerSize));    // Reserve space for stub marker.
+    __ push(MemOperand(esp, kPointerSize));  // Copy return address.
+    __ push(MemOperand(esp, 3 * kPointerSize));  // Copy entry address.
+
+    /* stack layout
+       4: entry address
+       3: return address
+       2: garbage
+       1: return address
+       0: entry address  <-- esp
+    */
+    __ mov(MemOperand(esp, 4 * kPointerSize), ebp);  // Save ebp.
+
+    // Copy context.
+    __ mov(ebp, MemOperand(ebp, StandardFrameConstants::kContextOffset));
+    __ mov(MemOperand(esp, 3 * kPointerSize), ebp);
+    // Fill ebp with the right stack frame address.
+    __ lea(ebp, MemOperand(esp, 4 * kPointerSize));
+
+    // 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());
+    __ mov(MemOperand(esp, 2 * kPointerSize),
+           Immediate(Smi::FromInt(StackFrame::STUB)));
+
+    /* stack layout
+       4: old ebp
+       3: context pointer
+       2: stub marker
+       1: return address
+       0: entry address  <-- esp
+    */
+    __ ret(0);  // Call the continuation without clobbering registers.
   }
   return !is_aborted();
 }
@@ -1143,12 +1169,13 @@ void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
     __ bind(&done);
   }
 
-  Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position().raw(),
-                                    instr->Mnemonic(), deopt_reason);
+  Deoptimizer::DeoptInfo deopt_info = MakeDeoptInfo(instr, deopt_reason);
+
   DCHECK(info()->IsStub() || frame_is_built_);
   if (cc == no_condition && frame_is_built_) {
     DeoptComment(deopt_info);
     __ call(entry, RelocInfo::RUNTIME_ENTRY);
+    info()->LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id);
   } else {
     Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type,
                                             !frame_is_built_);
@@ -2854,9 +2881,9 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
 
   // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
   // Check if the constructor in the map is a function.
-  __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
+  __ GetMapConstructor(temp, temp, temp2);
   // Objects with a non-function constructor have class 'Object'.
-  __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
+  __ CmpInstanceType(temp2, JS_FUNCTION_TYPE);
   if (String::Equals(class_name, isolate()->factory()->Object_string())) {
     __ j(not_equal, is_true);
   } else {
@@ -3112,16 +3139,6 @@ void LCodeGen::DoReturn(LReturn* instr) {
 }
 
 
-void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
-  Register result = ToRegister(instr->result());
-  __ mov(result, Operand::ForCell(instr->hydrogen()->cell().handle()));
-  if (instr->hydrogen()->RequiresHoleCheck()) {
-    __ cmp(result, factory()->the_hole_value());
-    DeoptimizeIf(equal, instr, Deoptimizer::kHole);
-  }
-}
-
-
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
@@ -3151,30 +3168,12 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
   }
   ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
-  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode,
+                                                       PREMONOMORPHIC).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
 
-void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
-  Register value = ToRegister(instr->value());
-  Handle<PropertyCell> cell_handle = 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. We deoptimize in that case.
-  if (instr->hydrogen()->RequiresHoleCheck()) {
-    __ cmp(Operand::ForCell(cell_handle), factory()->the_hole_value());
-    DeoptimizeIf(equal, instr, Deoptimizer::kHole);
-  }
-
-  // Store the value.
-  __ mov(Operand::ForCell(cell_handle), value);
-  // Cells are always rescanned, so no write barrier here.
-}
-
-
 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
   Register context = ToRegister(instr->context());
   Register result = ToRegister(instr->result());
@@ -3281,8 +3280,9 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
   if (FLAG_vector_ics) {
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
-  Handle<Code> ic =
-      CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(
+                        isolate(), NOT_CONTEXTUAL,
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3505,7 +3505,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code();
+  Handle<Code> ic =
+      CodeFactory::KeyedLoadICInOptimizedCode(
+          isolate(), instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -4099,7 +4101,7 @@ void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
 
     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
     __ push(temp_result);
-    __ CallRuntimeSaveDoubles(Runtime::kMathSqrtRT);
+    __ CallRuntimeSaveDoubles(Runtime::kMathSqrt);
     RecordSafepointWithRegisters(instr->pointer_map(), 1,
                                  Safepoint::kNoLazyDeopt);
     __ StoreToSafepointRegisterSlot(temp_result, eax);
@@ -4263,14 +4265,8 @@ void LCodeGen::DoMathLog(LMathLog* instr) {
 void LCodeGen::DoMathClz32(LMathClz32* instr) {
   Register input = ToRegister(instr->value());
   Register result = ToRegister(instr->result());
-  Label not_zero_input;
-  __ bsr(result, input);
 
-  __ j(not_zero, &not_zero_input);
-  __ Move(result, Immediate(63));  // 63^31 == 32
-
-  __ bind(&not_zero_input);
-  __ xor_(result, Immediate(31));  // for x in [0..31], 31^x == 31-x.
+  __ Lzcnt(result, input);
 }
 
 
@@ -4570,7 +4566,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
   __ mov(StoreDescriptor::NameRegister(), instr->name());
-  Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->language_mode());
+  Handle<Code> ic =
+      StoreIC::initialize_stub(isolate(), instr->language_mode(),
+                               instr->hydrogen()->initialization_state());
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -4800,8 +4798,9 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
   DCHECK(ToRegister(instr->key()).is(StoreDescriptor::NameRegister()));
   DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
 
-  Handle<Code> ic =
-      CodeFactory::KeyedStoreIC(isolate(), instr->language_mode()).code();
+  Handle<Code> ic = CodeFactory::KeyedStoreICInOptimizedCode(
+                        isolate(), instr->language_mode(),
+                        instr->hydrogen()->initialization_state()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
index eeccd1b..009d470 100644 (file)
@@ -2130,14 +2130,6 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
 }
 
 
-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(), esi);
   LOperand* global_object =
@@ -2153,13 +2145,6 @@ LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
-  LStoreGlobalCell* result =
-      new(zone()) LStoreGlobalCell(UseRegister(instr->value()));
-  return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
-}
-
-
 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
   LOperand* context = UseRegisterAtStart(instr->value());
   LInstruction* result =
index ccd197f..becd4f2 100644 (file)
@@ -104,7 +104,6 @@ class LCodeGen;
   V(LoadContextSlot)                         \
   V(LoadFieldByIndex)                        \
   V(LoadFunctionPrototype)                   \
-  V(LoadGlobalCell)                          \
   V(LoadGlobalGeneric)                       \
   V(LoadKeyed)                               \
   V(LoadKeyedGeneric)                        \
@@ -145,7 +144,6 @@ class LCodeGen;
   V(StoreCodeEntry)                          \
   V(StoreContextSlot)                        \
   V(StoreFrameContext)                       \
-  V(StoreGlobalCell)                         \
   V(StoreKeyed)                              \
   V(StoreKeyedGeneric)                       \
   V(StoreNamedField)                         \
@@ -1726,13 +1724,6 @@ class LLoadKeyedGeneric FINAL : public LTemplateInstruction<1, 3, 1> {
 };
 
 
-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,
@@ -1754,19 +1745,6 @@ class LLoadGlobalGeneric FINAL : public LTemplateInstruction<1, 2, 1> {
 };
 
 
-class LStoreGlobalCell FINAL : public LTemplateInstruction<0, 1, 0> {
- public:
-  explicit LStoreGlobalCell(LOperand* value) {
-    inputs_[0] = value;
-  }
-
-  LOperand* value() { return inputs_[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) {
index 41b93d9..f6541b8 100644 (file)
@@ -14,7 +14,6 @@
 #include "src/debug.h"
 #include "src/isolate-inl.h"
 #include "src/runtime/runtime.h"
-#include "src/serialize.h"
 
 namespace v8 {
 namespace internal {
@@ -987,44 +986,21 @@ void MacroAssembler::LeaveApiExitFrame(bool restore_context) {
 }
 
 
-void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
-                                    int handler_index) {
+void MacroAssembler::PushStackHandler() {
   // Adjust this code if not the case.
-  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kSize == 1 * 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);
-
-  // We will build up the handler from the bottom by pushing on the stack.
-  // First push the frame pointer and context.
-  if (kind == StackHandler::JS_ENTRY) {
-    // The frame pointer does not point to a JS frame so we save NULL for
-    // ebp. We expect the code throwing an exception to check ebp before
-    // dereferencing it to restore the context.
-    push(Immediate(0));  // NULL frame pointer.
-    push(Immediate(Smi::FromInt(0)));  // No context.
-  } else {
-    push(ebp);
-    push(esi);
-  }
-  // Push the state and the code object.
-  unsigned state =
-      StackHandler::IndexField::encode(handler_index) |
-      StackHandler::KindField::encode(kind);
-  push(Immediate(state));
-  Push(CodeObject());
 
   // Link the current handler as the next handler.
   ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
   push(Operand::StaticVariable(handler_address));
+
   // Set this new handler as the current one.
   mov(Operand::StaticVariable(handler_address), esp);
 }
 
 
-void MacroAssembler::PopTryHandler() {
+void MacroAssembler::PopStackHandler() {
   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
   ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
   pop(Operand::StaticVariable(handler_address));
@@ -1032,103 +1008,6 @@ void MacroAssembler::PopTryHandler() {
 }
 
 
-void MacroAssembler::JumpToHandlerEntry() {
-  // Compute the handler entry address and jump to it.  The handler table is
-  // a fixed array of (smi-tagged) code offsets.
-  // eax = exception, edi = code object, edx = state.
-  mov(ebx, FieldOperand(edi, Code::kHandlerTableOffset));
-  shr(edx, StackHandler::kKindWidth);
-  mov(edx, FieldOperand(ebx, edx, times_4, FixedArray::kHeaderSize));
-  SmiUntag(edx);
-  lea(edi, FieldOperand(edi, edx, times_1, Code::kHeaderSize));
-  jmp(edi);
-}
-
-
-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);
-
-  // The exception is expected in eax.
-  if (!value.is(eax)) {
-    mov(eax, value);
-  }
-  // Drop the stack pointer to the top of the top handler.
-  ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
-  mov(esp, Operand::StaticVariable(handler_address));
-  // Restore the next handler.
-  pop(Operand::StaticVariable(handler_address));
-
-  // Remove the code object and state, compute the handler address in edi.
-  pop(edi);  // Code object.
-  pop(edx);  // Index and state.
-
-  // Restore the context and frame pointer.
-  pop(esi);  // Context.
-  pop(ebp);  // Frame pointer.
-
-  // If the handler is a JS frame, restore the context to the frame.
-  // (kind == ENTRY) == (ebp == 0) == (esi == 0), so we could test either
-  // ebp or esi.
-  Label skip;
-  test(esi, esi);
-  j(zero, &skip, Label::kNear);
-  mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
-  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);
-  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 eax.
-  if (!value.is(eax)) {
-    mov(eax, value);
-  }
-  // Drop the stack pointer to the top of the top stack handler.
-  ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
-  mov(esp, Operand::StaticVariable(handler_address));
-
-  // Unwind the handlers until the top ENTRY handler is found.
-  Label fetch_next, check_kind;
-  jmp(&check_kind, Label::kNear);
-  bind(&fetch_next);
-  mov(esp, Operand(esp, StackHandlerConstants::kNextOffset));
-
-  bind(&check_kind);
-  STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
-  test(Operand(esp, StackHandlerConstants::kStateOffset),
-       Immediate(StackHandler::KindField::kMask));
-  j(not_zero, &fetch_next);
-
-  // Set the top handler address to next handler past the top ENTRY handler.
-  pop(Operand::StaticVariable(handler_address));
-
-  // Remove the code object and state, compute the handler address in edi.
-  pop(edi);  // Code object.
-  pop(edx);  // Index and state.
-
-  // Clear the context pointer and frame pointer (0 was saved in the handler).
-  pop(esi);
-  pop(ebp);
-
-  JumpToHandlerEntry();
-}
-
-
 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
                                             Register scratch1,
                                             Register scratch2,
@@ -1883,6 +1762,20 @@ void MacroAssembler::NegativeZeroTest(Register result,
 }
 
 
+void MacroAssembler::GetMapConstructor(Register result, Register map,
+                                       Register temp) {
+  Label done, loop;
+  mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
+  bind(&loop);
+  JumpIfSmi(result, &done);
+  CmpObjectType(result, MAP_TYPE, temp);
+  j(not_equal, &done);
+  mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
+  jmp(&loop);
+  bind(&done);
+}
+
+
 void MacroAssembler::TryGetFunctionPrototype(Register function,
                                              Register result,
                                              Register scratch,
@@ -1934,7 +1827,7 @@ void MacroAssembler::TryGetFunctionPrototype(Register function,
     // Non-instance prototype: Fetch prototype from constructor field
     // in initial map.
     bind(&non_instance);
-    mov(result, FieldOperand(result, Map::kConstructorOffset));
+    GetMapConstructor(result, result, scratch);
   }
 
   // All done.
@@ -2448,6 +2341,17 @@ void MacroAssembler::Move(const Operand& dst, const Immediate& x) {
 }
 
 
+void MacroAssembler::Lzcnt(Register dst, const Operand& src) {
+  // TODO(intel): Add support for LZCNT (with ABM/BMI1).
+  Label not_zero_src;
+  bsr(dst, src);
+  j(not_zero, &not_zero_src, Label::kNear);
+  Move(dst, Immediate(63));  // 63^31 == 32
+  bind(&not_zero_src);
+  xor_(dst, Immediate(31));  // for x in [0..31], 31^x == 31-x.
+}
+
+
 void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
   if (FLAG_native_code_counters && counter->Enabled()) {
     mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
index c25203f..c392598 100644 (file)
@@ -535,17 +535,11 @@ class MacroAssembler: public Assembler {
   // ---------------------------------------------------------------------------
   // Exception handling
 
-  // Push a new try handler and link it into try handler chain.
-  void PushTryHandler(StackHandler::Kind kind, int handler_index);
+  // Push a new stack handler and link it into stack handler chain.
+  void PushStackHandler();
 
-  // Unlink the stack handler on top of the stack from the try handler chain.
-  void PopTryHandler();
-
-  // Throw to the top handler in the try hander chain.
-  void Throw(Register value);
-
-  // Throw past all JS frames to the top JS entry frame.
-  void ThrowUncatchable(Register value);
+  // Unlink the stack handler on top of the stack from the stack handler chain.
+  void PopStackHandler();
 
   // ---------------------------------------------------------------------------
   // Inline caching support
@@ -683,6 +677,10 @@ class MacroAssembler: public Assembler {
   void NegativeZeroTest(Register result, Register op1, Register op2,
                         Register scratch, Label* then_label);
 
+  // Machine code version of Map::GetConstructor().
+  // |temp| holds |result|'s map when done.
+  void GetMapConstructor(Register result, Register map, Register temp);
+
   // 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
@@ -778,6 +776,9 @@ class MacroAssembler: public Assembler {
   void Push(Register src) { push(src); }
   void Pop(Register dst) { pop(dst); }
 
+  void Lzcnt(Register dst, Register src) { Lzcnt(dst, Operand(src)); }
+  void Lzcnt(Register dst, const Operand& src);
+
   // Emit call to the code we are currently generating.
   void CallSelf() {
     Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
@@ -966,10 +967,6 @@ class MacroAssembler: public Assembler {
                           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.
   Operand SafepointRegisterSlot(Register reg);
   static int SafepointRegisterStackIndex(int reg_code);
index 1b851e4..60536a4 100644 (file)
@@ -86,6 +86,7 @@
         'compiler/test-run-machops.cc',
         'compiler/test-run-properties.cc',
         'compiler/test-run-stackcheck.cc',
+        'compiler/test-run-stubs.cc',
         'compiler/test-run-variables.cc',
         'compiler/test-simplified-lowering.cc',
         'cctest.cc',
         'test-api.cc',
         'test-api.h',
         'test-api-interceptors.cc',
+        'test-array-list.cc',
         'test-ast.cc',
         'test-atomicops.cc',
         'test-bignum.cc',
         'test-thread-termination.cc',
         'test-threads.cc',
         'test-transitions.cc',
+        'test-typedarrays.cc',
         'test-types.cc',
         'test-unbound-queue.cc',
         'test-unboxed-doubles.cc',
             },
           },
         }],
+        ['OS=="aix"', {
+          'ldflags': [ '-Wl,-bbigtoc' ],
+        }],
         ['component=="shared_library"', {
           # cctest can't be built against a shared library, so we need to
           # depend on the underlying static target in that case.
index e111438..08877c8 100644 (file)
@@ -558,6 +558,9 @@ static inline void SimulateIncrementalMarking(i::Heap* heap) {
   CHECK(marking->IsMarking());
   while (!marking->IsComplete()) {
     marking->Step(i::MB, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD);
+    if (marking->IsReadyToOverApproximateWeakClosure()) {
+      marking->MarkObjectGroups();
+    }
   }
   CHECK(marking->IsComplete());
 }
index c58b1f0..d7f7249 100644 (file)
@@ -64,9 +64,6 @@
   # are actually 13 * 38 * 5 * 128 = 316160 individual tests hidden here.
   'test-parsing/ParserSync': [PASS, NO_VARIANTS],
 
-  # Modules are busted
-  'test-parsing/ExportsMaybeAssigned': [SKIP],
-
   # This tests only the type system, so there is no point in running several
   # variants.
   'test-hydrogen-types/*': [PASS, NO_VARIANTS],
   # The cpu profiler tests are notoriously flaky.
   # BUG(2999). (test/cpu-profiler/CollectCpuProfile)
   # BUG(3287). (test-cpu-profiler/SampleWhenFrameIsNotSetup)
-  'test-cpu-profiler/*': [PASS, FLAKY],
-  'test-cpu-profiler/*': [SKIP],
+  'test-cpu-profiler/CollectCpuProfile': [SKIP],
+  'test-cpu-profiler/CollectCpuProfileSamples': [SKIP],
+  'test-cpu-profiler/FunctionApplySample': [SKIP],
+  'test-cpu-profiler/FunctionCallSample': [SKIP],
+  'test-cpu-profiler/SampleWhenFrameIsNotSetup': [SKIP],
+  'test-cpu-profiler/HotDeoptNoFrameEntry': [SKIP],
+  'test-cpu-profiler/BoundFunctionCall': [SKIP],
+  'test-cpu-profiler/CpuProfileDeepStack': [SKIP],
+  'test-cpu-profiler/JsNativeJsSample': [SKIP],
+  'test-cpu-profiler/JsNativeJsRuntimeJsSample': [SKIP],
+  'test-cpu-profiler/JsNative1JsNative2JsSample': [SKIP],
 
   # BUG(3525). Test crashes flakily.
   'test-debug/RecursiveBreakpoints': [PASS, FLAKY],
   'test-debug/RecursiveBreakpointsGlobal': [PASS, FLAKY],
 
+  # Fails sometimes.
+  'test-debug/ProcessDebugMessagesThreaded': [PASS, FLAKY],
+
   ##############################################################################
   # TurboFan compiler failures.
 
   # BUG(3742).
   'test-mark-compact/MarkCompactCollector': [PASS, ['arch==arm', NO_VARIANTS]],
 
-  # TODO(jarin/mstarzinger): Investigate debugger issues with TurboFan.
-  'test-debug/DebugStepNatives': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepFunctionApply': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepFunctionCall': [PASS, NO_VARIANTS],
+  # TODO(jarin): Cannot lazy-deoptimize from conversions before comparisons.
+  'test-js-typed-lowering/OrderCompareEffects': [SKIP],
 
   # TODO(jochen): Reenable after we removed the CHECK() from the marking queue.
   'test-mark-compact/MarkingDeque': [SKIP],
 
+  'test-heap/TestInternalWeakLists': [PASS, ['arch==arm', NO_VARIANTS]],
+  'test-heap/TestInternalWeakListsTraverseWithGC': [PASS, ['arch==arm', NO_VARIANTS]],
+
   ############################################################################
   # Slow tests.
   'test-api/Threading1': [PASS, ['mode == debug', SLOW]],
 ##############################################################################
 ['arch == arm64', {
 
+  'test-cpu-profiler/CollectDeoptEvents': [PASS, FAIL],
+
   'test-api/Bug618': [PASS],
 
   # BUG(v8:3385).
   'test-serialize/DeserializeFromSecondSerialization': [PASS, FAIL],
   'test-serialize/DeserializeFromSecondSerializationAndRunScript2': [PASS, FAIL],
 
-  # BUG(v8:2999).
-  'test-cpu-profiler/CollectCpuProfile': [PASS, FAIL],
-
   # BUG(v8:3154).
   'test-heap/ReleaseOverReservedPages': [PASS, FAIL],
 
 ##############################################################################
 ['system == windows', {
 
-  # BUG(2999).
-  'test-cpu-profiler/CollectCpuProfile': [PASS, FAIL],
-
   # BUG(3005).
   'test-alloc/CodeRange': [PASS, FAIL],
 
   # BUG(3331). Fails on windows.
   'test-heap/NoWeakHashTableLeakWithIncrementalMarking': [SKIP],
 
-  # BUG(v8:3433). Crashes on windows.
-  'test-cpu-profiler/FunctionApplySample': [SKIP],
-
 }],  # 'system == windows'
 
 ##############################################################################
 ##############################################################################
 ['arch == arm', {
 
+  'test-cpu-profiler/CollectDeoptEvents': [PASS, FAIL],
+
   # BUG(355): Test crashes on ARM.
   'test-log/ProfLazyMode': [SKIP],
 
 
 ##############################################################################
 ['arch == mipsel or arch == mips', {
-
-  # BUG(2657): Test sometimes times out on MIPS simulator.
-  'test-thread-termination/TerminateMultipleV8ThreadsDefaultIsolate': [PASS, TIMEOUT],
+  'test-cpu-profiler/CollectDeoptEvents': [PASS, FAIL],
 
   # BUG(1075): Unresolved crashes on MIPS also.
   'test-serialize/Deserialize': [SKIP],
   'test-serialize/DeserializeFromSecondSerializationAndRunScript2': [SKIP],
   'test-serialize/DeserializeAndRunScript2': [SKIP],
   'test-serialize/DeserializeFromSecondSerialization': [SKIP],
-
-  # Test requires turbofan:
-  'test-simplified-lowering/LowerStringOps_to_call_and_compare': [SKIP],
-  'codegen-tester/CompareWrapper': [SKIP],
-  'codegen-tester/ParametersEqual': [SKIP],
 }],  # 'arch == mipsel or arch == mips'
 
 ##############################################################################
 
 ##############################################################################
 ['arch == mips64el', {
-
-  # BUG(2657): Test sometimes times out on MIPS simulator.
-  'test-thread-termination/TerminateMultipleV8ThreadsDefaultIsolate': [PASS, TIMEOUT],
+  'test-cpu-profiler/CollectDeoptEvents': [PASS, FAIL],
 
   # BUG(v8:3154).
   'test-heap/ReleaseOverReservedPages': [PASS, FAIL],
   'test-serialize/DeserializeFromSecondSerializationAndRunScript2': [SKIP],
   'test-serialize/DeserializeAndRunScript2': [SKIP],
   'test-serialize/DeserializeFromSecondSerialization': [SKIP],
-
-  # Test requires turbofan:
-  'test-simplified-lowering/LowerStringOps_to_call_and_compare': [SKIP],
-  'codegen-tester/CompareWrapper': [SKIP],
-  'codegen-tester/ParametersEqual': [SKIP],
 }],  # 'arch == mips64el'
 
 ##############################################################################
   'codegen-tester/CompareWrapper': [SKIP],
   'codegen-tester/ParametersEqual': [SKIP],
   'test-simplified-lowering/LowerStringOps_to_call_and_compare': [SKIP],
+  'test-serialize/SerializeInternalReference': [FAIL],
 }],  # 'arch == x87'
 
 ##############################################################################
 
 }],  # 'arch == nacl_ia32 or arch == nacl_x64'
 
-['arch == ppc64', {
-  #issue 2857
-  'test-log/EquivalenceOfLoggingAndTraversal' : [SKIP],
-}],  # 'arch == ppc64'
+##############################################################################
+['arch == ppc and simulator_run == True or arch == ppc64 and simulator_run == True', {
+
+  # Pass but take too long with the simulator.
+  'test-api/Threading1': [PASS, SLOW],
+  'test-api/Threading2': [PASS, SLOW],
+  'test-api/ExternalArrays': [PASS, SLOW],
+
+}],  # 'arch == ppc64 and simulator_run == True'
 ]
index ffafaf0..30bbe1e 100644 (file)
@@ -128,6 +128,20 @@ struct ParameterTraits<T*> {
   static uintptr_t Cast(void* r) { return reinterpret_cast<uintptr_t>(r); }
 };
 
+// Additional template specialization required for mips64 to sign-extend
+// parameters defined by calling convention.
+template <>
+struct ParameterTraits<int32_t> {
+  static int64_t Cast(int32_t r) { return static_cast<int64_t>(r); }
+};
+
+template <>
+struct ParameterTraits<uint32_t> {
+  static int64_t Cast(uint32_t r) {
+    return static_cast<int64_t>(static_cast<int32_t>(r));
+  }
+};
+
 class CallHelper {
  public:
   explicit CallHelper(Isolate* isolate, MachineSignature* machine_sig)
@@ -214,6 +228,7 @@ class CallHelper {
     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)));
index 440043c..20efd1e 100644 (file)
@@ -34,6 +34,7 @@ class FunctionTester : public InitializedHandleScope {
         flags_(flags) {
     Compile(function);
     const uint32_t supported_flags = CompilationInfo::kContextSpecializing |
+                                     CompilationInfo::kBuiltinInliningEnabled |
                                      CompilationInfo::kInliningEnabled |
                                      CompilationInfo::kTypingEnabled;
     CHECK_EQ(0u, flags_ & ~supported_flags);
@@ -60,7 +61,6 @@ class FunctionTester : public InitializedHandleScope {
     CHECK(isolate->has_pending_exception());
     CHECK(try_catch.HasCaught());
     CHECK(no_result.is_null());
-    // TODO(mstarzinger): Temporary workaround for issue chromium:362388.
     isolate->OptionalRescheduleException(true);
   }
 
@@ -71,10 +71,8 @@ class FunctionTester : public InitializedHandleScope {
     CHECK(isolate->has_pending_exception());
     CHECK(try_catch.HasCaught());
     CHECK(no_result.is_null());
-    // TODO(mstarzinger): Calling OptionalRescheduleException is a dirty hack,
-    // it's the only way to make Message() not to assert because an external
-    // exception has been caught by the try_catch.
     isolate->OptionalRescheduleException(true);
+    CHECK(!try_catch.Message().IsEmpty());
     return try_catch.Message();
   }
 
@@ -152,9 +150,11 @@ class FunctionTester : public InitializedHandleScope {
   Handle<JSFunction> Compile(Handle<JSFunction> function) {
 // TODO(titzer): make this method private.
 #if V8_TURBOFAN_TARGET
-    CompilationInfoWithZone info(function);
+    Zone zone;
+    ParseInfo parse_info(&zone, function);
+    CompilationInfo info(&parse_info);
 
-    CHECK(Parser::ParseStatic(&info));
+    CHECK(Parser::ParseStatic(info.parse_info()));
     info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
     if (flags_ & CompilationInfo::kContextSpecializing) {
       info.MarkAsContextSpecializing();
@@ -165,7 +165,7 @@ class FunctionTester : public InitializedHandleScope {
     if (flags_ & CompilationInfo::kTypingEnabled) {
       info.MarkAsTypingEnabled();
     }
-    CHECK(Compiler::Analyze(&info));
+    CHECK(Compiler::Analyze(info.parse_info()));
     CHECK(Compiler::EnsureDeoptimizationSupport(&info));
 
     Pipeline pipeline(&info);
@@ -208,12 +208,14 @@ class FunctionTester : public InitializedHandleScope {
   // and replace the JSFunction's code with the result.
   Handle<JSFunction> CompileGraph(Graph* graph) {
     CHECK(Pipeline::SupportedTarget());
-    CompilationInfoWithZone info(function);
+    Zone zone;
+    ParseInfo parse_info(&zone, function);
+    CompilationInfo info(&parse_info);
 
-    CHECK(Parser::ParseStatic(&info));
+    CHECK(Parser::ParseStatic(info.parse_info()));
     info.SetOptimizing(BailoutId::None(),
                        Handle<Code>(function->shared()->code()));
-    CHECK(Compiler::Analyze(&info));
+    CHECK(Compiler::Analyze(info.parse_info()));
     CHECK(Compiler::EnsureDeoptimizationSupport(&info));
 
     Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, graph);
index e65ba2e..6afdc0a 100644 (file)
@@ -48,7 +48,7 @@ Node* SimplifiedGraphBuilder::MakeNode(const Operator* op,
   DCHECK(op->ValueInputCount() == value_input_count);
 
   DCHECK(!OperatorProperties::HasContextInput(op));
-  DCHECK(!OperatorProperties::HasFrameStateInput(op));
+  DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op));
   bool has_control = op->ControlInputCount() == 1;
   bool has_effect = op->EffectInputCount() == 1;
 
index a90e402..0b59308 100644 (file)
@@ -44,11 +44,14 @@ class DeoptCodegenTester {
   explicit DeoptCodegenTester(HandleAndZoneScope* scope, const char* src)
       : scope_(scope),
         function(NewFunction(src)),
-        info(function, scope->main_zone()),
-        bailout_id(-1) {
-    CHECK(Parser::ParseStatic(&info));
+        parse_info(scope->main_zone(), function),
+        info(&parse_info),
+        bailout_id(-1),
+        tagged_type(1, kMachAnyTagged, zone()),
+        empty_types(zone()) {
+    CHECK(Parser::ParseStatic(&parse_info));
     info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
-    CHECK(Compiler::Analyze(&info));
+    CHECK(Compiler::Analyze(&parse_info));
     CHECK(Compiler::EnsureDeoptimizationSupport(&info));
 
     DCHECK(info.shared_info()->has_deoptimization_support());
@@ -76,11 +79,14 @@ class DeoptCodegenTester {
 
   HandleAndZoneScope* scope_;
   Handle<JSFunction> function;
+  ParseInfo parse_info;
   CompilationInfo info;
   BailoutId bailout_id;
   Handle<Code> result_code;
   TestInstrSeq* code;
   Graph* graph;
+  ZoneVector<MachineType> tagged_type;
+  ZoneVector<MachineType> empty_types;
 };
 
 
@@ -118,9 +124,10 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester {
         m.NewNode(common.HeapConstant(caller_context_constant));
 
     bailout_id = GetCallBailoutId();
-    Node* parameters = m.NewNode(common.StateValues(1), m.UndefinedConstant());
-    Node* locals = m.NewNode(common.StateValues(0));
-    Node* stack = m.NewNode(common.StateValues(0));
+    Node* parameters =
+        m.NewNode(common.TypedStateValues(&tagged_type), m.UndefinedConstant());
+    Node* locals = m.NewNode(common.TypedStateValues(&empty_types));
+    Node* stack = m.NewNode(common.TypedStateValues(&empty_types));
 
     Node* state_node = m.NewNode(
         common.FrameState(JS_FRAME, bailout_id,
@@ -233,9 +240,10 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester {
     Node* context_node = m.NewNode(common.HeapConstant(context_constant));
 
     bailout_id = GetCallBailoutId();
-    Node* parameters = m.NewNode(common.StateValues(1), m.UndefinedConstant());
-    Node* locals = m.NewNode(common.StateValues(0));
-    Node* stack = m.NewNode(common.StateValues(0));
+    Node* parameters =
+        m.NewNode(common.TypedStateValues(&tagged_type), m.UndefinedConstant());
+    Node* locals = m.NewNode(common.TypedStateValues(&empty_types));
+    Node* stack = m.NewNode(common.TypedStateValues(&empty_types));
 
     Node* state_node = m.NewNode(
         common.FrameState(JS_FRAME, bailout_id,
index 827dcfd..c2b225a 100644 (file)
@@ -8,7 +8,7 @@
 #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/graph.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/node-properties.h"
 
@@ -694,9 +694,9 @@ TEST(CMergeReduce_none1) {
 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);
+  Node* t1 = R.graph.NewNode(R.common.IfTrue(), R.start);
+  Node* t2 = R.graph.NewNode(R.common.IfTrue(), R.start);
+  Node* merge = R.graph.NewNode(R.common.Merge(2), t1, t2);
   R.ReduceMerge(merge, merge);
 }
 
@@ -744,7 +744,7 @@ 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);
+  Node* f = R.graph.NewNode(R.common.IfTrue(), 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++) {
@@ -1118,7 +1118,7 @@ TEST(CChainedDiamondsReduce_x_false) {
   Diamond d2(R, R.zero);
   d2.chain(d1);
 
-  R.ReduceMergeIterative(d1.merge, d2.merge);
+  R.ReduceMergeIterative(R.start, d2.merge);
 }
 
 
@@ -1128,8 +1128,7 @@ TEST(CChainedDiamondsReduce_false_x) {
   Diamond d2(R, R.p0);
   d2.chain(d1);
 
-  R.ReduceMergeIterative(d2.merge, d2.merge);
-  CheckInputs(d2.branch, R.p0, R.start);
+  R.ReduceMergeIterative(R.start, d2.merge);
 }
 
 
@@ -1190,6 +1189,28 @@ TEST(CNestedDiamonds_xyz) {
 }
 
 
+TEST(CUnusedDiamond1) {
+  ControlReducerTester R;
+  // if (p0) { } else { }
+  Node* branch = R.graph.NewNode(R.common.Branch(), R.p0, R.start);
+  Node* if_true = R.graph.NewNode(R.common.IfTrue(), branch);
+  Node* if_false = R.graph.NewNode(R.common.IfFalse(), branch);
+  Node* merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false);
+  R.ReduceMergeIterative(R.start, merge);
+}
+
+
+TEST(CUnusedDiamond2) {
+  ControlReducerTester R;
+  // if (p0) { } else { }
+  Node* branch = R.graph.NewNode(R.common.Branch(), R.p0, R.start);
+  Node* if_true = R.graph.NewNode(R.common.IfTrue(), branch);
+  Node* if_false = R.graph.NewNode(R.common.IfFalse(), branch);
+  Node* merge = R.graph.NewNode(R.common.Merge(2), if_false, if_true);
+  R.ReduceMergeIterative(R.start, merge);
+}
+
+
 TEST(CDeadLoop1) {
   ControlReducerTester R;
 
@@ -1329,9 +1350,7 @@ TEST(Return_nested_diamonds1) {
 
   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);
+  CheckInputs(d1.merge, d1.if_true, d1.if_false);
 }
 
 
@@ -1348,11 +1367,7 @@ TEST(Return_nested_diamonds_true1) {
 
   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);
+  CheckInputs(ret, R.one, R.start, R.start);
 }
 
 
@@ -1369,11 +1384,7 @@ TEST(Return_nested_diamonds_false1) {
 
   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);
+  CheckInputs(ret, R.zero, R.start, R.start);
 }
 
 
index 85cc870..22d46e7 100644 (file)
@@ -27,20 +27,14 @@ typedef v8::internal::compiler::InstructionSequence TestInstrSeq;
 class InstructionTester : public HandleAndZoneScope {
  public:  // We're all friends here.
   InstructionTester()
-      : isolate(main_isolate()),
-        graph(zone()),
+      : graph(zone()),
         schedule(zone()),
-        fake_stub(main_isolate()),
-        info(&fake_stub, main_isolate()),
         common(zone()),
         machine(zone()),
         code(NULL) {}
 
-  Isolate* isolate;
   Graph graph;
   Schedule schedule;
-  FakeStubForTesting fake_stub;
-  CompilationInfoWithZone info;
   CommonOperatorBuilder common;
   MachineOperatorBuilder machine;
   TestInstrSeq* code;
@@ -93,8 +87,12 @@ class InstructionTester : public HandleAndZoneScope {
     return UnallocatedOperand(UnallocatedOperand::ANY, vreg).Copy(zone());
   }
 
+  RpoNumber RpoFor(BasicBlock* block) {
+    return RpoNumber::FromInt(block->rpo_number());
+  }
+
   InstructionBlock* BlockAt(BasicBlock* block) {
-    return code->InstructionBlockAt(block->GetRpoNumber());
+    return code->InstructionBlockAt(RpoFor(block));
   }
   BasicBlock* GetBasicBlock(int instruction_index) {
     const InstructionBlock* block =
@@ -131,7 +129,6 @@ TEST(InstructionBasic) {
 
   for (auto block : *blocks) {
     CHECK_EQ(block->rpo_number(), R.BlockAt(block)->rpo_number().ToInt());
-    CHECK_EQ(block->id().ToInt(), R.BlockAt(block)->id().ToInt());
     CHECK(!block->loop_end());
   }
 }
@@ -151,23 +148,23 @@ TEST(InstructionGetBasicBlock) {
 
   R.allocCode();
 
-  R.code->StartBlock(b0->GetRpoNumber());
+  R.code->StartBlock(R.RpoFor(b0));
   int i0 = R.NewInstr();
   int i1 = R.NewInstr();
-  R.code->EndBlock(b0->GetRpoNumber());
-  R.code->StartBlock(b1->GetRpoNumber());
+  R.code->EndBlock(R.RpoFor(b0));
+  R.code->StartBlock(R.RpoFor(b1));
   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());
+  R.code->EndBlock(R.RpoFor(b1));
+  R.code->StartBlock(R.RpoFor(b2));
   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());
+  R.code->EndBlock(R.RpoFor(b2));
+  R.code->StartBlock(R.RpoFor(b3));
+  R.code->EndBlock(R.RpoFor(b3));
 
   CHECK_EQ(b0, R.GetBasicBlock(i0));
   CHECK_EQ(b0, R.GetBasicBlock(i1));
@@ -203,11 +200,11 @@ TEST(InstructionIsGapAt) {
 
   R.allocCode();
   TestInstr* i0 = TestInstr::New(R.zone(), 100);
-  TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
-  R.code->StartBlock(b0->GetRpoNumber());
+  TestInstr* g = TestInstr::New(R.zone(), 103);
+  R.code->StartBlock(R.RpoFor(b0));
   R.code->AddInstruction(i0);
   R.code->AddInstruction(g);
-  R.code->EndBlock(b0->GetRpoNumber());
+  R.code->EndBlock(R.RpoFor(b0));
 
   CHECK(R.code->instructions().size() == 4);
   for (size_t i = 0; i < R.code->instructions().size(); ++i) {
@@ -226,18 +223,18 @@ TEST(InstructionIsGapAt2) {
 
   R.allocCode();
   TestInstr* i0 = TestInstr::New(R.zone(), 100);
-  TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
-  R.code->StartBlock(b0->GetRpoNumber());
+  TestInstr* g = TestInstr::New(R.zone(), 103);
+  R.code->StartBlock(R.RpoFor(b0));
   R.code->AddInstruction(i0);
   R.code->AddInstruction(g);
-  R.code->EndBlock(b0->GetRpoNumber());
+  R.code->EndBlock(R.RpoFor(b0));
 
   TestInstr* i1 = TestInstr::New(R.zone(), 102);
-  TestInstr* g1 = TestInstr::New(R.zone(), 104)->MarkAsControl();
-  R.code->StartBlock(b1->GetRpoNumber());
+  TestInstr* g1 = TestInstr::New(R.zone(), 104);
+  R.code->StartBlock(R.RpoFor(b1));
   R.code->AddInstruction(i1);
   R.code->AddInstruction(g1);
-  R.code->EndBlock(b1->GetRpoNumber());
+  R.code->EndBlock(R.RpoFor(b1));
 
   CHECK(R.code->instructions().size() == 8);
   for (size_t i = 0; i < R.code->instructions().size(); ++i) {
@@ -254,11 +251,11 @@ TEST(InstructionAddGapMove) {
 
   R.allocCode();
   TestInstr* i0 = TestInstr::New(R.zone(), 100);
-  TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
-  R.code->StartBlock(b0->GetRpoNumber());
+  TestInstr* g = TestInstr::New(R.zone(), 103);
+  R.code->StartBlock(R.RpoFor(b0));
   R.code->AddInstruction(i0);
   R.code->AddInstruction(g);
-  R.code->EndBlock(b0->GetRpoNumber());
+  R.code->EndBlock(R.RpoFor(b0));
 
   CHECK(R.code->instructions().size() == 4);
   for (size_t i = 0; i < R.code->instructions().size(); ++i) {
index f4531d3..cc4b2bd 100644 (file)
@@ -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 "src/compiler/graph-inl.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/js-typed-lowering.h"
 #include "src/compiler/machine-operator.h"
@@ -68,7 +67,7 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
     Node* stack = graph.NewNode(common.StateValues(0));
 
     Node* state_node =
-        graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0),
+        graph.NewNode(common.FrameState(JS_FRAME, BailoutId::None(),
                                         OutputFrameStateCombine::Ignore()),
                       parameters, locals, stack, context, UndefinedConstant());
 
@@ -114,9 +113,13 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
 
   Node* Binop(const Operator* op, Node* left, Node* right) {
     // JS binops also require context, effect, and control
-    if (OperatorProperties::HasFrameStateInput(op)) {
+    if (OperatorProperties::GetFrameStateInputCount(op) == 1) {
       return graph.NewNode(op, left, right, context(),
                            EmptyFrameState(context()), start(), control());
+    } else if (OperatorProperties::GetFrameStateInputCount(op) == 2) {
+      return graph.NewNode(op, left, right, context(),
+                           EmptyFrameState(context()),
+                           EmptyFrameState(context()), start(), control());
     } else {
       return graph.NewNode(op, left, right, context(), start(), control());
     }
@@ -124,7 +127,8 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
 
   Node* Unop(const Operator* op, Node* input) {
     // JS unops also require context, effect, and control
-    if (OperatorProperties::HasFrameStateInput(op)) {
+    if (OperatorProperties::GetFrameStateInputCount(op) > 0) {
+      DCHECK(OperatorProperties::GetFrameStateInputCount(op) == 1);
       return graph.NewNode(op, input, context(), EmptyFrameState(context()),
                            start(), control());
     } else {
@@ -134,7 +138,10 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
 
   Node* UseForEffect(Node* node) {
     // TODO(titzer): use EffectPhi after fixing EffectCount
-    if (OperatorProperties::HasFrameStateInput(javascript.ToNumber())) {
+    if (OperatorProperties::GetFrameStateInputCount(javascript.ToNumber()) >
+        0) {
+      DCHECK(OperatorProperties::GetFrameStateInputCount(
+                 javascript.ToNumber()) == 1);
       return graph.NewNode(javascript.ToNumber(), node, context(),
                            EmptyFrameState(context()), node, control());
     } else {
@@ -500,42 +507,6 @@ TEST(JSToNumberOfNumberOrOtherPrimitive) {
 }
 
 
-TEST(JSToBoolean) {
-  JSTypedLoweringTester R;
-  const Operator* op = R.javascript.ToBoolean();
-
-  {  // ToBoolean(undefined)
-    Node* r = R.ReduceUnop(op, Type::Undefined());
-    R.CheckFalse(r);
-  }
-
-  {  // ToBoolean(null)
-    Node* r = R.ReduceUnop(op, Type::Null());
-    R.CheckFalse(r);
-  }
-
-  {  // ToBoolean(boolean)
-    Node* r = R.ReduceUnop(op, Type::Boolean());
-    CHECK_EQ(IrOpcode::kParameter, r->opcode());
-  }
-
-  {  // ToBoolean(object)
-    Node* r = R.ReduceUnop(op, Type::DetectableObject());
-    R.CheckTrue(r);
-  }
-
-  {  // ToBoolean(undetectable)
-    Node* r = R.ReduceUnop(op, Type::Undetectable());
-    R.CheckFalse(r);
-  }
-
-  {  // ToBoolean(object)
-    Node* r = R.ReduceUnop(op, Type::Object());
-    CHECK_EQ(IrOpcode::kAnyToBoolean, r->opcode());
-  }
-}
-
-
 TEST(JSToString1) {
   JSTypedLoweringTester R;
 
@@ -717,24 +688,6 @@ TEST(MixedComparison1) {
 }
 
 
-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* r = R.reduce(orig);
-
-    if (r == orig && orig->opcode() == IrOpcode::kJSToBoolean) {
-      // The original node was turned into a ToBoolean.
-      CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
-    } else if (r->opcode() != IrOpcode::kHeapConstant) {
-      CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
-    }
-  }
-}
-
-
 TEST(RemoveToNumberEffects) {
   FLAG_turbo_deoptimization = true;
 
@@ -749,8 +702,9 @@ TEST(RemoveToNumberEffects) {
 
     switch (i) {
       case 0:
-        // TODO(jarin) Replace with a query of FLAG_turbo_deoptimization.
-        if (OperatorProperties::HasFrameStateInput(R.javascript.ToNumber())) {
+        if (FLAG_turbo_deoptimization) {
+          DCHECK(OperatorProperties::GetFrameStateInputCount(
+                     R.javascript.ToNumber()) == 1);
           effect_use = R.graph.NewNode(R.javascript.ToNumber(), p0, R.context(),
                                        frame_state, ton, R.start());
         } else {
@@ -759,8 +713,9 @@ TEST(RemoveToNumberEffects) {
         }
         break;
       case 1:
-        // TODO(jarin) Replace with a query of FLAG_turbo_deoptimization.
-        if (OperatorProperties::HasFrameStateInput(R.javascript.ToNumber())) {
+        if (FLAG_turbo_deoptimization) {
+          DCHECK(OperatorProperties::GetFrameStateInputCount(
+                     R.javascript.ToNumber()) == 1);
           effect_use =
               R.graph.NewNode(R.javascript.ToNumber(), ton, R.context(),
                               frame_state, ton, R.start());
@@ -773,11 +728,11 @@ TEST(RemoveToNumberEffects) {
         effect_use = R.graph.NewNode(R.common.EffectPhi(1), ton, R.start());
       case 3:
         effect_use = R.graph.NewNode(R.javascript.Add(), ton, ton, R.context(),
-                                     frame_state, ton, R.start());
+                                     frame_state, frame_state, ton, R.start());
         break;
       case 4:
         effect_use = R.graph.NewNode(R.javascript.Add(), p0, p0, R.context(),
-                                     frame_state, ton, R.start());
+                                     frame_state, frame_state, ton, R.start());
         break;
       case 5:
         effect_use = R.graph.NewNode(R.common.Return(), p0, ton, R.start());
index d9de18e..b2d3008 100644 (file)
@@ -13,8 +13,6 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
-typedef BasicBlock::RpoNumber RpoNumber;
-
 class TestCode : public HandleAndZoneScope {
  public:
   TestCode()
@@ -32,8 +30,8 @@ class TestCode : public HandleAndZoneScope {
   int Jump(int target) {
     Start();
     InstructionOperand ops[] = {UseRpo(target)};
-    sequence_.AddInstruction(Instruction::New(main_zone(), kArchJmp, 0, NULL, 1,
-                                              ops, 0, NULL)->MarkAsControl());
+    sequence_.AddInstruction(
+        Instruction::New(main_zone(), kArchJmp, 0, NULL, 1, ops, 0, NULL));
     int pos = static_cast<int>(sequence_.instructions().size() - 1);
     End();
     return pos;
@@ -47,8 +45,8 @@ class TestCode : public HandleAndZoneScope {
     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());
+    sequence_.AddInstruction(
+        Instruction::New(main_zone(), code, 0, NULL, 2, ops, 0, NULL));
     int pos = static_cast<int>(sequence_.instructions().size() - 1);
     End();
     return pos;
@@ -87,9 +85,9 @@ class TestCode : public HandleAndZoneScope {
   }
   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);
+      current_ = new (main_zone())
+          InstructionBlock(main_zone(), rpo_number_, RpoNumber::Invalid(),
+                           RpoNumber::Invalid(), deferred);
       blocks_.push_back(current_);
       sequence_.StartBlock(rpo_number_);
     }
index 13695b2..212ff3a 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "src/code-stubs.h"
 #include "src/compiler.h"
+#include "src/parser.h"
 #include "src/zone.h"
 
 #include "src/compiler/common-operator.h"
@@ -33,7 +34,7 @@ static Handle<JSFunction> Compile(const char* source) {
                                    ->NewStringFromUtf8(CStrVector(source))
                                    .ToHandleChecked();
   Handle<SharedFunctionInfo> shared_function = Compiler::CompileScript(
-      source_code, Handle<String>(), 0, 0, false, false,
+      source_code, Handle<String>(), 0, 0, false, false, Handle<Object>(),
       Handle<Context>(isolate->native_context()), NULL, NULL,
       v8::ScriptCompiler::kNoCompileOptions, NOT_NATIVES_CODE, false);
   return isolate->factory()->NewFunctionFromSharedFunctionInfo(
@@ -42,25 +43,25 @@ static Handle<JSFunction> Compile(const char* source) {
 
 
 TEST(TestLinkageCreate) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
   Handle<JSFunction> function = Compile("a + b");
-  CompilationInfoWithZone info(function);
+  ParseInfo parse_info(handles.main_zone(), function);
+  CompilationInfo info(&parse_info);
   CallDescriptor* descriptor = Linkage::ComputeIncoming(info.zone(), &info);
   CHECK(descriptor);
 }
 
 
 TEST(TestLinkageJSFunctionIncoming) {
-  InitializedHandleScope handles;
-
   const char* sources[] = {"(function() { })", "(function(a) { })",
                            "(function(a,b) { })", "(function(a,b,c) { })"};
 
   for (int i = 0; i < 3; i++) {
-    i::HandleScope handles(CcTest::i_isolate());
+    HandleAndZoneScope handles;
     Handle<JSFunction> function = v8::Utils::OpenHandle(
         *v8::Handle<v8::Function>::Cast(CompileRun(sources[i])));
-    CompilationInfoWithZone info(function);
+    ParseInfo parse_info(handles.main_zone(), function);
+    CompilationInfo info(&parse_info);
     CallDescriptor* descriptor = Linkage::ComputeIncoming(info.zone(), &info);
     CHECK(descriptor);
 
@@ -74,9 +75,10 @@ TEST(TestLinkageJSFunctionIncoming) {
 
 TEST(TestLinkageCodeStubIncoming) {
   Isolate* isolate = CcTest::InitIsolateOnce();
+  Zone zone;
   ToNumberStub stub(isolate);
-  CompilationInfoWithZone info(&stub, isolate);
-  CallDescriptor* descriptor = Linkage::ComputeIncoming(info.zone(), &info);
+  CompilationInfo info(&stub, isolate, &zone);
+  CallDescriptor* descriptor = Linkage::ComputeIncoming(&zone, &info);
   CHECK(descriptor);
   CHECK_EQ(1, static_cast<int>(descriptor->JSParameterCount()));
   CHECK_EQ(1, static_cast<int>(descriptor->ReturnCount()));
@@ -88,7 +90,8 @@ TEST(TestLinkageCodeStubIncoming) {
 TEST(TestLinkageJSCall) {
   HandleAndZoneScope handles;
   Handle<JSFunction> function = Compile("a + c");
-  CompilationInfoWithZone info(function);
+  ParseInfo parse_info(handles.main_zone(), function);
+  CompilationInfo info(&parse_info);
 
   for (int i = 0; i < 32; i++) {
     CallDescriptor* descriptor = Linkage::GetJSCallDescriptor(
index 7513307..5f9820c 100644 (file)
@@ -29,14 +29,15 @@ struct TestHelper : public HandleAndZoneScope {
 
   void CheckLoopAssignedCount(int expected, const char* var_name) {
     // TODO(titzer): don't scope analyze every single time.
-    CompilationInfo info(function, main_zone());
+    ParseInfo parse_info(main_zone(), function);
+    CompilationInfo info(&parse_info);
 
-    CHECK(Parser::ParseStatic(&info));
-    CHECK(Rewriter::Rewrite(&info));
-    CHECK(Scope::Analyze(&info));
+    CHECK(Parser::ParseStatic(&parse_info));
+    CHECK(Rewriter::Rewrite(&parse_info));
+    CHECK(Scope::Analyze(&parse_info));
 
     Scope* scope = info.function()->scope();
-    AstValueFactory* factory = info.ast_value_factory();
+    AstValueFactory* factory = parse_info.ast_value_factory();
     CHECK(scope);
 
     if (result == NULL) {
index 7ee5751..beedc45 100644 (file)
@@ -6,7 +6,6 @@
 
 #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"
index 842d182..0cb7701 100644 (file)
@@ -9,7 +9,6 @@
 #include "graph-tester.h"
 #include "src/compiler/common-operator.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"
@@ -20,45 +19,6 @@ using namespace v8::internal::compiler;
 static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
                                "dummy", 0, 0, 0, 1, 0, 0);
 
-class PreNodeVisitor : public NullNodeVisitor {
- public:
-  void Pre(Node* node) {
-    printf("NODE ID: %d\n", node->id());
-    nodes_.push_back(node);
-  }
-  std::vector<Node*> nodes_;
-};
-
-
-class PostNodeVisitor : public NullNodeVisitor {
- public:
-  void Post(Node* node) {
-    printf("NODE ID: %d\n", node->id());
-    nodes_.push_back(node);
-  }
-  std::vector<Node*> nodes_;
-};
-
-
-TEST(TestInputNodePreOrderVisitSimple) {
-  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.VisitNodeInputsFromEnd(&node_visitor);
-  CHECK_EQ(5, static_cast<int>(node_visitor.nodes_.size()));
-  CHECK(n5->id() == node_visitor.nodes_[0]->id());
-  CHECK(n4->id() == node_visitor.nodes_[1]->id());
-  CHECK(n2->id() == node_visitor.nodes_[2]->id());
-  CHECK(graph.start()->id() == node_visitor.nodes_[3]->id());
-  CHECK(n3->id() == node_visitor.nodes_[4]->id());
-}
-
-
 TEST(TestPrintNodeGraphToNodeGraphviz) {
   GraphWithStartNodeTester graph;
   Node* n2 = graph.NewNode(&dummy_operator, graph.start());
index 2c51e26..5bb21f5 100644 (file)
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
+#define NONE reinterpret_cast<Node*>(1)
+
 static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
                                "dummy", 0, 0, 0, 1, 0, 0);
 
+#define CHECK_USES(node, ...)                                          \
+  do {                                                                 \
+    Node* __array[] = {__VA_ARGS__};                                   \
+    int __size =                                                       \
+        __array[0] != NONE ? static_cast<int>(arraysize(__array)) : 0; \
+    CheckUseChain(node, __array, __size);                              \
+  } while (false)
+
+
+typedef std::multiset<Node*, std::less<Node*>> NodeMSet;
+
+static void CheckUseChain(Node* node, Node** uses, int use_count) {
+  // Check ownership.
+  if (use_count == 1) CHECK(node->OwnedBy(uses[0]));
+  if (use_count > 1) {
+    for (int i = 0; i < use_count; i++) {
+      CHECK(!node->OwnedBy(uses[i]));
+    }
+  }
+
+  // Check the self-reported use count.
+  CHECK_EQ(use_count, node->UseCount());
+
+  // Build the expectation set.
+  NodeMSet expect_set;
+  for (int i = 0; i < use_count; i++) {
+    expect_set.insert(uses[i]);
+  }
+
+  {
+    // Check that iterating over the uses gives the right counts.
+    NodeMSet use_set;
+    for (auto use : node->uses()) {
+      use_set.insert(use);
+    }
+    CHECK(expect_set == use_set);
+  }
+
+  {
+    // Check that iterating over the use edges gives the right counts,
+    // input indices, from(), and to() pointers.
+    NodeMSet use_set;
+    for (auto edge : node->use_edges()) {
+      CHECK_EQ(node, edge.to());
+      CHECK_EQ(node, edge.from()->InputAt(edge.index()));
+      use_set.insert(edge.from());
+    }
+    CHECK(expect_set == use_set);
+  }
+
+  {
+    // Check the use nodes actually have the node as inputs.
+    for (Node* use : node->uses()) {
+      size_t count = 0;
+      for (Node* input : use->inputs()) {
+        if (input == node) count++;
+      }
+      CHECK_EQ(count, expect_set.count(use));
+    }
+  }
+}
+
+
+#define CHECK_INPUTS(node, ...)                                        \
+  do {                                                                 \
+    Node* __array[] = {__VA_ARGS__};                                   \
+    int __size =                                                       \
+        __array[0] != NONE ? static_cast<int>(arraysize(__array)) : 0; \
+    CheckInputs(node, __array, __size);                                \
+  } while (false)
+
+
+static void CheckInputs(Node* node, Node** inputs, int input_count) {
+  CHECK_EQ(input_count, node->InputCount());
+  // Check InputAt().
+  for (int i = 0; i < static_cast<int>(input_count); i++) {
+    CHECK_EQ(inputs[i], node->InputAt(i));
+  }
+
+  // Check input iterator.
+  int index = 0;
+  for (Node* input : node->inputs()) {
+    CHECK_EQ(inputs[index], input);
+    index++;
+  }
+
+  // Check use lists of inputs.
+  for (int i = 0; i < static_cast<int>(input_count); i++) {
+    Node* input = inputs[i];
+    if (!input) continue;  // skip null inputs
+    bool found = false;
+    // Check regular use list.
+    for (Node* use : input->uses()) {
+      if (use == node) {
+        found = true;
+        break;
+      }
+    }
+    CHECK(found);
+    int count = 0;
+    // Check use edge list.
+    for (auto edge : input->use_edges()) {
+      if (edge.from() == node && edge.to() == input && edge.index() == i) {
+        count++;
+      }
+    }
+    CHECK_EQ(1, count);
+  }
+}
+
+
 TEST(NodeUseIteratorReplaceUses) {
   GraphTester graph;
   Node* n0 = graph.NewNode(&dummy_operator);
   Node* n1 = graph.NewNode(&dummy_operator, n0);
   Node* n2 = graph.NewNode(&dummy_operator, n0);
   Node* n3 = graph.NewNode(&dummy_operator);
-  auto i1(n0->uses().begin());
-  CHECK_EQ(n1, *i1);
-  ++i1;
-  CHECK_EQ(n2, *i1);
+
+  CHECK_USES(n0, n1, n2);
+
+  CHECK_INPUTS(n1, n0);
+  CHECK_INPUTS(n2, n0);
+
   n0->ReplaceUses(n3);
-  auto i2(n3->uses().begin());
-  CHECK_EQ(n1, *i2);
-  ++i2;
-  CHECK_EQ(n2, *i2);
-  auto i3(n1->inputs().begin());
-  CHECK_EQ(n3, *i3);
-  ++i3;
-  CHECK(n1->inputs().end() == i3);
-  auto i4(n2->inputs().begin());
-  CHECK_EQ(n3, *i4);
-  ++i4;
-  CHECK(n2->inputs().end() == i4);
+
+  CHECK_USES(n0, NONE);
+  CHECK_USES(n1, NONE);
+  CHECK_USES(n2, NONE);
+  CHECK_USES(n3, n1, n2);
+
+  CHECK_INPUTS(n1, n3);
+  CHECK_INPUTS(n2, n3);
 }
 
 
@@ -46,21 +157,22 @@ TEST(NodeUseIteratorReplaceUsesSelf) {
   GraphTester graph;
   Node* n0 = graph.NewNode(&dummy_operator);
   Node* n1 = graph.NewNode(&dummy_operator, n0);
-  Node* n3 = graph.NewNode(&dummy_operator);
+
+  CHECK_USES(n0, n1);
+  CHECK_USES(n1, NONE);
 
   n1->ReplaceInput(0, n1);  // Create self-reference.
 
-  auto i1(n1->uses().begin());
-  CHECK_EQ(n1, *i1);
+  CHECK_USES(n0, NONE);
+  CHECK_USES(n1, n1);
 
-  n1->ReplaceUses(n3);
+  Node* n2 = graph.NewNode(&dummy_operator);
 
-  CHECK(n1->uses().begin() == n1->uses().end());
+  n1->ReplaceUses(n2);
 
-  auto i2(n3->uses().begin());
-  CHECK_EQ(n1, *i2);
-  ++i2;
-  CHECK(n1->uses().end() == i2);
+  CHECK_USES(n0, NONE);
+  CHECK_USES(n1, NONE);
+  CHECK_USES(n2, n1);
 }
 
 
@@ -70,48 +182,22 @@ TEST(ReplaceInput) {
   Node* n1 = graph.NewNode(&dummy_operator);
   Node* n2 = graph.NewNode(&dummy_operator);
   Node* n3 = graph.NewNode(&dummy_operator, n0, n1, n2);
-  auto i1(n3->inputs().begin());
-  CHECK(n0 == *i1);
-  CHECK_EQ(n0, n3->InputAt(0));
-  ++i1;
-  CHECK_EQ(n1, *i1);
-  CHECK_EQ(n1, n3->InputAt(1));
-  ++i1;
-  CHECK_EQ(n2, *i1);
-  CHECK_EQ(n2, n3->InputAt(2));
-  ++i1;
-  CHECK(i1 == n3->inputs().end());
-
-  auto i2(n1->uses().begin());
-  CHECK_EQ(n3, *i2);
-  ++i2;
-  CHECK(i2 == n1->uses().end());
-
   Node* n4 = graph.NewNode(&dummy_operator);
-  auto i3(n4->uses().begin());
-  CHECK(i3 == n4->uses().end());
+
+  CHECK_USES(n0, n3);
+  CHECK_USES(n1, n3);
+  CHECK_USES(n2, n3);
+  CHECK_USES(n3, NONE);
+  CHECK_USES(n4, NONE);
+
+  CHECK_INPUTS(n3, n0, n1, n2);
 
   n3->ReplaceInput(1, n4);
 
-  auto i4(n1->uses().begin());
-  CHECK(i4 == n1->uses().end());
-
-  auto i5(n4->uses().begin());
-  CHECK_EQ(n3, *i5);
-  ++i5;
-  CHECK(i5 == n4->uses().end());
-
-  auto i6(n3->inputs().begin());
-  CHECK(n0 == *i6);
-  CHECK_EQ(n0, n3->InputAt(0));
-  ++i6;
-  CHECK_EQ(n4, *i6);
-  CHECK_EQ(n4, n3->InputAt(1));
-  ++i6;
-  CHECK_EQ(n2, *i6);
-  CHECK_EQ(n2, n3->InputAt(2));
-  ++i6;
-  CHECK(i6 == n3->inputs().end());
+  CHECK_USES(n1, NONE);
+  CHECK_USES(n4, n3);
+
+  CHECK_INPUTS(n3, n0, n4, n2);
 }
 
 
@@ -169,16 +255,19 @@ TEST(Uses) {
 
   Node* n0 = graph.NewNode(&dummy_operator);
   Node* n1 = graph.NewNode(&dummy_operator, n0);
-  CHECK_EQ(1, n0->UseCount());
-  printf("A: %d vs %d\n", n0->UseAt(0)->id(), n1->id());
-  CHECK(n0->UseAt(0) == n1);
+
+  CHECK_USES(n0, n1);
+  CHECK_USES(n1, NONE);
+
   Node* n2 = graph.NewNode(&dummy_operator, n0);
-  CHECK_EQ(2, n0->UseCount());
-  printf("B: %d vs %d\n", n0->UseAt(1)->id(), n2->id());
-  CHECK(n0->UseAt(1) == n2);
+
+  CHECK_USES(n0, n1, n2);
+  CHECK_USES(n2, NONE);
+
   Node* n3 = graph.NewNode(&dummy_operator, n0);
-  CHECK_EQ(3, n0->UseCount());
-  CHECK(n0->UseAt(2) == n3);
+
+  CHECK_USES(n0, n1, n2, n3);
+  CHECK_USES(n3, NONE);
 }
 
 
@@ -189,39 +278,23 @@ TEST(Inputs) {
   Node* n1 = graph.NewNode(&dummy_operator, n0);
   Node* n2 = graph.NewNode(&dummy_operator, n0);
   Node* n3 = graph.NewNode(&dummy_operator, n0, n1, n2);
-  CHECK_EQ(3, n3->InputCount());
-  CHECK(n3->InputAt(0) == n0);
-  CHECK(n3->InputAt(1) == n1);
-  CHECK(n3->InputAt(2) == n2);
+
+  CHECK_INPUTS(n3, n0, n1, n2);
+
   Node* n4 = graph.NewNode(&dummy_operator, n0, n1, n2);
   n3->AppendInput(graph.zone(), n4);
-  CHECK_EQ(4, n3->InputCount());
-  CHECK(n3->InputAt(0) == n0);
-  CHECK(n3->InputAt(1) == n1);
-  CHECK(n3->InputAt(2) == n2);
-  CHECK(n3->InputAt(3) == n4);
-  Node* n5 = graph.NewNode(&dummy_operator, n4);
+
+  CHECK_INPUTS(n3, n0, n1, n2, n4);
+  CHECK_USES(n4, n3);
+
   n3->AppendInput(graph.zone(), n4);
-  CHECK_EQ(5, n3->InputCount());
-  CHECK(n3->InputAt(0) == n0);
-  CHECK(n3->InputAt(1) == n1);
-  CHECK(n3->InputAt(2) == n2);
-  CHECK(n3->InputAt(3) == n4);
-  CHECK(n3->InputAt(4) == n4);
-
-  // Make sure uses have been hooked op correctly.
-  Node::Uses uses(n4->uses());
-  auto current = uses.begin();
-  CHECK(current != uses.end());
-  CHECK(*current == n3);
-  ++current;
-  CHECK(current != uses.end());
-  CHECK(*current == n5);
-  ++current;
-  CHECK(current != uses.end());
-  CHECK(*current == n3);
-  ++current;
-  CHECK(current == uses.end());
+
+  CHECK_INPUTS(n3, n0, n1, n2, n4, n4);
+  CHECK_USES(n4, n3, n3);
+
+  Node* n5 = graph.NewNode(&dummy_operator, n4);
+
+  CHECK_USES(n4, n3, n3, n5);
 }
 
 
@@ -232,17 +305,25 @@ TEST(RemoveInput) {
   Node* n1 = graph.NewNode(&dummy_operator, n0);
   Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
 
+  CHECK_INPUTS(n0, NONE);
+  CHECK_INPUTS(n1, n0);
+  CHECK_INPUTS(n2, n0, n1);
+  CHECK_USES(n0, n1, n2);
+
   n1->RemoveInput(0);
-  CHECK_EQ(0, n1->InputCount());
-  CHECK_EQ(1, n0->UseCount());
+  CHECK_INPUTS(n1, NONE);
+  CHECK_USES(n0, n2);
 
   n2->RemoveInput(0);
-  CHECK_EQ(1, n2->InputCount());
-  CHECK_EQ(0, n0->UseCount());
-  CHECK_EQ(1, n1->UseCount());
+  CHECK_INPUTS(n2, n1);
+  CHECK_USES(n0, NONE);
+  CHECK_USES(n1, n2);
 
   n2->RemoveInput(0);
-  CHECK_EQ(0, n2->InputCount());
+  CHECK_INPUTS(n2, NONE);
+  CHECK_USES(n0, NONE);
+  CHECK_USES(n1, NONE);
+  CHECK_USES(n2, NONE);
 }
 
 
@@ -253,33 +334,17 @@ TEST(AppendInputsAndIterator) {
   Node* n1 = graph.NewNode(&dummy_operator, n0);
   Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
 
-  Node::InputEdges inputs(n2->input_edges());
-  Node::InputEdges::iterator current = inputs.begin();
-  CHECK(current != inputs.end());
-  CHECK((*current).to() == n0);
-  ++current;
-  CHECK(current != inputs.end());
-  CHECK((*current).to() == n1);
-  ++current;
-  CHECK(current == inputs.end());
+  CHECK_INPUTS(n0, NONE);
+  CHECK_INPUTS(n1, n0);
+  CHECK_INPUTS(n2, n0, n1);
+  CHECK_USES(n0, n1, n2);
 
   Node* n3 = graph.NewNode(&dummy_operator);
+
   n2->AppendInput(graph.zone(), n3);
-  inputs = n2->input_edges();
-  current = inputs.begin();
-  CHECK(current != inputs.end());
-  CHECK((*current).to() == n0);
-  CHECK_EQ(0, (*current).index());
-  ++current;
-  CHECK(current != inputs.end());
-  CHECK((*current).to() == n1);
-  CHECK_EQ(1, (*current).index());
-  ++current;
-  CHECK(current != inputs.end());
-  CHECK((*current).to() == n3);
-  CHECK_EQ(2, (*current).index());
-  ++current;
-  CHECK(current == inputs.end());
+
+  CHECK_INPUTS(n2, n0, n1, n3);
+  CHECK_USES(n3, n2);
 }
 
 
@@ -289,15 +354,23 @@ TEST(NullInputsSimple) {
   Node* n0 = graph.NewNode(&dummy_operator);
   Node* n1 = graph.NewNode(&dummy_operator, n0);
   Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
-  CHECK_EQ(2, n2->InputCount());
-
-  CHECK(n0 == n2->InputAt(0));
-  CHECK(n1 == n2->InputAt(1));
-  CHECK_EQ(2, n0->UseCount());
-  n2->ReplaceInput(0, NULL);
-  CHECK(NULL == n2->InputAt(0));
-  CHECK(n1 == n2->InputAt(1));
-  CHECK_EQ(1, n0->UseCount());
+
+  CHECK_INPUTS(n0, NONE);
+  CHECK_INPUTS(n1, n0);
+  CHECK_INPUTS(n2, n0, n1);
+  CHECK_USES(n0, n1, n2);
+
+  n2->ReplaceInput(0, nullptr);
+
+  CHECK_INPUTS(n2, NULL, n1);
+
+  CHECK_USES(n0, n1);
+
+  n2->ReplaceInput(1, nullptr);
+
+  CHECK_INPUTS(n2, NULL, NULL);
+
+  CHECK_USES(n1, NONE);
 }
 
 
@@ -310,17 +383,16 @@ TEST(NullInputsAppended) {
   Node* n3 = graph.NewNode(&dummy_operator, n0);
   n3->AppendInput(graph.zone(), n1);
   n3->AppendInput(graph.zone(), n2);
-  CHECK_EQ(3, n3->InputCount());
 
-  CHECK(n0 == n3->InputAt(0));
-  CHECK(n1 == n3->InputAt(1));
-  CHECK(n2 == n3->InputAt(2));
-  CHECK_EQ(1, n1->UseCount());
+  CHECK_INPUTS(n3, n0, n1, n2);
+  CHECK_USES(n0, n1, n2, n3);
+  CHECK_USES(n1, n3);
+  CHECK_USES(n2, n3);
+
   n3->ReplaceInput(1, NULL);
-  CHECK(n0 == n3->InputAt(0));
-  CHECK(NULL == n3->InputAt(1));
-  CHECK(n2 == n3->InputAt(2));
-  CHECK_EQ(0, n1->UseCount());
+  CHECK_USES(n1, NONE);
+
+  CHECK_INPUTS(n3, n0, NULL, n2);
 }
 
 
@@ -331,26 +403,23 @@ TEST(ReplaceUsesFromAppendedInputs) {
   Node* n1 = graph.NewNode(&dummy_operator, n0);
   Node* n2 = graph.NewNode(&dummy_operator, n0);
   Node* n3 = graph.NewNode(&dummy_operator);
+
+  CHECK_INPUTS(n2, n0);
+
   n2->AppendInput(graph.zone(), n1);
+  CHECK_INPUTS(n2, n0, n1);
+  CHECK_USES(n1, n2);
+
   n2->AppendInput(graph.zone(), n0);
-  CHECK_EQ(0, n3->UseCount());
-  CHECK_EQ(3, n0->UseCount());
+  CHECK_INPUTS(n2, n0, n1, n0);
+  CHECK_USES(n1, n2);
+  CHECK_USES(n0, n2, n1, n2);
+
   n0->ReplaceUses(n3);
-  CHECK_EQ(0, n0->UseCount());
-  CHECK_EQ(3, n3->UseCount());
-
-  Node::Uses uses(n3->uses());
-  auto current = uses.begin();
-  CHECK(current != uses.end());
-  CHECK(*current == n1);
-  ++current;
-  CHECK(current != uses.end());
-  CHECK(*current == n2);
-  ++current;
-  CHECK(current != uses.end());
-  CHECK(*current == n2);
-  ++current;
-  CHECK(current == uses.end());
+
+  CHECK_USES(n0, NONE);
+  CHECK_INPUTS(n2, n3, n1, n3);
+  CHECK_USES(n3, n2, n1, n2);
 }
 
 
@@ -378,17 +447,16 @@ TEST(TrimInputCountInline) {
     Node* n0 = graph.NewNode(&dummy_operator);
     Node* n1 = graph.NewNode(&dummy_operator, n0);
     n1->TrimInputCount(1);
-    CHECK_EQ(1, n1->InputCount());
-    CHECK_EQ(n0, n1->InputAt(0));
-    CHECK_EQ(1, n0->UseCount());
+    CHECK_INPUTS(n1, n0);
+    CHECK_USES(n0, n1);
   }
 
   {
     Node* n0 = graph.NewNode(&dummy_operator);
     Node* n1 = graph.NewNode(&dummy_operator, n0);
     n1->TrimInputCount(0);
-    CHECK_EQ(0, n1->InputCount());
-    CHECK_EQ(0, n0->UseCount());
+    CHECK_INPUTS(n1, NONE);
+    CHECK_USES(n0, NONE);
   }
 
   {
@@ -396,10 +464,9 @@ TEST(TrimInputCountInline) {
     Node* n1 = graph.NewNode(&dummy_operator);
     Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
     n2->TrimInputCount(2);
-    CHECK_EQ(2, n2->InputCount());
-    CHECK_EQ(1, n0->UseCount());
-    CHECK_EQ(1, n1->UseCount());
-    CHECK_EQ(0, n2->UseCount());
+    CHECK_INPUTS(n2, n0, n1);
+    CHECK_USES(n0, n2);
+    CHECK_USES(n1, n2);
   }
 
   {
@@ -407,10 +474,9 @@ TEST(TrimInputCountInline) {
     Node* n1 = graph.NewNode(&dummy_operator);
     Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
     n2->TrimInputCount(1);
-    CHECK_EQ(1, n2->InputCount());
-    CHECK_EQ(1, n0->UseCount());
-    CHECK_EQ(0, n1->UseCount());
-    CHECK_EQ(0, n2->UseCount());
+    CHECK_INPUTS(n2, n0);
+    CHECK_USES(n0, n2);
+    CHECK_USES(n1, NONE);
   }
 
   {
@@ -418,28 +484,25 @@ TEST(TrimInputCountInline) {
     Node* n1 = graph.NewNode(&dummy_operator);
     Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
     n2->TrimInputCount(0);
-    CHECK_EQ(0, n2->InputCount());
-    CHECK_EQ(0, n0->UseCount());
-    CHECK_EQ(0, n1->UseCount());
-    CHECK_EQ(0, n2->UseCount());
+    CHECK_INPUTS(n2, NONE);
+    CHECK_USES(n0, NONE);
+    CHECK_USES(n1, NONE);
   }
 
   {
     Node* n0 = graph.NewNode(&dummy_operator);
     Node* n2 = graph.NewNode(&dummy_operator, n0, n0);
     n2->TrimInputCount(1);
-    CHECK_EQ(1, n2->InputCount());
-    CHECK_EQ(1, n0->UseCount());
-    CHECK_EQ(0, n2->UseCount());
+    CHECK_INPUTS(n2, n0);
+    CHECK_USES(n0, n2);
   }
 
   {
     Node* n0 = graph.NewNode(&dummy_operator);
     Node* n2 = graph.NewNode(&dummy_operator, n0, n0);
     n2->TrimInputCount(0);
-    CHECK_EQ(0, n2->InputCount());
-    CHECK_EQ(0, n0->UseCount());
-    CHECK_EQ(0, n2->UseCount());
+    CHECK_INPUTS(n2, NONE);
+    CHECK_USES(n0, NONE);
   }
 }
 
@@ -451,10 +514,12 @@ TEST(TrimInputCountOutOfLine1) {
     Node* n0 = graph.NewNode(&dummy_operator);
     Node* n1 = graph.NewNode(&dummy_operator);
     n1->AppendInput(graph.zone(), n0);
+    CHECK_INPUTS(n1, n0);
+    CHECK_USES(n0, n1);
+
     n1->TrimInputCount(1);
-    CHECK_EQ(1, n1->InputCount());
-    CHECK_EQ(n0, n1->InputAt(0));
-    CHECK_EQ(1, n0->UseCount());
+    CHECK_INPUTS(n1, n0);
+    CHECK_USES(n0, n1);
   }
 
   {
@@ -473,14 +538,12 @@ TEST(TrimInputCountOutOfLine1) {
     Node* n2 = graph.NewNode(&dummy_operator);
     n2->AppendInput(graph.zone(), n0);
     n2->AppendInput(graph.zone(), n1);
-    CHECK_EQ(2, n2->InputCount());
+    CHECK_INPUTS(n2, n0, n1);
     n2->TrimInputCount(2);
-    CHECK_EQ(2, n2->InputCount());
-    CHECK_EQ(n0, n2->InputAt(0));
-    CHECK_EQ(n1, n2->InputAt(1));
-    CHECK_EQ(1, n0->UseCount());
-    CHECK_EQ(1, n1->UseCount());
-    CHECK_EQ(0, n2->UseCount());
+    CHECK_INPUTS(n2, n0, n1);
+    CHECK_USES(n0, n2);
+    CHECK_USES(n1, n2);
+    CHECK_USES(n2, NONE);
   }
 
   {
@@ -489,13 +552,12 @@ TEST(TrimInputCountOutOfLine1) {
     Node* n2 = graph.NewNode(&dummy_operator);
     n2->AppendInput(graph.zone(), n0);
     n2->AppendInput(graph.zone(), n1);
-    CHECK_EQ(2, n2->InputCount());
+    CHECK_INPUTS(n2, n0, n1);
     n2->TrimInputCount(1);
-    CHECK_EQ(1, n2->InputCount());
-    CHECK_EQ(n0, n2->InputAt(0));
-    CHECK_EQ(1, n0->UseCount());
-    CHECK_EQ(0, n1->UseCount());
-    CHECK_EQ(0, n2->UseCount());
+    CHECK_INPUTS(n2, n0);
+    CHECK_USES(n0, n2);
+    CHECK_USES(n1, NONE);
+    CHECK_USES(n2, NONE);
   }
 
   {
@@ -504,12 +566,12 @@ TEST(TrimInputCountOutOfLine1) {
     Node* n2 = graph.NewNode(&dummy_operator);
     n2->AppendInput(graph.zone(), n0);
     n2->AppendInput(graph.zone(), n1);
-    CHECK_EQ(2, n2->InputCount());
+    CHECK_INPUTS(n2, n0, n1);
     n2->TrimInputCount(0);
-    CHECK_EQ(0, n2->InputCount());
-    CHECK_EQ(0, n0->UseCount());
-    CHECK_EQ(0, n1->UseCount());
-    CHECK_EQ(0, n2->UseCount());
+    CHECK_INPUTS(n2, NONE);
+    CHECK_USES(n0, NONE);
+    CHECK_USES(n1, NONE);
+    CHECK_USES(n2, NONE);
   }
 
   {
@@ -517,12 +579,11 @@ TEST(TrimInputCountOutOfLine1) {
     Node* n2 = graph.NewNode(&dummy_operator);
     n2->AppendInput(graph.zone(), n0);
     n2->AppendInput(graph.zone(), n0);
-    CHECK_EQ(2, n2->InputCount());
-    CHECK_EQ(2, n0->UseCount());
+    CHECK_INPUTS(n2, n0, n0);
+    CHECK_USES(n0, n2, n2);
     n2->TrimInputCount(1);
-    CHECK_EQ(1, n2->InputCount());
-    CHECK_EQ(1, n0->UseCount());
-    CHECK_EQ(0, n2->UseCount());
+    CHECK_INPUTS(n2, n0);
+    CHECK_USES(n0, n2);
   }
 
   {
@@ -530,12 +591,11 @@ TEST(TrimInputCountOutOfLine1) {
     Node* n2 = graph.NewNode(&dummy_operator);
     n2->AppendInput(graph.zone(), n0);
     n2->AppendInput(graph.zone(), n0);
-    CHECK_EQ(2, n2->InputCount());
-    CHECK_EQ(2, n0->UseCount());
+    CHECK_INPUTS(n2, n0, n0);
+    CHECK_USES(n0, n2, n2);
     n2->TrimInputCount(0);
-    CHECK_EQ(0, n2->InputCount());
-    CHECK_EQ(0, n0->UseCount());
-    CHECK_EQ(0, n2->UseCount());
+    CHECK_INPUTS(n2, NONE);
+    CHECK_USES(n0, NONE);
   }
 }
 
@@ -548,14 +608,12 @@ TEST(TrimInputCountOutOfLine2) {
     Node* n1 = graph.NewNode(&dummy_operator);
     Node* n2 = graph.NewNode(&dummy_operator, n0);
     n2->AppendInput(graph.zone(), n1);
-    CHECK_EQ(2, n2->InputCount());
+    CHECK_INPUTS(n2, n0, n1);
     n2->TrimInputCount(2);
-    CHECK_EQ(2, n2->InputCount());
-    CHECK_EQ(n0, n2->InputAt(0));
-    CHECK_EQ(n1, n2->InputAt(1));
-    CHECK_EQ(1, n0->UseCount());
-    CHECK_EQ(1, n1->UseCount());
-    CHECK_EQ(0, n2->UseCount());
+    CHECK_INPUTS(n2, n0, n1);
+    CHECK_USES(n0, n2);
+    CHECK_USES(n1, n2);
+    CHECK_USES(n2, NONE);
   }
 
   {
@@ -563,13 +621,12 @@ TEST(TrimInputCountOutOfLine2) {
     Node* n1 = graph.NewNode(&dummy_operator);
     Node* n2 = graph.NewNode(&dummy_operator, n0);
     n2->AppendInput(graph.zone(), n1);
-    CHECK_EQ(2, n2->InputCount());
+    CHECK_INPUTS(n2, n0, n1);
     n2->TrimInputCount(1);
-    CHECK_EQ(1, n2->InputCount());
-    CHECK_EQ(n0, n2->InputAt(0));
-    CHECK_EQ(1, n0->UseCount());
-    CHECK_EQ(0, n1->UseCount());
-    CHECK_EQ(0, n2->UseCount());
+    CHECK_INPUTS(n2, n0);
+    CHECK_USES(n0, n2);
+    CHECK_USES(n1, NONE);
+    CHECK_USES(n2, NONE);
   }
 
   {
@@ -577,24 +634,24 @@ TEST(TrimInputCountOutOfLine2) {
     Node* n1 = graph.NewNode(&dummy_operator);
     Node* n2 = graph.NewNode(&dummy_operator, n0);
     n2->AppendInput(graph.zone(), n1);
-    CHECK_EQ(2, n2->InputCount());
+    CHECK_INPUTS(n2, n0, n1);
     n2->TrimInputCount(0);
-    CHECK_EQ(0, n2->InputCount());
-    CHECK_EQ(0, n0->UseCount());
-    CHECK_EQ(0, n1->UseCount());
-    CHECK_EQ(0, n2->UseCount());
+    CHECK_INPUTS(n2, NONE);
+    CHECK_USES(n0, NONE);
+    CHECK_USES(n1, NONE);
+    CHECK_USES(n2, NONE);
   }
 
   {
     Node* n0 = graph.NewNode(&dummy_operator);
     Node* n2 = graph.NewNode(&dummy_operator, n0);
     n2->AppendInput(graph.zone(), n0);
-    CHECK_EQ(2, n2->InputCount());
-    CHECK_EQ(2, n0->UseCount());
+    CHECK_INPUTS(n2, n0, n0);
+    CHECK_USES(n0, n2, n2);
     n2->TrimInputCount(1);
-    CHECK_EQ(1, n2->InputCount());
-    CHECK_EQ(1, n0->UseCount());
-    CHECK_EQ(0, n2->UseCount());
+    CHECK_INPUTS(n2, n0);
+    CHECK_USES(n0, n2);
+    CHECK_USES(n2, NONE);
   }
 
   {
@@ -611,7 +668,7 @@ TEST(TrimInputCountOutOfLine2) {
 }
 
 
-TEST(RemoveAllInputs) {
+TEST(NullAllInputs) {
   GraphTester graph;
 
   for (int i = 0; i < 2; i++) {
@@ -620,27 +677,27 @@ TEST(RemoveAllInputs) {
     Node* n2;
     if (i == 0) {
       n2 = graph.NewNode(&dummy_operator, n0, n1);
+      CHECK_INPUTS(n2, n0, n1);
     } else {
       n2 = graph.NewNode(&dummy_operator, n0);
+      CHECK_INPUTS(n2, n0);
       n2->AppendInput(graph.zone(), n1);  // with out-of-line input.
+      CHECK_INPUTS(n2, n0, n1);
     }
 
-    n0->RemoveAllInputs();
-    CHECK_EQ(0, n0->InputCount());
+    n0->NullAllInputs();
+    CHECK_INPUTS(n0, NONE);
 
-    CHECK_EQ(2, n0->UseCount());
-    n1->RemoveAllInputs();
-    CHECK_EQ(1, n1->InputCount());
-    CHECK_EQ(1, n0->UseCount());
-    CHECK(!n1->InputAt(0));
+    CHECK_USES(n0, n1, n2);
+    n1->NullAllInputs();
+    CHECK_INPUTS(n1, NULL);
+    CHECK_INPUTS(n2, n0, n1);
+    CHECK_USES(n0, n2);
 
-    CHECK_EQ(1, n1->UseCount());
-    n2->RemoveAllInputs();
-    CHECK_EQ(2, n2->InputCount());
-    CHECK_EQ(0, n0->UseCount());
-    CHECK_EQ(0, n1->UseCount());
-    CHECK(!n2->InputAt(0));
-    CHECK(!n2->InputAt(1));
+    n2->NullAllInputs();
+    CHECK_INPUTS(n1, NULL);
+    CHECK_INPUTS(n2, NULL, NULL);
+    CHECK_USES(n0, NONE);
   }
 
   {
@@ -648,11 +705,53 @@ TEST(RemoveAllInputs) {
     Node* n1 = graph.NewNode(&dummy_operator, n0);
     n1->ReplaceInput(0, n1);  // self-reference.
 
-    CHECK_EQ(0, n0->UseCount());
-    CHECK_EQ(1, n1->UseCount());
-    n1->RemoveAllInputs();
-    CHECK_EQ(1, n1->InputCount());
-    CHECK_EQ(0, n1->UseCount());
-    CHECK(!n1->InputAt(0));
+    CHECK_INPUTS(n0, NONE);
+    CHECK_INPUTS(n1, n1);
+    CHECK_USES(n0, NONE);
+    CHECK_USES(n1, n1);
+    n1->NullAllInputs();
+
+    CHECK_INPUTS(n0, NONE);
+    CHECK_INPUTS(n1, NULL);
+    CHECK_USES(n0, NONE);
+    CHECK_USES(n1, NONE);
+  }
+}
+
+
+TEST(AppendAndTrim) {
+  GraphTester graph;
+
+  Node* nodes[] = {
+      graph.NewNode(&dummy_operator), graph.NewNode(&dummy_operator),
+      graph.NewNode(&dummy_operator), graph.NewNode(&dummy_operator),
+      graph.NewNode(&dummy_operator)};
+
+  int max = static_cast<int>(arraysize(nodes));
+
+  Node* last = graph.NewNode(&dummy_operator);
+
+  for (int i = 0; i < max; i++) {
+    last->AppendInput(graph.zone(), nodes[i]);
+    CheckInputs(last, nodes, i + 1);
+
+    for (int j = 0; j < max; j++) {
+      if (j <= i) CHECK_USES(nodes[j], last);
+      if (j > i) CHECK_USES(nodes[j], NONE);
+    }
+
+    CHECK_USES(last, NONE);
+  }
+
+  for (int i = max; i >= 0; i--) {
+    last->TrimInputCount(i);
+    CheckInputs(last, nodes, i);
+
+    for (int j = 0; j < i; j++) {
+      if (j < i) CHECK_USES(nodes[j], last);
+      if (j >= i) CHECK_USES(nodes[j], NONE);
+    }
+
+    CHECK_USES(last, NONE);
   }
 }
index e396390..d217118 100644 (file)
@@ -36,6 +36,8 @@ static int CheckInputs(Node* node, Node* i0 = NULL, Node* i1 = NULL,
 
 static Operator kIntLt(IrOpcode::kInt32LessThan, Operator::kPure,
                        "Int32LessThan", 2, 0, 0, 1, 0, 0);
+static Operator kIntAdd(IrOpcode::kInt32Add, Operator::kPure, "Int32Add", 2, 0,
+                        0, 1, 0, 0);
 
 
 static const int kMaxOsrValues = 10;
@@ -122,7 +124,12 @@ class OsrDeconstructorTester : public HandleAndZoneScope {
     CHECK(!nodes.IsLive(osr_normal_entry));
     CHECK(!nodes.IsLive(osr_loop_entry));
     // No dangling nodes should be left over.
-    CHECK_EQ(0u, nodes.gray.size());
+    for (Node* const node : nodes.live) {
+      for (Node* const use : node->uses()) {
+        CHECK(std::find(nodes.live.begin(), nodes.live.end(), use) !=
+              nodes.live.end());
+      }
+    }
   }
 };
 
@@ -484,3 +491,105 @@ TEST(Deconstruct_osr_nested2) {
   CheckInputs(new_outer_phi, new_entry_phi, new_inner_phi,
               T.jsgraph.ZeroConstant(), new_outer_loop);
 }
+
+
+Node* MakeCounter(JSGraph* jsgraph, Node* start, Node* loop) {
+  int count = loop->InputCount();
+  NodeVector tmp_inputs(jsgraph->graph()->zone());
+  for (int i = 0; i < count; i++) {
+    tmp_inputs.push_back(start);
+  }
+  tmp_inputs.push_back(loop);
+
+  Node* phi = jsgraph->graph()->NewNode(
+      jsgraph->common()->Phi(kMachInt32, count), count + 1, &tmp_inputs[0]);
+  Node* inc = jsgraph->graph()->NewNode(&kIntAdd, phi, jsgraph->OneConstant());
+
+  for (int i = 1; i < count; i++) {
+    phi->ReplaceInput(i, inc);
+  }
+  return phi;
+}
+
+
+TEST(Deconstruct_osr_nested3) {
+  OsrDeconstructorTester T(1);
+
+  // outermost loop.
+  While loop0(T, T.p0, false, 1);
+  Node* loop0_cntr = MakeCounter(&T.jsgraph, T.p0, loop0.loop);
+  loop0.branch->ReplaceInput(0, loop0_cntr);
+
+  // middle loop.
+  Node* loop1 = T.graph.NewNode(T.common.Loop(2), loop0.if_true, T.self);
+  loop1->ReplaceInput(0, loop0.if_true);
+  Node* loop1_phi =
+      T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), loop0_cntr, loop0_cntr);
+
+  // innermost (OSR) loop.
+  While loop2(T, T.p0, true, 1);
+  loop2.loop->ReplaceInput(0, loop1);
+
+  Node* loop2_cntr = MakeCounter(&T.jsgraph, loop1_phi, loop2.loop);
+  loop2_cntr->ReplaceInput(1, T.osr_values[0]);
+  Node* osr_phi = loop2_cntr;
+  Node* loop2_inc = loop2_cntr->InputAt(2);
+  loop2.branch->ReplaceInput(0, loop2_cntr);
+
+  loop1_phi->ReplaceInput(1, loop2_cntr);
+  loop0_cntr->ReplaceInput(1, loop2_cntr);
+
+  // Branch to either the outer or middle loop.
+  Node* branch = T.graph.NewNode(T.common.Branch(), loop2_cntr, loop2.exit);
+  Node* if_true = T.graph.NewNode(T.common.IfTrue(), branch);
+  Node* if_false = T.graph.NewNode(T.common.IfFalse(), branch);
+
+  loop0.loop->ReplaceInput(1, if_true);
+  loop1->ReplaceInput(1, if_false);
+
+  Node* ret =
+      T.graph.NewNode(T.common.Return(), loop0_cntr, T.start, loop0.exit);
+  Node* end = T.graph.NewNode(T.common.End(), ret);
+  T.graph.SetEnd(end);
+
+  T.DeconstructOsr();
+
+  // Check structure of deconstructed graph.
+  // Check loop2 (OSR loop) is directly connected to start.
+  CheckInputs(loop2.loop, T.start, loop2.if_true);
+  CheckInputs(osr_phi, T.osr_values[0], loop2_inc, loop2.loop);
+  CheckInputs(loop2.branch, osr_phi, loop2.loop);
+  CheckInputs(loop2.if_true, loop2.branch);
+  CheckInputs(loop2.exit, loop2.branch);
+  CheckInputs(branch, osr_phi, loop2.exit);
+  CheckInputs(if_true, branch);
+  CheckInputs(if_false, branch);
+
+  // Check structure of new_loop1.
+  Node* new_loop1_loop = FindSuccessor(if_false, IrOpcode::kLoop);
+  // TODO(titzer): check the internal copy of loop2.
+  USE(new_loop1_loop);
+
+  // Check structure of new_loop0.
+  Node* new_loop0_loop_entry = FindSuccessor(if_true, IrOpcode::kMerge);
+  Node* new_loop0_loop = FindSuccessor(new_loop0_loop_entry, IrOpcode::kLoop);
+  // TODO(titzer): check the internal copies of loop1 and loop2.
+
+  Node* new_loop0_branch = FindSuccessor(new_loop0_loop, IrOpcode::kBranch);
+  Node* new_loop0_if_true = FindSuccessor(new_loop0_branch, IrOpcode::kIfTrue);
+  Node* new_loop0_exit = FindSuccessor(new_loop0_branch, IrOpcode::kIfFalse);
+
+  USE(new_loop0_if_true);
+
+  Node* new_ret = T.graph.end()->InputAt(0);
+  CHECK_EQ(IrOpcode::kReturn, new_ret->opcode());
+
+  Node* new_loop0_phi = new_ret->InputAt(0);
+  CHECK_EQ(IrOpcode::kPhi, new_loop0_phi->opcode());
+  CHECK_EQ(new_loop0_loop, NodeProperties::GetControlInput(new_loop0_phi));
+  CHECK_EQ(new_loop0_phi, FindSuccessor(new_loop0_loop, IrOpcode::kPhi));
+
+  // Check that the return returns the phi from the OSR loop and control
+  // depends on the copy of the outer loop0.
+  CheckInputs(new_ret, new_loop0_phi, T.graph.start(), new_loop0_exit);
+}
index 98b0bae..b67af6e 100644 (file)
@@ -17,13 +17,13 @@ using namespace v8::internal;
 using namespace v8::internal::compiler;
 
 TEST(PipelineAdd) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
   const char* source = "(function(a,b) { return a + b; })";
   Handle<JSFunction> function = v8::Utils::OpenHandle(
       *v8::Handle<v8::Function>::Cast(CompileRun(source)));
-  CompilationInfoWithZone info(function);
-
-  CHECK(Compiler::ParseAndAnalyze(&info));
+  ParseInfo parse_info(handles.main_zone(), function);
+  CHECK(Compiler::ParseAndAnalyze(&parse_info));
+  CompilationInfo info(&parse_info);
 
   Pipeline pipeline(&info);
 #if V8_TURBOFAN_TARGET
index 19b96ba..a6d76e4 100644 (file)
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
+namespace {
+
 // Helper to determine inline count via JavaScriptFrame::GetInlineCount.
 // Note that a count of 1 indicates that no inlining has occured.
-static void AssertInlineCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
+void AssertInlineCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
   StackTraceFrameIterator it(CcTest::i_isolate());
   int frames_seen = 0;
   JavaScriptFrame* topmost = it.frame();
@@ -30,7 +32,7 @@ static void AssertInlineCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
 }
 
 
-static void InstallAssertInlineCountHelper(v8::Isolate* isolate) {
+void InstallAssertInlineCountHelper(v8::Isolate* isolate) {
   v8::Local<v8::Context> context = isolate->GetCurrentContext();
   v8::Local<v8::FunctionTemplate> t =
       v8::FunctionTemplate::New(isolate, AssertInlineCount);
@@ -38,9 +40,15 @@ static void InstallAssertInlineCountHelper(v8::Isolate* isolate) {
 }
 
 
-static uint32_t kInlineFlags = CompilationInfo::kInliningEnabled |
-                               CompilationInfo::kContextSpecializing |
-                               CompilationInfo::kTypingEnabled;
+const uint32_t kBuiltinInlineFlags = CompilationInfo::kBuiltinInliningEnabled |
+                                     CompilationInfo::kContextSpecializing |
+                                     CompilationInfo::kTypingEnabled;
+
+const uint32_t kInlineFlags = CompilationInfo::kInliningEnabled |
+                              CompilationInfo::kContextSpecializing |
+                              CompilationInfo::kTypingEnabled;
+
+}  // namespace
 
 
 TEST(SimpleInlining) {
@@ -320,6 +328,53 @@ TEST(InlineLoopGuardedTwice) {
 }
 
 
+TEST(InlineLoopUnguardedEmpty) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s) { AssertInlineCount(2); while (s); return s; };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4));
+}
+
+
+TEST(InlineLoopUnguardedOnce) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s) { AssertInlineCount(2); while (s) {"
+      "                    s = s - 1; }; return s; };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4));
+}
+
+
+TEST(InlineLoopUnguardedTwice) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s) { AssertInlineCount(2); 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(0.0), T.Val(4));
+}
+
+
 TEST(InlineStrictIntoNonStrict) {
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
@@ -437,4 +492,38 @@ TEST(InlineWithArguments) {
   T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
 }
 
+
+TEST(InlineBuiltin) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s,t,u) { AssertInlineCount(2); return true; }"
+      "  function bar() { return foo(); };"
+      "  %SetInlineBuiltinFlag(foo);"
+      "  return bar;"
+      "})();",
+      kBuiltinInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value());
+}
+
+
+TEST(InlineNestedBuiltin) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s,t,u) { AssertInlineCount(3); return true; }"
+      "  function baz(s,t,u) { return foo(s,t,u); }"
+      "  function bar() { return baz(); };"
+      "  %SetInlineBuiltinFlag(foo);"
+      "  %SetInlineBuiltinFlag(baz);"
+      "  return bar;"
+      "})();",
+      kBuiltinInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value());
+}
+
 #endif  // V8_TURBOFAN_TARGET
index bd4038e..7fc5cc9 100644 (file)
@@ -10,29 +10,98 @@ using namespace v8::internal;
 using namespace v8::internal::compiler;
 uint32_t flags = CompilationInfo::kInliningEnabled;
 
-TEST(IsSmi) {
+
+TEST(CallFunction) {
   FLAG_turbo_deoptimization = true;
-  FunctionTester T("(function(a) { return %_IsSmi(a); })", flags);
+  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.CheckTrue(T.Val(1));
-  T.CheckFalse(T.Val(1.1));
-  T.CheckFalse(T.Val(-0.0));
-  T.CheckTrue(T.Val(-2));
-  T.CheckFalse(T.Val(-2.3));
+  T.CheckCall(T.Val(129), T.NewObject("({d:123})"), T.NewObject("f"));
+  T.CheckCall(T.Val("6x"), T.NewObject("({d:'x'})"), T.NewObject("f"));
+}
+
+
+TEST(ClassOf) {
+  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])"));
+  T.CheckCall(T.Val("Object"), T.NewObject("({})"));
+  T.CheckCall(T.Val("RegExp"), T.NewObject("(/x/)"));
+  T.CheckCall(T.null(), T.undefined());
+  T.CheckCall(T.null(), T.null());
+  T.CheckCall(T.null(), T.Val("x"));
+  T.CheckCall(T.null(), T.Val(1));
+}
+
+
+TEST(HeapObjectGetMap) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_HeapObjectGetMap(a); })", flags);
+
+  Factory* factory = T.main_isolate()->factory();
+  T.CheckCall(factory->null_map(), T.null());
+  T.CheckCall(factory->undefined_map(), T.undefined());
+  T.CheckCall(factory->heap_number_map(), T.Val(3.1415));
+  T.CheckCall(factory->symbol_map(), factory->NewSymbol());
+}
+
+
+#define COUNTER_NAME "hurz"
+
+static int* LookupCounter(const char* name) {
+  static int counter = 1234;
+  return strcmp(name, COUNTER_NAME) == 0 ? &counter : nullptr;
+}
+
+
+TEST(IncrementStatsCounter) {
+  FLAG_turbo_deoptimization = true;
+  FLAG_native_code_counters = true;
+  reinterpret_cast<v8::Isolate*>(CcTest::InitIsolateOnce())
+      ->SetCounterFunction(LookupCounter);
+  FunctionTester T(
+      "(function() { %_IncrementStatsCounter('" COUNTER_NAME "'); })", flags);
+  StatsCounter counter(T.main_isolate(), COUNTER_NAME);
+  if (!counter.Enabled()) return;
+
+  int old_value = *counter.GetInternalPointer();
+  T.CheckCall(T.undefined());
+  CHECK_EQ(old_value + 1, *counter.GetInternalPointer());
+}
+
+#undef COUNTER_NAME
+
+
+TEST(IsArray) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsArray(a); })", flags);
+
+  T.CheckFalse(T.NewObject("(function() {})"));
+  T.CheckTrue(T.NewObject("([1])"));
+  T.CheckFalse(T.NewObject("({})"));
+  T.CheckFalse(T.NewObject("(/x/)"));
   T.CheckFalse(T.undefined());
+  T.CheckFalse(T.null());
+  T.CheckFalse(T.Val("x"));
+  T.CheckFalse(T.Val(1));
 }
 
 
-TEST(IsNonNegativeSmi) {
+TEST(IsFunction) {
   FLAG_turbo_deoptimization = true;
-  FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })", flags);
+  FunctionTester T("(function(a) { return %_IsFunction(a); })", flags);
 
-  T.CheckTrue(T.Val(1));
-  T.CheckFalse(T.Val(1.1));
-  T.CheckFalse(T.Val(-0.0));
-  T.CheckFalse(T.Val(-2));
-  T.CheckFalse(T.Val(-2.3));
+  T.CheckTrue(T.NewObject("(function() {})"));
+  T.CheckFalse(T.NewObject("([1])"));
+  T.CheckFalse(T.NewObject("({})"));
+  T.CheckFalse(T.NewObject("(/x/)"));
   T.CheckFalse(T.undefined());
+  T.CheckFalse(T.null());
+  T.CheckFalse(T.Val("x"));
+  T.CheckFalse(T.Val(1));
 }
 
 
@@ -49,18 +118,16 @@ TEST(IsMinusZero) {
 }
 
 
-TEST(IsArray) {
+TEST(IsNonNegativeSmi) {
   FLAG_turbo_deoptimization = true;
-  FunctionTester T("(function(a) { return %_IsArray(a); })", flags);
+  FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })", flags);
 
-  T.CheckFalse(T.NewObject("(function() {})"));
-  T.CheckTrue(T.NewObject("([1])"));
-  T.CheckFalse(T.NewObject("({})"));
-  T.CheckFalse(T.NewObject("(/x/)"));
+  T.CheckTrue(T.Val(1));
+  T.CheckFalse(T.Val(1.1));
+  T.CheckFalse(T.Val(-0.0));
+  T.CheckFalse(T.Val(-2));
+  T.CheckFalse(T.Val(-2.3));
   T.CheckFalse(T.undefined());
-  T.CheckFalse(T.null());
-  T.CheckFalse(T.Val("x"));
-  T.CheckFalse(T.Val(1));
 }
 
 
@@ -79,14 +146,14 @@ TEST(IsObject) {
 }
 
 
-TEST(IsFunction) {
+TEST(IsRegExp) {
   FLAG_turbo_deoptimization = true;
-  FunctionTester T("(function(a) { return %_IsFunction(a); })", flags);
+  FunctionTester T("(function(a) { return %_IsRegExp(a); })", flags);
 
-  T.CheckTrue(T.NewObject("(function() {})"));
+  T.CheckFalse(T.NewObject("(function() {})"));
   T.CheckFalse(T.NewObject("([1])"));
   T.CheckFalse(T.NewObject("({})"));
-  T.CheckFalse(T.NewObject("(/x/)"));
+  T.CheckTrue(T.NewObject("(/x/)"));
   T.CheckFalse(T.undefined());
   T.CheckFalse(T.null());
   T.CheckFalse(T.Val("x"));
@@ -94,33 +161,30 @@ TEST(IsFunction) {
 }
 
 
-TEST(IsRegExp) {
+TEST(IsSmi) {
   FLAG_turbo_deoptimization = true;
-  FunctionTester T("(function(a) { return %_IsRegExp(a); })", flags);
+  FunctionTester T("(function(a) { return %_IsSmi(a); })", flags);
 
-  T.CheckFalse(T.NewObject("(function() {})"));
-  T.CheckFalse(T.NewObject("([1])"));
-  T.CheckFalse(T.NewObject("({})"));
-  T.CheckTrue(T.NewObject("(/x/)"));
+  T.CheckTrue(T.Val(1));
+  T.CheckFalse(T.Val(1.1));
+  T.CheckFalse(T.Val(-0.0));
+  T.CheckTrue(T.Val(-2));
+  T.CheckFalse(T.Val(-2.3));
   T.CheckFalse(T.undefined());
-  T.CheckFalse(T.null());
-  T.CheckFalse(T.Val("x"));
-  T.CheckFalse(T.Val(1));
 }
 
 
-TEST(ClassOf) {
+TEST(MapGetInstanceType) {
   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])"));
-  T.CheckCall(T.Val("Object"), T.NewObject("({})"));
-  T.CheckCall(T.Val("RegExp"), T.NewObject("(/x/)"));
-  T.CheckCall(T.null(), T.undefined());
-  T.CheckCall(T.null(), T.null());
-  T.CheckCall(T.null(), T.Val("x"));
-  T.CheckCall(T.null(), T.Val(1));
+  FunctionTester T(
+      "(function(a) { return %_MapGetInstanceType(%_HeapObjectGetMap(a)); })",
+      flags);
+
+  Factory* factory = T.main_isolate()->factory();
+  T.CheckCall(T.Val(ODDBALL_TYPE), T.null());
+  T.CheckCall(T.Val(ODDBALL_TYPE), T.undefined());
+  T.CheckCall(T.Val(HEAP_NUMBER_TYPE), T.Val(3.1415));
+  T.CheckCall(T.Val(SYMBOL_TYPE), factory->NewSymbol());
 }
 
 
@@ -138,14 +202,48 @@ TEST(ObjectEquals) {
 }
 
 
-TEST(ValueOf) {
+TEST(OneByteSeqStringGetChar) {
   FLAG_turbo_deoptimization = true;
-  FunctionTester T("(function(a) { return %_ValueOf(a); })", flags);
+  FunctionTester T("(function(a,b) { return %_OneByteSeqStringGetChar(a,b); })",
+                   flags);
 
-  T.CheckCall(T.Val("a"), T.Val("a"));
-  T.CheckCall(T.Val("b"), T.NewObject("(new String('b'))"));
-  T.CheckCall(T.Val(123), T.Val(123));
-  T.CheckCall(T.Val(456), T.NewObject("(new Number(456))"));
+  Handle<SeqOneByteString> string =
+      T.main_isolate()->factory()->NewRawOneByteString(3).ToHandleChecked();
+  string->SeqOneByteStringSet(0, 'b');
+  string->SeqOneByteStringSet(1, 'a');
+  string->SeqOneByteStringSet(2, 'r');
+  T.CheckCall(T.Val('b'), string, T.Val(0.0));
+  T.CheckCall(T.Val('a'), string, T.Val(1));
+  T.CheckCall(T.Val('r'), string, T.Val(2));
+}
+
+
+TEST(OneByteSeqStringSetChar) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { %_OneByteSeqStringSetChar(a,88,b); })",
+                   flags);
+
+  Handle<SeqOneByteString> string =
+      T.main_isolate()->factory()->NewRawOneByteString(3).ToHandleChecked();
+  string->SeqOneByteStringSet(0, 'b');
+  string->SeqOneByteStringSet(1, 'a');
+  string->SeqOneByteStringSet(2, 'r');
+  T.Call(T.Val(1), string);
+  CHECK_EQ('b', string->SeqOneByteStringGet(0));
+  CHECK_EQ('X', string->SeqOneByteStringGet(1));
+  CHECK_EQ('r', string->SeqOneByteStringGet(2));
+}
+
+
+TEST(NewConsString) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function() { "
+      "   return %_NewConsString(14, true, 'abcdefghi', 'jklmn');"
+      " })",
+      flags);
+
+  T.CheckCall(T.Val("abcdefghijklmn"));
 }
 
 
@@ -159,13 +257,13 @@ TEST(SetValueOf) {
 }
 
 
-TEST(StringCharFromCode) {
+TEST(StringAdd) {
   FLAG_turbo_deoptimization = true;
-  FunctionTester T("(function(a) { return %_StringCharFromCode(a); })", flags);
+  FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags);
 
-  T.CheckCall(T.Val("a"), T.Val(97));
-  T.CheckCall(T.Val("\xE2\x9D\x8A"), T.Val(0x274A));
-  T.CheckCall(T.Val(""), T.undefined());
+  T.CheckCall(T.Val("aaabbb"), T.Val("aaa"), T.Val("bbb"));
+  T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val(""));
+  T.CheckCall(T.Val("bbb"), T.Val(""), T.Val("bbb"));
 }
 
 
@@ -190,17 +288,27 @@ TEST(StringCharCodeAt) {
 }
 
 
-TEST(StringAdd) {
+TEST(StringCharFromCode) {
   FLAG_turbo_deoptimization = true;
-  FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags);
+  FunctionTester T("(function(a) { return %_StringCharFromCode(a); })", flags);
 
-  T.CheckCall(T.Val("aaabbb"), T.Val("aaa"), T.Val("bbb"));
-  T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val(""));
-  T.CheckCall(T.Val("bbb"), T.Val(""), T.Val("bbb"));
+  T.CheckCall(T.Val("a"), T.Val(97));
+  T.CheckCall(T.Val("\xE2\x9D\x8A"), T.Val(0x274A));
+  T.CheckCall(T.Val(""), T.undefined());
+}
+
+
+TEST(StringCompare) {
+  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"));
+  T.CheckCall(T.Val(+1), T.Val("ccc"), T.Val("bbb"));
 }
 
 
-TEST(StringSubString) {
+TEST(SubString) {
   FLAG_turbo_deoptimization = true;
   FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })", flags);
 
@@ -210,22 +318,45 @@ TEST(StringSubString) {
 }
 
 
-TEST(StringCompare) {
+TEST(TwoByteSeqStringGetChar) {
   FLAG_turbo_deoptimization = true;
-  FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })", flags);
+  FunctionTester T("(function(a,b) { return %_TwoByteSeqStringGetChar(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"));
-  T.CheckCall(T.Val(+1), T.Val("ccc"), T.Val("bbb"));
+  Handle<SeqTwoByteString> string =
+      T.main_isolate()->factory()->NewRawTwoByteString(3).ToHandleChecked();
+  string->SeqTwoByteStringSet(0, 'b');
+  string->SeqTwoByteStringSet(1, 'a');
+  string->SeqTwoByteStringSet(2, 'r');
+  T.CheckCall(T.Val('b'), string, T.Val(0.0));
+  T.CheckCall(T.Val('a'), string, T.Val(1));
+  T.CheckCall(T.Val('r'), string, T.Val(2));
 }
 
 
-TEST(CallFunction) {
+TEST(TwoByteSeqStringSetChar) {
   FLAG_turbo_deoptimization = true;
-  FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })",
+  FunctionTester T("(function(a,b) { %_TwoByteSeqStringSetChar(a,88,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"));
-  T.CheckCall(T.Val("6x"), T.NewObject("({d:'x'})"), T.NewObject("f"));
+  Handle<SeqTwoByteString> string =
+      T.main_isolate()->factory()->NewRawTwoByteString(3).ToHandleChecked();
+  string->SeqTwoByteStringSet(0, 'b');
+  string->SeqTwoByteStringSet(1, 'a');
+  string->SeqTwoByteStringSet(2, 'r');
+  T.Call(T.Val(1), string);
+  CHECK_EQ('b', string->SeqTwoByteStringGet(0));
+  CHECK_EQ('X', string->SeqTwoByteStringGet(1));
+  CHECK_EQ('r', string->SeqTwoByteStringGet(2));
+}
+
+
+TEST(ValueOf) {
+  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'))"));
+  T.CheckCall(T.Val(123), T.Val(123));
+  T.CheckCall(T.Val(456), T.NewObject("(new Number(456))"));
 }
index 74990da..f06dc5f 100644 (file)
@@ -18,7 +18,8 @@ TEST(Throw) {
 }
 
 
-TEST(ThrowSourcePosition) {
+TEST(ThrowMessagePosition) {
+  i::FLAG_turbo_exceptions = true;
   static const char* src =
       "(function(a, b) {        \n"
       "  if (a == 1) throw 1;   \n"
@@ -30,22 +31,57 @@ TEST(ThrowSourcePosition) {
   v8::Handle<v8::Message> message;
 
   message = T.CheckThrowsReturnMessage(T.Val(1), T.undefined());
-  CHECK(!message.IsEmpty());
   CHECK_EQ(2, message->GetLineNumber());
   CHECK_EQ(40, message->GetStartPosition());
 
   message = T.CheckThrowsReturnMessage(T.Val(2), T.undefined());
-  CHECK(!message.IsEmpty());
   CHECK_EQ(3, message->GetLineNumber());
   CHECK_EQ(67, message->GetStartPosition());
 
   message = T.CheckThrowsReturnMessage(T.Val(3), T.undefined());
-  CHECK(!message.IsEmpty());
   CHECK_EQ(4, message->GetLineNumber());
   CHECK_EQ(95, message->GetStartPosition());
 }
 
 
+TEST(ThrowMessageDirectly) {
+  i::FLAG_turbo_exceptions = true;
+  static const char* src =
+      "(function(a, b) {"
+      "  if (a) { throw b; } else { throw new Error(b); }"
+      "})";
+  FunctionTester T(src);
+  v8::Handle<v8::Message> message;
+
+  message = T.CheckThrowsReturnMessage(T.false_value(), T.Val("Wat?"));
+  CHECK(message->Get()->Equals(v8_str("Uncaught Error: Wat?")));
+
+  message = T.CheckThrowsReturnMessage(T.true_value(), T.Val("Kaboom!"));
+  CHECK(message->Get()->Equals(v8_str("Uncaught Kaboom!")));
+}
+
+
+TEST(ThrowMessageIndirectly) {
+  i::FLAG_turbo_exceptions = true;
+  static const char* src =
+      "(function(a, b) {"
+      "  try {"
+      "    if (a) { throw b; } else { throw new Error(b); }"
+      "  } finally {"
+      "    try { throw 'clobber'; } catch (e) { 'unclobber'; }"
+      "  }"
+      "})";
+  FunctionTester T(src);
+  v8::Handle<v8::Message> message;
+
+  message = T.CheckThrowsReturnMessage(T.false_value(), T.Val("Wat?"));
+  CHECK(message->Get()->Equals(v8_str("Uncaught Error: Wat?")));
+
+  message = T.CheckThrowsReturnMessage(T.true_value(), T.Val("Kaboom!"));
+  CHECK(message->Get()->Equals(v8_str("Uncaught Kaboom!")));
+}
+
+
 // TODO(mstarzinger): Increase test coverage by having similar tests within the
 // mjsunit suite to also test integration with other components (e.g. OSR).
 
@@ -118,6 +154,28 @@ TEST(CatchBreak) {
 }
 
 
+TEST(CatchCall) {
+  i::FLAG_turbo_exceptions = true;
+  const char* src =
+      "(function(fun) {"
+      "  var r = '-';"
+      "  try {"
+      "    r += 'A-';"
+      "    return r + 'B-' + fun();"
+      "  } catch (e) {"
+      "    r += e;"
+      "  }"
+      "  return r;"
+      "})";
+  FunctionTester T(src);
+
+  CompileRun("function thrower() { throw 'T-'; }");
+  T.CheckCall(T.Val("-A-T-"), T.NewFunction("thrower"));
+  CompileRun("function returner() { return 'R-'; }");
+  T.CheckCall(T.Val("-A-B-R-"), T.NewFunction("returner"));
+}
+
+
 TEST(Finally) {
   i::FLAG_turbo_exceptions = true;
   const char* src =
@@ -158,3 +216,76 @@ TEST(FinallyBreak) {
   T.CheckCall(T.Val("-A-B-D-"), T.false_value(), T.true_value());
   T.CheckCall(T.Val("-A-B-C-D-"), T.false_value(), T.false_value());
 }
+
+
+TEST(DeoptTry) {
+  i::FLAG_turbo_exceptions = true;
+  i::FLAG_turbo_deoptimization = true;
+  const char* src =
+      "(function f(a) {"
+      "  try {"
+      "    %DeoptimizeFunction(f);"
+      "    throw a;"
+      "  } catch (e) {"
+      "    return e + 1;"
+      "  }"
+      "})";
+  FunctionTester T(src);
+
+  T.CheckCall(T.Val(2), T.Val(1));
+}
+
+
+TEST(DeoptCatch) {
+  i::FLAG_turbo_exceptions = true;
+  i::FLAG_turbo_deoptimization = true;
+  const char* src =
+      "(function f(a) {"
+      "  try {"
+      "    throw a;"
+      "  } catch (e) {"
+      "    %DeoptimizeFunction(f);"
+      "    return e + 1;"
+      "  }"
+      "})";
+  FunctionTester T(src);
+
+  T.CheckCall(T.Val(2), T.Val(1));
+}
+
+
+TEST(DeoptFinallyReturn) {
+  i::FLAG_turbo_exceptions = true;
+  i::FLAG_turbo_deoptimization = true;
+  const char* src =
+      "(function f(a) {"
+      "  try {"
+      "    throw a;"
+      "  } finally {"
+      "    %DeoptimizeFunction(f);"
+      "    return a + 1;"
+      "  }"
+      "})";
+  FunctionTester T(src);
+
+  T.CheckCall(T.Val(2), T.Val(1));
+}
+
+
+TEST(DeoptFinallyReThrow) {
+  i::FLAG_turbo_exceptions = true;
+  i::FLAG_turbo_deoptimization = true;
+  const char* src =
+      "(function f(a) {"
+      "  try {"
+      "    throw a;"
+      "  } finally {"
+      "    %DeoptimizeFunction(f);"
+      "  }"
+      "})";
+  FunctionTester T(src);
+
+#if 0  // TODO(mstarzinger): Enable once we can.
+  T.CheckThrows(T.NewObject("new Error"), T.Val(1));
+#endif
+}
index bb7c239..032db82 100644 (file)
@@ -451,7 +451,6 @@ TEST(LookupStore) {
 
 
 TEST(BlockLoadStore) {
-  FLAG_harmony_scoping = true;
   FunctionTester T("(function(a) { 'use strict'; { let x = a+a; return x; }})");
 
   T.CheckCall(T.Val(46), T.Val(23));
@@ -460,7 +459,6 @@ TEST(BlockLoadStore) {
 
 
 TEST(BlockLoadStoreNested) {
-  FLAG_harmony_scoping = true;
   const char* src =
       "(function(a,b) {"
       "'use strict';"
index 5a55ce6..102e6d8 100644 (file)
@@ -4436,6 +4436,26 @@ TEST(RunInt32SubWithOverflowInBranchP) {
 }
 
 
+TEST(RunWord64EqualInBranchP) {
+  int64_t input;
+  MLabel blocka, blockb;
+  RawMachineAssemblerTester<int64_t> m;
+  if (!m.machine()->Is64()) return;
+  Node* value = m.LoadFromPointer(&input, kMachInt64);
+  m.Branch(m.Word64Equal(value, m.Int64Constant(0)), &blocka, &blockb);
+  m.Bind(&blocka);
+  m.Return(m.Int32Constant(1));
+  m.Bind(&blockb);
+  m.Return(m.Int32Constant(2));
+  input = V8_INT64_C(0);
+  CHECK_EQ(1, m.Call());
+  input = V8_INT64_C(1);
+  CHECK_EQ(2, m.Call());
+  input = V8_INT64_C(0x100000000);
+  CHECK_EQ(2, m.Call());
+}
+
+
 TEST(RunChangeInt32ToInt64P) {
   if (kPointerSize < 8) return;
   int64_t actual = -1;
@@ -4627,6 +4647,72 @@ TEST(RunFloat32Constant) {
 }
 
 
+TEST(RunFloat64ExtractLowWord32) {
+  uint64_t input = 0;
+  RawMachineAssemblerTester<int32_t> m;
+  m.Return(m.Float64ExtractLowWord32(m.LoadFromPointer(&input, kMachFloat64)));
+  FOR_FLOAT64_INPUTS(i) {
+    input = bit_cast<uint64_t>(*i);
+    int32_t expected = bit_cast<int32_t>(static_cast<uint32_t>(input));
+    CHECK_EQ(expected, m.Call());
+  }
+}
+
+
+TEST(RunFloat64ExtractHighWord32) {
+  uint64_t input = 0;
+  RawMachineAssemblerTester<int32_t> m;
+  m.Return(m.Float64ExtractHighWord32(m.LoadFromPointer(&input, kMachFloat64)));
+  FOR_FLOAT64_INPUTS(i) {
+    input = bit_cast<uint64_t>(*i);
+    int32_t expected = bit_cast<int32_t>(static_cast<uint32_t>(input >> 32));
+    CHECK_EQ(expected, m.Call());
+  }
+}
+
+
+TEST(RunFloat64InsertLowWord32) {
+  uint64_t input = 0;
+  uint64_t result = 0;
+  RawMachineAssemblerTester<int32_t> m(kMachInt32);
+  m.StoreToPointer(
+      &result, kMachFloat64,
+      m.Float64InsertLowWord32(m.LoadFromPointer(&input, kMachFloat64),
+                               m.Parameter(0)));
+  m.Return(m.Int32Constant(0));
+  FOR_FLOAT64_INPUTS(i) {
+    FOR_INT32_INPUTS(j) {
+      input = bit_cast<uint64_t>(*i);
+      uint64_t expected = (input & ~(V8_UINT64_C(0xFFFFFFFF))) |
+                          (static_cast<uint64_t>(bit_cast<uint32_t>(*j)));
+      CHECK_EQ(0, m.Call(*j));
+      CHECK_EQ(expected, result);
+    }
+  }
+}
+
+
+TEST(RunFloat64InsertHighWord32) {
+  uint64_t input = 0;
+  uint64_t result = 0;
+  RawMachineAssemblerTester<int32_t> m(kMachInt32);
+  m.StoreToPointer(
+      &result, kMachFloat64,
+      m.Float64InsertHighWord32(m.LoadFromPointer(&input, kMachFloat64),
+                                m.Parameter(0)));
+  m.Return(m.Int32Constant(0));
+  FOR_FLOAT64_INPUTS(i) {
+    FOR_INT32_INPUTS(j) {
+      input = bit_cast<uint64_t>(*i);
+      uint64_t expected = (input & ~(V8_UINT64_C(0xFFFFFFFF) << 32)) |
+                          (static_cast<uint64_t>(bit_cast<uint32_t>(*j)) << 32);
+      CHECK_EQ(0, m.Call(*j));
+      CHECK_EQ(expected, result);
+    }
+  }
+}
+
+
 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,
@@ -4725,13 +4811,13 @@ static double kValues[] = {0.1,
                            -two_52 + 1 - 0.7};
 
 
-TEST(RunFloat64Floor) {
+TEST(RunFloat64RoundDown1) {
   double input = -1.0;
   double result = 0.0;
   RawMachineAssemblerTester<int32_t> m;
-  if (!m.machine()->HasFloat64Floor()) return;
+  if (!m.machine()->HasFloat64RoundDown()) return;
   m.StoreToPointer(&result, kMachFloat64,
-                   m.Float64Floor(m.LoadFromPointer(&input, kMachFloat64)));
+                   m.Float64RoundDown(m.LoadFromPointer(&input, kMachFloat64)));
   m.Return(m.Int32Constant(0));
   for (size_t i = 0; i < arraysize(kValues); ++i) {
     input = kValues[i];
@@ -4742,13 +4828,16 @@ TEST(RunFloat64Floor) {
 }
 
 
-TEST(RunFloat64Ceil) {
+TEST(RunFloat64RoundDown2) {
   double input = -1.0;
   double result = 0.0;
   RawMachineAssemblerTester<int32_t> m;
-  if (!m.machine()->HasFloat64Ceil()) return;
+  if (!m.machine()->HasFloat64RoundDown()) return;
   m.StoreToPointer(&result, kMachFloat64,
-                   m.Float64Ceil(m.LoadFromPointer(&input, kMachFloat64)));
+                   m.Float64Sub(m.Float64Constant(-0.0),
+                                m.Float64RoundDown(m.Float64Sub(
+                                    m.Float64Constant(-0.0),
+                                    m.LoadFromPointer(&input, kMachFloat64)))));
   m.Return(m.Int32Constant(0));
   for (size_t i = 0; i < arraysize(kValues); ++i) {
     input = kValues[i];
@@ -4763,7 +4852,7 @@ TEST(RunFloat64RoundTruncate) {
   double input = -1.0;
   double result = 0.0;
   RawMachineAssemblerTester<int32_t> m;
-  if (!m.machine()->HasFloat64Ceil()) return;
+  if (!m.machine()->HasFloat64RoundTruncate()) return;
   m.StoreToPointer(
       &result, kMachFloat64,
       m.Float64RoundTruncate(m.LoadFromPointer(&input, kMachFloat64)));
@@ -4793,4 +4882,5 @@ TEST(RunFloat64RoundTiesAway) {
     CHECK_EQ(expected, result);
   }
 }
+
 #endif  // V8_TURBOFAN_TARGET
diff --git a/deps/v8/test/cctest/compiler/test-run-stubs.cc b/deps/v8/test/cctest/compiler/test-run-stubs.cc
new file mode 100644 (file)
index 0000000..daf9a46
--- /dev/null
@@ -0,0 +1,106 @@
+// 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.
+
+#include "src/bootstrapper.h"
+#include "src/code-stubs.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/linkage.h"
+#include "src/compiler/pipeline.h"
+#include "src/parser.h"
+#include "test/cctest/compiler/function-tester.h"
+
+#if V8_TURBOFAN_TARGET
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+
+static Handle<JSFunction> GetFunction(Isolate* isolate, const char* name) {
+  v8::ExtensionConfiguration no_extensions;
+  Handle<Context> ctx = isolate->bootstrapper()->CreateEnvironment(
+      MaybeHandle<JSGlobalProxy>(), v8::Handle<v8::ObjectTemplate>(),
+      &no_extensions);
+  Handle<JSBuiltinsObject> builtins = handle(ctx->builtins());
+  MaybeHandle<Object> fun = Object::GetProperty(isolate, builtins, name);
+  Handle<JSFunction> function = Handle<JSFunction>::cast(fun.ToHandleChecked());
+  // Just to make sure nobody calls this...
+  function->set_code(isolate->builtins()->builtin(Builtins::kIllegal));
+  return function;
+}
+
+
+class StringLengthStubTF : public CodeStub {
+ public:
+  explicit StringLengthStubTF(Isolate* isolate) : CodeStub(isolate) {}
+
+  StringLengthStubTF(uint32_t key, Isolate* isolate) : CodeStub(key, isolate) {}
+
+  CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
+    return LoadDescriptor(isolate());
+  };
+
+  Handle<Code> GenerateCode() OVERRIDE {
+    Zone zone;
+    // Build a "hybrid" CompilationInfo for a JSFunction/CodeStub pair.
+    ParseInfo parse_info(&zone, GetFunction(isolate(), "STRING_LENGTH_STUB"));
+    CompilationInfo info(&parse_info);
+    info.SetStub(this);
+    // Run a "mini pipeline", extracted from compiler.cc.
+    CHECK(Parser::ParseStatic(info.parse_info()));
+    CHECK(Compiler::Analyze(info.parse_info()));
+    return Pipeline(&info).GenerateCode();
+  }
+
+  Major MajorKey() const OVERRIDE { return StringLength; };
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::HANDLER; }
+  InlineCacheState GetICState() const OVERRIDE { return MONOMORPHIC; }
+  ExtraICState GetExtraICState() const OVERRIDE { return Code::LOAD_IC; }
+  Code::StubType GetStubType() const OVERRIDE { return Code::FAST; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StringLengthStubTF);
+};
+
+
+TEST(RunStringLengthStubTF) {
+  HandleAndZoneScope scope;
+  Isolate* isolate = scope.main_isolate();
+  Zone* zone = scope.main_zone();
+
+  // Create code and an accompanying descriptor.
+  StringLengthStubTF stub(isolate);
+  Handle<Code> code = stub.GenerateCode();
+  CompilationInfo info(&stub, isolate, zone);
+  CallDescriptor* descriptor = Linkage::ComputeIncoming(zone, &info);
+
+  // Create a function to call the code using the descriptor.
+  Graph graph(zone);
+  CommonOperatorBuilder common(zone);
+  // FunctionTester (ab)uses a 2-argument function
+  Node* start = graph.NewNode(common.Start(2));
+  // Parameter 0 is the receiver
+  Node* receiverParam = graph.NewNode(common.Parameter(1), start);
+  Node* nameParam = graph.NewNode(common.Parameter(2), start);
+  Unique<HeapObject> u = Unique<HeapObject>::CreateImmovable(code);
+  Node* theCode = graph.NewNode(common.HeapConstant(u));
+  Node* dummyContext = graph.NewNode(common.NumberConstant(0.0));
+  Node* call = graph.NewNode(common.Call(descriptor), theCode, receiverParam,
+                             nameParam, dummyContext, start, start);
+  Node* ret = graph.NewNode(common.Return(), call, call, start);
+  Node* end = graph.NewNode(common.End(), ret);
+  graph.SetStart(start);
+  graph.SetEnd(end);
+  FunctionTester ft(&graph);
+
+  // Actuall call through to the stub, verifying its result.
+  const char* testString = "Und das Lamm schrie HURZ!";
+  Handle<JSReceiver> receiverArg =
+      Object::ToObject(isolate, ft.Val(testString)).ToHandleChecked();
+  Handle<String> nameArg = ft.Val("length");
+  Handle<Object> result = ft.Call(receiverArg, nameArg).ToHandleChecked();
+  CHECK_EQ(static_cast<int>(strlen(testString)), Smi::cast(*result)->value());
+}
+
+#endif  // V8_TURBOFAN_TARGET
index bf86e0d..4e5fd18 100644 (file)
@@ -49,7 +49,6 @@ static const char* bind_tests[] = {
 
 
 static void RunVariableTests(const char* source, const char* tests[]) {
-  FLAG_harmony_scoping = true;
   EmbeddedVector<char, 512> buffer;
 
   for (int i = 0; tests[i] != NULL; i += 3) {
index 6e2480e..634483b 100644 (file)
@@ -790,25 +790,6 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
 };
 
 
-#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());
@@ -1441,27 +1422,43 @@ TEST(LowerLoadField_to_load) {
 
 
 TEST(LowerStoreField_to_store) {
-  TestingGraph t(Type::Any(), Type::Signed32());
+  {
+    TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
-    FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                          Handle<Name>::null(), Type::Any(), kMachineReps[i]};
+    for (size_t i = 0; i < arraysize(kMachineReps); i++) {
+      FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
+                            Handle<Name>::null(), Type::Any(), kMachineReps[i]};
 
 
-    Node* val = t.ExampleWithOutput(kMachineReps[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);
+      t.Lower();
+      CHECK_EQ(IrOpcode::kStore, store->opcode());
+      CHECK_EQ(val, store->InputAt(2));
+      CheckFieldAccessArithmetic(access, store);
+
+      StoreRepresentation rep = OpParameter<StoreRepresentation>(store);
+      if (kMachineReps[i] & kRepTagged) {
+        CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
+      }
+      CHECK_EQ(kMachineReps[i], rep.machine_type());
+    }
+  }
+  {
+    TestingGraph t(Type::Any(),
+                   Type::Intersect(Type::SignedSmall(), Type::TaggedSigned()));
+    FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
+                          Handle<Name>::null(), Type::Any(), kMachAnyTagged};
     Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
-                                     val, t.start, t.start);
+                                     t.p1, t.start, t.start);
     t.Effect(store);
     t.Lower();
     CHECK_EQ(IrOpcode::kStore, store->opcode());
-    CHECK_EQ(val, store->InputAt(2));
-    CheckFieldAccessArithmetic(access, store);
-
+    CHECK_EQ(t.p1, store->InputAt(2));
     StoreRepresentation rep = OpParameter<StoreRepresentation>(store);
-    if (kMachineReps[i] & kRepTagged) {
-      CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
-    }
-    CHECK_EQ(kMachineReps[i], rep.machine_type());
+    CHECK_EQ(kNoWriteBarrier, rep.write_barrier_kind());
   }
 }
 
@@ -1489,26 +1486,42 @@ TEST(LowerLoadElement_to_load) {
 
 
 TEST(LowerStoreElement_to_store) {
-  TestingGraph t(Type::Any(), Type::Signed32());
+  {
+    TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
-    ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                            Type::Any(), kMachineReps[i]};
+    for (size_t i = 0; i < arraysize(kMachineReps); i++) {
+      ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
+                              Type::Any(), kMachineReps[i]};
+
+      Node* val = t.ExampleWithOutput(kMachineReps[i]);
+      Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access),
+                                       t.p0, t.p1, val, t.start, t.start);
+      t.Effect(store);
+      t.Lower();
+      CHECK_EQ(IrOpcode::kStore, store->opcode());
+      CHECK_EQ(val, store->InputAt(2));
+      CheckElementAccessArithmetic(access, store);
 
-    Node* val = t.ExampleWithOutput(kMachineReps[i]);
+      StoreRepresentation rep = OpParameter<StoreRepresentation>(store);
+      if (kMachineReps[i] & kRepTagged) {
+        CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
+      }
+      CHECK_EQ(kMachineReps[i], rep.machine_type());
+    }
+  }
+  {
+    TestingGraph t(Type::Any(), Type::Signed32(),
+                   Type::Intersect(Type::SignedSmall(), Type::TaggedSigned()));
+    ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
+                            Type::Any(), kMachAnyTagged};
     Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
-                                     t.p1, val, t.start, t.start);
+                                     t.p1, t.p2, t.start, t.start);
     t.Effect(store);
     t.Lower();
     CHECK_EQ(IrOpcode::kStore, store->opcode());
-    CHECK_EQ(val, store->InputAt(2));
-    CheckElementAccessArithmetic(access, store);
-
+    CHECK_EQ(t.p2, store->InputAt(2));
     StoreRepresentation rep = OpParameter<StoreRepresentation>(store);
-    if (kMachineReps[i] & kRepTagged) {
-      CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
-    }
-    CHECK_EQ(kMachineReps[i], rep.machine_type());
+    CHECK_EQ(kNoWriteBarrier, rep.write_barrier_kind());
   }
 }
 
@@ -1938,10 +1951,10 @@ TEST(NumberModulus_TruncatingToUint32) {
     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.Return(trunc);
     t.Lower();
 
-    CHECK_EQ(IrOpcode::kUint32Mod, ret->InputAt(0)->opcode());
+    CHECK_EQ(IrOpcode::kUint32Mod, t.ret->InputAt(0)->InputAt(0)->opcode());
   }
 }
 
index bbb74c0..be69111 100644 (file)
@@ -605,3 +605,86 @@ THREADED_TEST(Regress433458) {
       "Object.defineProperty(obj, 'prop', { writable: false });"
       "Object.defineProperty(obj, 'prop', { writable: true });");
 }
+
+
+static bool security_check_value = false;
+
+
+static bool SecurityTestCallback(Local<v8::Object> global, Local<Value> name,
+                                 v8::AccessType type, Local<Value> data) {
+  return security_check_value;
+}
+
+
+TEST(PrototypeGetterAccessCheck) {
+  i::FLAG_allow_natives_syntax = true;
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  auto fun_templ = v8::FunctionTemplate::New(isolate);
+  auto getter_templ = v8::FunctionTemplate::New(isolate, handle_property);
+  getter_templ->SetAcceptAnyReceiver(false);
+  fun_templ->InstanceTemplate()->SetAccessorProperty(v8_str("foo"),
+                                                     getter_templ);
+  auto obj_templ = v8::ObjectTemplate::New(isolate);
+  obj_templ->SetAccessCheckCallbacks(SecurityTestCallback, nullptr);
+  env->Global()->Set(v8_str("Fun"), fun_templ->GetFunction());
+  env->Global()->Set(v8_str("obj"), obj_templ->NewInstance());
+  env->Global()->Set(v8_str("obj2"), obj_templ->NewInstance());
+
+  security_check_value = true;
+  CompileRun("var proto = new Fun();");
+  CompileRun("obj.__proto__ = proto;");
+  ExpectInt32("proto.foo", 907);
+
+  // Test direct.
+  security_check_value = true;
+  ExpectInt32("obj.foo", 907);
+  security_check_value = false;
+  {
+    v8::TryCatch try_catch(isolate);
+    CompileRun("obj.foo");
+    CHECK(try_catch.HasCaught());
+  }
+
+  // Test through call.
+  security_check_value = true;
+  ExpectInt32("proto.__lookupGetter__('foo').call(obj)", 907);
+  security_check_value = false;
+  {
+    v8::TryCatch try_catch(isolate);
+    CompileRun("proto.__lookupGetter__('foo').call(obj)");
+    CHECK(try_catch.HasCaught());
+  }
+
+  // Test ics.
+  CompileRun(
+      "function f() {"
+      "   var x;"
+      "  for (var i = 0; i < 4; i++) {"
+      "    x = obj.foo;"
+      "  }"
+      "  return x;"
+      "}");
+
+  security_check_value = true;
+  ExpectInt32("f()", 907);
+  security_check_value = false;
+  {
+    v8::TryCatch try_catch(isolate);
+    CompileRun("f();");
+    CHECK(try_catch.HasCaught());
+  }
+
+  // Test crankshaft.
+  CompileRun("%OptimizeFunctionOnNextCall(f);");
+
+  security_check_value = true;
+  ExpectInt32("f()", 907);
+  security_check_value = false;
+  {
+    v8::TryCatch try_catch(isolate);
+    CompileRun("f();");
+    CHECK(try_catch.HasCaught());
+  }
+}
index 79ba4a4..0ec9934 100644 (file)
@@ -63,7 +63,7 @@ static AllocationResult AllocateAfterFailures() {
   heap->AllocateFixedArray(10000, TENURED).ToObjectChecked();
 
   // Large object space.
-  static const int kLargeObjectSpaceFillerLength = 300000;
+  static const int kLargeObjectSpaceFillerLength = 3 * (Page::kPageSize / 10);
   static const int kLargeObjectSpaceFillerSize = FixedArray::SizeFor(
       kLargeObjectSpaceFillerLength);
   DCHECK(kLargeObjectSpaceFillerSize > heap->old_pointer_space()->AreaSize());
@@ -210,7 +210,7 @@ TEST(CodeRange) {
       // Geometrically distributed sizes, greater than
       // Page::kMaxRegularHeapObjectSize (which is greater than code page area).
       // TODO(gc): instead of using 3 use some contant based on code_range_size
-      // kMaxHeapObjectSize.
+      // kMaxRegularHeapObjectSize.
       size_t requested =
           (Page::kMaxRegularHeapObjectSize << (Pseudorandom() % 3)) +
           Pseudorandom() % 5000 + 1;
index a2acb24..e3bee15 100644 (file)
@@ -15,7 +15,6 @@
 #include "src/objects.h"
 #include "src/parser.h"
 #include "src/smart-pointers.h"
-#include "src/snapshot.h"
 #include "src/unicode-inl.h"
 #include "src/utils.h"
 #include "src/vm-state.h"
@@ -2934,16 +2933,8 @@ struct AccessCheckData {
 };
 
 
-bool SimpleNamedAccessChecker(Local<v8::Object> global, Local<Value> name,
-                              v8::AccessType type, Local<Value> data) {
-  auto access_check_data = GetWrappedObject<AccessCheckData>(data);
-  access_check_data->count++;
-  return access_check_data->result;
-}
-
-
-bool SimpleIndexedAccessChecker(Local<v8::Object> global, uint32_t index,
-                                v8::AccessType type, Local<Value> data) {
+bool SimpleAccessChecker(Local<v8::Object> global, Local<Value> name,
+                         v8::AccessType type, Local<Value> data) {
   auto access_check_data = GetWrappedObject<AccessCheckData>(data);
   access_check_data->count++;
   return access_check_data->result;
@@ -3015,7 +3006,7 @@ THREADED_TEST(NamedAllCanReadInterceptor) {
 
   auto checked = v8::ObjectTemplate::New(isolate);
   checked->SetAccessCheckCallbacks(
-      SimpleNamedAccessChecker, nullptr,
+      SimpleAccessChecker, nullptr,
       BuildWrappedObject<AccessCheckData>(isolate, &access_check_data), false);
 
   context->Global()->Set(v8_str("intercepted_0"), intercepted_0->NewInstance());
@@ -3032,15 +3023,27 @@ THREADED_TEST(NamedAllCanReadInterceptor) {
 
   access_check_data.result = true;
   ExpectInt32("checked.whatever", 17);
-  CHECK_EQ(1, access_check_data.count);
+  CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')")
+             ->IsUndefined());
+  CHECK_EQ(2, access_check_data.count);
 
   access_check_data.result = false;
   ExpectInt32("checked.whatever", intercept_data_0.value);
-  CHECK_EQ(2, access_check_data.count);
+  {
+    v8::TryCatch try_catch(isolate);
+    CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')");
+    CHECK(try_catch.HasCaught());
+  }
+  CHECK_EQ(4, access_check_data.count);
 
   intercept_data_1.should_intercept = true;
   ExpectInt32("checked.whatever", intercept_data_1.value);
-  CHECK_EQ(3, access_check_data.count);
+  {
+    v8::TryCatch try_catch(isolate);
+    CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')");
+    CHECK(try_catch.HasCaught());
+  }
+  CHECK_EQ(6, access_check_data.count);
 }
 
 
@@ -3081,7 +3084,7 @@ THREADED_TEST(IndexedAllCanReadInterceptor) {
 
   auto checked = v8::ObjectTemplate::New(isolate);
   checked->SetAccessCheckCallbacks(
-      nullptr, SimpleIndexedAccessChecker,
+      SimpleAccessChecker, nullptr,
       BuildWrappedObject<AccessCheckData>(isolate, &access_check_data), false);
 
   context->Global()->Set(v8_str("intercepted_0"), intercepted_0->NewInstance());
@@ -3098,13 +3101,211 @@ THREADED_TEST(IndexedAllCanReadInterceptor) {
 
   access_check_data.result = true;
   ExpectInt32("checked[15]", 17);
-  CHECK_EQ(1, access_check_data.count);
+  CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, '15')")
+             ->IsUndefined());
+  CHECK_EQ(3, access_check_data.count);
 
   access_check_data.result = false;
   ExpectInt32("checked[15]", intercept_data_0.value);
-  CHECK_EQ(2, access_check_data.count);
+  // Note: this should throw but without a LookupIterator it's complicated.
+  CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, '15')")
+             ->IsUndefined());
+  CHECK_EQ(6, access_check_data.count);
 
   intercept_data_1.should_intercept = true;
   ExpectInt32("checked[15]", intercept_data_1.value);
-  CHECK_EQ(3, access_check_data.count);
+  // Note: this should throw but without a LookupIterator it's complicated.
+  CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, '15')")
+             ->IsUndefined());
+  CHECK_EQ(9, access_check_data.count);
+}
+
+
+THREADED_TEST(NonMaskingInterceptorOwnProperty) {
+  auto isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext context;
+
+  ShouldInterceptData intercept_data;
+  intercept_data.value = 239;
+  intercept_data.should_intercept = true;
+
+  auto interceptor_templ = v8::ObjectTemplate::New(isolate);
+  v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
+  conf.flags = v8::PropertyHandlerFlags::kNonMasking;
+  conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
+  interceptor_templ->SetHandler(conf);
+
+  auto interceptor = interceptor_templ->NewInstance();
+  context->Global()->Set(v8_str("obj"), interceptor);
+
+  ExpectInt32("obj.whatever", 239);
+
+  CompileRun("obj.whatever = 4;");
+  ExpectInt32("obj.whatever", 4);
+
+  CompileRun("delete obj.whatever;");
+  ExpectInt32("obj.whatever", 239);
+}
+
+
+THREADED_TEST(NonMaskingInterceptorPrototypeProperty) {
+  auto isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext context;
+
+  ShouldInterceptData intercept_data;
+  intercept_data.value = 239;
+  intercept_data.should_intercept = true;
+
+  auto interceptor_templ = v8::ObjectTemplate::New(isolate);
+  v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
+  conf.flags = v8::PropertyHandlerFlags::kNonMasking;
+  conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
+  interceptor_templ->SetHandler(conf);
+
+  auto interceptor = interceptor_templ->NewInstance();
+  context->Global()->Set(v8_str("obj"), interceptor);
+
+  ExpectInt32("obj.whatever", 239);
+
+  CompileRun("obj.__proto__ = {'whatever': 4};");
+  ExpectInt32("obj.whatever", 4);
+
+  CompileRun("delete obj.__proto__.whatever;");
+  ExpectInt32("obj.whatever", 239);
+}
+
+
+THREADED_TEST(NonMaskingInterceptorPrototypePropertyIC) {
+  auto isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext context;
+
+  ShouldInterceptData intercept_data;
+  intercept_data.value = 239;
+  intercept_data.should_intercept = true;
+
+  auto interceptor_templ = v8::ObjectTemplate::New(isolate);
+  v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
+  conf.flags = v8::PropertyHandlerFlags::kNonMasking;
+  conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
+  interceptor_templ->SetHandler(conf);
+
+  auto interceptor = interceptor_templ->NewInstance();
+  context->Global()->Set(v8_str("obj"), interceptor);
+
+  CompileRun(
+      "outer = {};"
+      "outer.__proto__ = obj;"
+      "function f(obj) {"
+      "  var x;"
+      "  for (var i = 0; i < 4; i++) {"
+      "    x = obj.whatever;"
+      "  }"
+      "  return x;"
+      "}");
+
+  // Receiver == holder.
+  CompileRun("obj.__proto__ = null;");
+  ExpectInt32("f(obj)", 239);
+  ExpectInt32("f(outer)", 239);
+
+  // Receiver != holder.
+  CompileRun("Object.setPrototypeOf(obj, {});");
+  ExpectInt32("f(obj)", 239);
+  ExpectInt32("f(outer)", 239);
+
+  // Masked value on prototype.
+  CompileRun("obj.__proto__.whatever = 4;");
+  CompileRun("obj.__proto__.__proto__ = { 'whatever' : 5 };");
+  ExpectInt32("f(obj)", 4);
+  ExpectInt32("f(outer)", 4);
+
+  // Masked value on prototype prototype.
+  CompileRun("delete obj.__proto__.whatever;");
+  ExpectInt32("f(obj)", 5);
+  ExpectInt32("f(outer)", 5);
+
+  // Reset.
+  CompileRun("delete obj.__proto__.__proto__.whatever;");
+  ExpectInt32("f(obj)", 239);
+  ExpectInt32("f(outer)", 239);
+
+  // Masked value on self.
+  CompileRun("obj.whatever = 4;");
+  ExpectInt32("f(obj)", 4);
+  ExpectInt32("f(outer)", 4);
+
+  // Reset.
+  CompileRun("delete obj.whatever;");
+  ExpectInt32("f(obj)", 239);
+  ExpectInt32("f(outer)", 239);
+
+  CompileRun("outer.whatever = 4;");
+  ExpectInt32("f(obj)", 239);
+  ExpectInt32("f(outer)", 4);
+}
+
+
+namespace {
+
+void DatabaseGetter(Local<Name> name,
+                    const v8::PropertyCallbackInfo<Value>& info) {
+  ApiTestFuzzer::Fuzz();
+  auto context = info.GetIsolate()->GetCurrentContext();
+  Local<v8::Object> db = info.Holder()
+                             ->GetRealNamedProperty(context, v8_str("db"))
+                             .ToLocalChecked()
+                             .As<v8::Object>();
+  if (!db->Has(context, name).FromJust()) return;
+  info.GetReturnValue().Set(db->Get(context, name).ToLocalChecked());
+}
+
+
+void DatabaseSetter(Local<Name> name, Local<Value> value,
+                    const v8::PropertyCallbackInfo<Value>& info) {
+  ApiTestFuzzer::Fuzz();
+  auto context = info.GetIsolate()->GetCurrentContext();
+  if (name->Equals(v8_str("db"))) return;
+  Local<v8::Object> db = info.Holder()
+                             ->GetRealNamedProperty(context, v8_str("db"))
+                             .ToLocalChecked()
+                             .As<v8::Object>();
+  db->Set(context, name, value).FromJust();
+  info.GetReturnValue().Set(value);
+}
+}
+
+
+THREADED_TEST(NonMaskingInterceptorGlobalEvalRegression) {
+  auto isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext context;
+
+  auto interceptor_templ = v8::ObjectTemplate::New(isolate);
+  v8::NamedPropertyHandlerConfiguration conf(DatabaseGetter, DatabaseSetter);
+  conf.flags = v8::PropertyHandlerFlags::kNonMasking;
+  interceptor_templ->SetHandler(conf);
+
+  context->Global()->Set(v8_str("intercepted_1"),
+                         interceptor_templ->NewInstance());
+  context->Global()->Set(v8_str("intercepted_2"),
+                         interceptor_templ->NewInstance());
+
+  // Init dbs.
+  CompileRun(
+      "intercepted_1.db = {};"
+      "intercepted_2.db = {};");
+
+  ExpectInt32(
+      "var obj = intercepted_1;"
+      "obj.x = 4;"
+      "eval('obj.x');"
+      "eval('obj.x');"
+      "eval('obj.x');"
+      "obj = intercepted_2;"
+      "obj.x = 9;"
+      "eval('obj.x');",
+      9);
 }
index afb70ff..8432cbf 100644 (file)
@@ -45,7 +45,6 @@
 #include "src/objects.h"
 #include "src/parser.h"
 #include "src/smart-pointers.h"
-#include "src/snapshot.h"
 #include "src/unicode-inl.h"
 #include "src/utils.h"
 #include "src/vm-state.h"
@@ -61,12 +60,15 @@ using ::v8::FunctionTemplate;
 using ::v8::Handle;
 using ::v8::HandleScope;
 using ::v8::Local;
-using ::v8::Name;
+using ::v8::Maybe;
 using ::v8::Message;
 using ::v8::MessageCallback;
+using ::v8::Name;
+using ::v8::None;
 using ::v8::Object;
 using ::v8::ObjectTemplate;
 using ::v8::Persistent;
+using ::v8::PropertyAttribute;
 using ::v8::Script;
 using ::v8::StackTrace;
 using ::v8::String;
@@ -691,28 +693,23 @@ class RandomLengthOneByteResource
 
 
 THREADED_TEST(NewExternalForVeryLongString) {
+  auto isolate = CcTest::isolate();
   {
-    LocalContext env;
-    v8::HandleScope scope(env->GetIsolate());
+    v8::HandleScope scope(isolate);
     v8::TryCatch try_catch;
     RandomLengthOneByteResource r(1 << 30);
-    v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
+    v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r);
     CHECK(str.IsEmpty());
-    CHECK(try_catch.HasCaught());
-    String::Utf8Value exception_value(try_catch.Exception());
-    CHECK_EQ(0, strcmp("RangeError: Invalid string length", *exception_value));
+    CHECK(!try_catch.HasCaught());
   }
 
   {
-    LocalContext env;
-    v8::HandleScope scope(env->GetIsolate());
+    v8::HandleScope scope(isolate);
     v8::TryCatch try_catch;
     RandomLengthResource r(1 << 30);
-    v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
+    v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r);
     CHECK(str.IsEmpty());
-    CHECK(try_catch.HasCaught());
-    String::Utf8Value exception_value(try_catch.Exception());
-    CHECK_EQ(0, strcmp("RangeError: Invalid string length", *exception_value));
+    CHECK(!try_catch.HasCaught());
   }
 }
 
@@ -733,8 +730,8 @@ THREADED_TEST(ScavengeExternalString) {
     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
     CHECK_EQ(0, dispose_count);
   }
-  CcTest::heap()->CollectGarbage(
-      in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
+  CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE
+                                              : i::OLD_DATA_SPACE);
   CHECK_EQ(1, dispose_count);
 }
 
@@ -756,8 +753,8 @@ THREADED_TEST(ScavengeExternalOneByteString) {
     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
     CHECK_EQ(0, dispose_count);
   }
-  CcTest::heap()->CollectGarbage(
-      in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
+  CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE
+                                              : i::OLD_DATA_SPACE);
   CHECK_EQ(1, dispose_count);
 }
 
@@ -2124,7 +2121,7 @@ THREADED_TEST(InternalFieldsAlignedPointers) {
   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
   CheckAlignedPointerInInternalField(obj, huge);
 
-  v8::UniquePersistent<v8::Object> persistent(isolate, obj);
+  v8::Global<v8::Object> persistent(isolate, obj);
   CHECK_EQ(1, Object::InternalFieldCount(persistent));
   CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
 }
@@ -3035,20 +3032,20 @@ THREADED_TEST(ResettingGlobalHandleToEmpty) {
 
 
 template <class T>
-static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
+static v8::Global<T> PassUnique(v8::Global<T> unique) {
   return unique.Pass();
 }
 
 
 template <class T>
-static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
-                                            const v8::Persistent<T>& global) {
-  v8::UniquePersistent<String> unique(isolate, global);
+static v8::Global<T> ReturnUnique(v8::Isolate* isolate,
+                                  const v8::Persistent<T>& global) {
+  v8::Global<String> unique(isolate, global);
   return unique.Pass();
 }
 
 
-THREADED_TEST(UniquePersistent) {
+THREADED_TEST(Global) {
   v8::Isolate* isolate = CcTest::isolate();
   v8::Persistent<String> global;
   {
@@ -3059,11 +3056,11 @@ THREADED_TEST(UniquePersistent) {
       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   int initial_handle_count = global_handles->global_handles_count();
   {
-    v8::UniquePersistent<String> unique(isolate, global);
+    v8::Global<String> unique(isolate, global);
     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
     // Test assignment via Pass
     {
-      v8::UniquePersistent<String> copy = unique.Pass();
+      v8::Global<String> copy = unique.Pass();
       CHECK(unique.IsEmpty());
       CHECK(copy == global);
       CHECK_EQ(initial_handle_count + 1,
@@ -3072,7 +3069,7 @@ THREADED_TEST(UniquePersistent) {
     }
     // Test ctor via Pass
     {
-      v8::UniquePersistent<String> copy(unique.Pass());
+      v8::Global<String> copy(unique.Pass());
       CHECK(unique.IsEmpty());
       CHECK(copy == global);
       CHECK_EQ(initial_handle_count + 1,
@@ -3081,7 +3078,7 @@ THREADED_TEST(UniquePersistent) {
     }
     // Test pass through function call
     {
-      v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
+      v8::Global<String> copy = PassUnique(unique.Pass());
       CHECK(unique.IsEmpty());
       CHECK(copy == global);
       CHECK_EQ(initial_handle_count + 1,
@@ -3092,7 +3089,7 @@ THREADED_TEST(UniquePersistent) {
   }
   // Test pass from function call
   {
-    v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
+    v8::Global<String> unique = ReturnUnique(isolate, global);
     CHECK(unique == global);
     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
   }
@@ -3101,6 +3098,123 @@ THREADED_TEST(UniquePersistent) {
 }
 
 
+namespace {
+
+class TwoPassCallbackData;
+void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
+void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
+
+
+class TwoPassCallbackData {
+ public:
+  TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter)
+      : first_pass_called_(false),
+        second_pass_called_(false),
+        trigger_gc_(false),
+        instance_counter_(instance_counter) {
+    HandleScope scope(isolate);
+    i::ScopedVector<char> buffer(40);
+    i::SNPrintF(buffer, "%p", static_cast<void*>(this));
+    auto string =
+        v8::String::NewFromUtf8(isolate, buffer.start(),
+                                v8::NewStringType::kNormal).ToLocalChecked();
+    cell_.Reset(isolate, string);
+    (*instance_counter_)++;
+  }
+
+  ~TwoPassCallbackData() {
+    CHECK(first_pass_called_);
+    CHECK(second_pass_called_);
+    CHECK(cell_.IsEmpty());
+    (*instance_counter_)--;
+  }
+
+  void FirstPass() {
+    CHECK(!first_pass_called_);
+    CHECK(!second_pass_called_);
+    CHECK(!cell_.IsEmpty());
+    cell_.Reset();
+    first_pass_called_ = true;
+  }
+
+  void SecondPass() {
+    CHECK(first_pass_called_);
+    CHECK(!second_pass_called_);
+    CHECK(cell_.IsEmpty());
+    second_pass_called_ = true;
+    delete this;
+  }
+
+  void SetWeak() {
+    cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
+  }
+
+  void MarkTriggerGc() { trigger_gc_ = true; }
+  bool trigger_gc() { return trigger_gc_; }
+
+  int* instance_counter() { return instance_counter_; }
+
+ private:
+  bool first_pass_called_;
+  bool second_pass_called_;
+  bool trigger_gc_;
+  v8::Global<v8::String> cell_;
+  int* instance_counter_;
+};
+
+
+void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
+  ApiTestFuzzer::Fuzz();
+  bool trigger_gc = data.GetParameter()->trigger_gc();
+  int* instance_counter = data.GetParameter()->instance_counter();
+  data.GetParameter()->SecondPass();
+  if (!trigger_gc) return;
+  auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter);
+  data_2->SetWeak();
+  CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+}
+
+
+void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
+  data.GetParameter()->FirstPass();
+  data.SetSecondPassCallback(SecondPassCallback);
+}
+
+}  // namespace
+
+
+TEST(TwoPassPhantomCallbacks) {
+  auto isolate = CcTest::isolate();
+  const size_t kLength = 20;
+  int instance_counter = 0;
+  for (size_t i = 0; i < kLength; ++i) {
+    auto data = new TwoPassCallbackData(isolate, &instance_counter);
+    data->SetWeak();
+  }
+  CHECK_EQ(static_cast<int>(kLength), instance_counter);
+  CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+  CHECK_EQ(0, instance_counter);
+}
+
+
+TEST(TwoPassPhantomCallbacksNestedGc) {
+  auto isolate = CcTest::isolate();
+  const size_t kLength = 20;
+  TwoPassCallbackData* array[kLength];
+  int instance_counter = 0;
+  for (size_t i = 0; i < kLength; ++i) {
+    array[i] = new TwoPassCallbackData(isolate, &instance_counter);
+    array[i]->SetWeak();
+  }
+  array[5]->MarkTriggerGc();
+  array[10]->MarkTriggerGc();
+  array[15]->MarkTriggerGc();
+  CHECK_EQ(static_cast<int>(kLength), instance_counter);
+  CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+  CHECK_EQ(0, instance_counter);
+}
+
+
 template <typename K, typename V>
 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
  public:
@@ -3126,8 +3240,7 @@ class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
     return data.GetParameter()->key;
   }
   static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
-  static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
-                      K key) {}
+  static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {}
 };
 
 
@@ -3153,7 +3266,7 @@ static void TestPersistentValueMap() {
       typename Map::PersistentValueReference ref = map.GetReference(7);
       CHECK(expected->Equals(ref.NewLocal(isolate)));
     }
-    v8::UniquePersistent<v8::Object> removed = map.Remove(7);
+    v8::Global<v8::Object> removed = map.Remove(7);
     CHECK_EQ(0, static_cast<int>(map.Size()));
     CHECK(expected == removed);
     removed = map.Remove(7);
@@ -3165,8 +3278,7 @@ static void TestPersistentValueMap() {
     {
       typename Map::PersistentValueReference ref;
       Local<v8::Object> expected2 = v8::Object::New(isolate);
-      removed = map.Set(8, v8::UniquePersistent<v8::Object>(isolate, expected2),
-                        &ref);
+      removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
       CHECK_EQ(1, static_cast<int>(map.Size()));
       CHECK(expected == removed);
       CHECK(expected2->Equals(ref.NewLocal(isolate)));
@@ -3197,6 +3309,126 @@ TEST(PersistentValueMap) {
 }
 
 
+namespace {
+
+void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); }
+
+
+Local<v8::Object> NewObjectForIntKey(
+    v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ,
+    int key) {
+  auto local = Local<v8::ObjectTemplate>::New(isolate, templ);
+  auto obj = local->NewInstance();
+  obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key));
+  return obj;
+}
+
+
+template <typename K, typename V>
+class PhantomStdMapTraits : public v8::StdMapTraits<K, V> {
+ public:
+  typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType;
+  static const v8::PersistentContainerCallbackType kCallbackType =
+      v8::kWeakWithInternalFields;
+  struct WeakCallbackDataType {
+    MapType* map;
+    K key;
+  };
+  static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
+                                                     Local<V> value) {
+    WeakCallbackDataType* data = new WeakCallbackDataType;
+    data->map = map;
+    data->key = key;
+    return data;
+  }
+  static MapType* MapFromWeakCallbackInfo(
+      const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
+    return data.GetParameter()->map;
+  }
+  static K KeyFromWeakCallbackInfo(
+      const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
+    return data.GetParameter()->key;
+  }
+  static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
+  static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {
+    CHECK_EQ(IntKeyToVoidPointer(key),
+             v8::Object::GetAlignedPointerFromInternalField(value, 0));
+  }
+  static void DisposeWeak(
+      v8::Isolate* isolate,
+      const v8::WeakCallbackInfo<WeakCallbackDataType>& info, K key) {
+    CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0));
+    DisposeCallbackData(info.GetParameter());
+  }
+};
+
+}  // namespace
+
+
+TEST(GlobalValueMap) {
+  typedef v8::GlobalValueMap<int, v8::Object,
+                             PhantomStdMapTraits<int, v8::Object>> Map;
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::Global<ObjectTemplate> templ;
+  {
+    HandleScope scope(isolate);
+    auto t = ObjectTemplate::New(isolate);
+    t->SetInternalFieldCount(1);
+    templ.Reset(isolate, t);
+  }
+  Map map(isolate);
+  v8::internal::GlobalHandles* global_handles =
+      reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
+  int initial_handle_count = global_handles->global_handles_count();
+  CHECK_EQ(0, static_cast<int>(map.Size()));
+  {
+    HandleScope scope(isolate);
+    Local<v8::Object> obj = map.Get(7);
+    CHECK(obj.IsEmpty());
+    Local<v8::Object> expected = v8::Object::New(isolate);
+    map.Set(7, expected);
+    CHECK_EQ(1, static_cast<int>(map.Size()));
+    obj = map.Get(7);
+    CHECK(expected->Equals(obj));
+    {
+      Map::PersistentValueReference ref = map.GetReference(7);
+      CHECK(expected->Equals(ref.NewLocal(isolate)));
+    }
+    v8::Global<v8::Object> removed = map.Remove(7);
+    CHECK_EQ(0, static_cast<int>(map.Size()));
+    CHECK(expected == removed);
+    removed = map.Remove(7);
+    CHECK(removed.IsEmpty());
+    map.Set(8, expected);
+    CHECK_EQ(1, static_cast<int>(map.Size()));
+    map.Set(8, expected);
+    CHECK_EQ(1, static_cast<int>(map.Size()));
+    {
+      Map::PersistentValueReference ref;
+      Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8);
+      removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
+      CHECK_EQ(1, static_cast<int>(map.Size()));
+      CHECK(expected == removed);
+      CHECK(expected2->Equals(ref.NewLocal(isolate)));
+    }
+  }
+  CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
+  CcTest::i_isolate()->heap()->CollectAllGarbage(
+      i::Heap::kAbortIncrementalMarkingMask);
+  CHECK_EQ(0, static_cast<int>(map.Size()));
+  CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
+  {
+    HandleScope scope(isolate);
+    Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9);
+    map.Set(9, value);
+    map.Clear();
+  }
+  CHECK_EQ(0, static_cast<int>(map.Size()));
+  CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
+}
+
+
 TEST(PersistentValueVector) {
   LocalContext env;
   v8::Isolate* isolate = env->GetIsolate();
@@ -3209,7 +3441,7 @@ TEST(PersistentValueVector) {
 
   Local<v8::Object> obj1 = v8::Object::New(isolate);
   Local<v8::Object> obj2 = v8::Object::New(isolate);
-  v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
+  v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate));
 
   CHECK(vector.IsEmpty());
   CHECK_EQ(0, static_cast<int>(vector.Size()));
@@ -3891,6 +4123,7 @@ static void check_message_3(v8::Handle<v8::Message> message,
   CHECK(message->GetScriptOrigin().ResourceIsSharedCrossOrigin()->Value());
   CHECK(message->GetScriptOrigin().ResourceIsEmbedderDebugScript()->Value());
   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
+  CHECK_EQ(7.40, message->GetScriptOrigin().SourceMapUrl()->NumberValue());
   message_received = true;
 }
 
@@ -3902,10 +4135,10 @@ TEST(MessageHandler3) {
   CHECK(!message_received);
   v8::V8::AddMessageListener(check_message_3);
   LocalContext context;
-  v8::ScriptOrigin origin =
-      v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
-                       v8::Integer::New(isolate, 2), v8::True(isolate),
-                       Handle<v8::Integer>(), v8::True(isolate));
+  v8::ScriptOrigin origin = v8::ScriptOrigin(
+      v8_str("6.75"), v8::Integer::New(isolate, 1),
+      v8::Integer::New(isolate, 2), v8::True(isolate), Handle<v8::Integer>(),
+      v8::True(isolate), v8_str("7.40"));
   v8::Handle<v8::Script> script =
       Script::Compile(v8_str("throw 'error'"), &origin);
   script->Run();
@@ -6266,12 +6499,13 @@ THREADED_TEST(ErrorWithMissingScriptInfo) {
 
 struct FlagAndPersistent {
   bool flag;
-  v8::Persistent<v8::Object> handle;
+  v8::Global<v8::Object> handle;
 };
 
 
-static void SetFlag(const v8::PhantomCallbackData<FlagAndPersistent>& data) {
+static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
   data.GetParameter()->flag = true;
+  data.GetParameter()->handle.Reset();
 }
 
 
@@ -6309,8 +6543,10 @@ static void IndependentWeakHandle(bool global_gc, bool interlinked) {
 
   object_a.flag = false;
   object_b.flag = false;
-  object_a.handle.SetPhantom(&object_a, &SetFlag);
-  object_b.handle.SetPhantom(&object_b, &SetFlag);
+  object_a.handle.SetWeak(&object_a, &SetFlag,
+                          v8::WeakCallbackType::kParameter);
+  object_b.handle.SetWeak(&object_b, &SetFlag,
+                          v8::WeakCallbackType::kParameter);
   CHECK(!object_b.handle.IsIndependent());
   object_a.handle.MarkIndependent();
   object_b.handle.MarkIndependent();
@@ -6365,7 +6601,7 @@ class Trivial2 {
 
 
 void CheckInternalFields(
-    const v8::PhantomCallbackData<v8::Persistent<v8::Object>>& data) {
+    const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
   v8::Persistent<v8::Object>* handle = data.GetParameter();
   handle->Reset();
   Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField1());
@@ -6405,8 +6641,8 @@ void InternalFieldCallback(bool global_gc) {
         reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
     CHECK_EQ(103, t2->x());
 
-    handle.SetPhantom<v8::Persistent<v8::Object>>(&handle, CheckInternalFields,
-                                                  0, 1);
+    handle.SetWeak<v8::Persistent<v8::Object>>(
+        &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields);
     if (!global_gc) {
       handle.MarkIndependent();
     }
@@ -7673,30 +7909,9 @@ TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
 
 // For use within the TestSecurityHandler() test.
 static bool g_security_callback_result = false;
-static bool NamedSecurityTestCallback(Local<v8::Object> global,
-                                      Local<Value> name,
-                                      v8::AccessType type,
-                                      Local<Value> data) {
+static bool SecurityTestCallback(Local<v8::Object> global, Local<Value> name,
+                                 v8::AccessType type, Local<Value> data) {
   printf("a\n");
-  // Always allow read access.
-  if (type == v8::ACCESS_GET)
-    return true;
-
-  // Sometimes allow other access.
-  return g_security_callback_result;
-}
-
-
-static bool IndexedSecurityTestCallback(Local<v8::Object> global,
-                                        uint32_t key,
-                                        v8::AccessType type,
-                                        Local<Value> data) {
-  printf("b\n");
-  // Always allow read access.
-  if (type == v8::ACCESS_GET)
-    return true;
-
-  // Sometimes allow other access.
   return g_security_callback_result;
 }
 
@@ -7707,8 +7922,7 @@ TEST(SecurityHandler) {
   v8::HandleScope scope0(isolate);
   v8::Handle<v8::ObjectTemplate> global_template =
       v8::ObjectTemplate::New(isolate);
-  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
-                                           IndexedSecurityTestCallback);
+  global_template->SetAccessCheckCallbacks(SecurityTestCallback, NULL);
   // Create an environment
   v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
   context0->Enter();
@@ -7735,6 +7949,7 @@ TEST(SecurityHandler) {
   v8::Handle<Script> script1 =
     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
   script1->Run();
+  g_security_callback_result = true;
   // This read will pass the security check.
   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
   CHECK_EQ(111, foo1->Int32Value());
@@ -7743,7 +7958,7 @@ TEST(SecurityHandler) {
   CHECK_EQ(999, z1->Int32Value());
 
   // Create another environment, should pass security checks.
-  { g_security_callback_result = true;  // allow security handler to pass.
+  {
     v8::HandleScope scope2(isolate);
     LocalContext context2;
     v8::Handle<v8::Object> global2 = context2->Global();
@@ -7866,26 +8081,13 @@ THREADED_TEST(SecurityChecksForPrototypeChain) {
 }
 
 
-static bool named_security_check_with_gc_called;
+static bool security_check_with_gc_called;
 
-static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
-                                        Local<Value> name,
-                                        v8::AccessType type,
-                                        Local<Value> data) {
+static bool SecurityTestCallbackWithGC(Local<v8::Object> global,
+                                       Local<v8::Value> name,
+                                       v8::AccessType type, Local<Value> data) {
   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
-  named_security_check_with_gc_called = true;
-  return true;
-}
-
-
-static bool indexed_security_check_with_gc_called;
-
-static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
-                                              uint32_t key,
-                                              v8::AccessType type,
-                                              Local<Value> data) {
-  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
-  indexed_security_check_with_gc_called = true;
+  security_check_with_gc_called = true;
   return true;
 }
 
@@ -7895,29 +8097,20 @@ TEST(SecurityTestGCAllowed) {
   v8::HandleScope handle_scope(isolate);
   v8::Handle<v8::ObjectTemplate> object_template =
       v8::ObjectTemplate::New(isolate);
-  object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
-                                           IndexedSecurityTestCallbackWithGC);
+  object_template->SetAccessCheckCallbacks(SecurityTestCallbackWithGC, NULL);
 
   v8::Handle<Context> context = Context::New(isolate);
   v8::Context::Scope context_scope(context);
 
   context->Global()->Set(v8_str("obj"), object_template->NewInstance());
 
-  named_security_check_with_gc_called = false;
-  CompileRun("obj.foo = new String(1001);");
-  CHECK(named_security_check_with_gc_called);
-
-  indexed_security_check_with_gc_called = false;
+  security_check_with_gc_called = false;
   CompileRun("obj[0] = new String(1002);");
-  CHECK(indexed_security_check_with_gc_called);
-
-  named_security_check_with_gc_called = false;
-  CHECK(CompileRun("obj.foo")->ToString(isolate)->Equals(v8_str("1001")));
-  CHECK(named_security_check_with_gc_called);
+  CHECK(security_check_with_gc_called);
 
-  indexed_security_check_with_gc_called = false;
+  security_check_with_gc_called = false;
   CHECK(CompileRun("obj[0]")->ToString(isolate)->Equals(v8_str("1002")));
-  CHECK(indexed_security_check_with_gc_called);
+  CHECK(security_check_with_gc_called);
 }
 
 
@@ -8275,22 +8468,11 @@ TEST(DetachedAccesses) {
 }
 
 
-static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
-static bool NamedAccessBlocker(Local<v8::Object> global,
-                               Local<Value> name,
-                               v8::AccessType type,
-                               Local<Value> data) {
+static bool allowed_access = false;
+static bool AccessBlocker(Local<v8::Object> global, Local<Value> name,
+                          v8::AccessType type, Local<Value> data) {
   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
-      allowed_access_type[type];
-}
-
-
-static bool IndexedAccessBlocker(Local<v8::Object> global,
-                                 uint32_t key,
-                                 v8::AccessType type,
-                                 Local<Value> data) {
-  return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
-      allowed_access_type[type];
+         allowed_access;
 }
 
 
@@ -8338,8 +8520,7 @@ TEST(AccessControl) {
   v8::Handle<v8::ObjectTemplate> global_template =
       v8::ObjectTemplate::New(isolate);
 
-  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
-                                           IndexedAccessBlocker);
+  global_template->SetAccessCheckCallbacks(AccessBlocker, NULL);
 
   // Add an accessor accessible by cross-domain JS code.
   global_template->SetAccessor(
@@ -8413,15 +8594,10 @@ TEST(AccessControl) {
   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
   CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
 
-  // Enable ACCESS_HAS
-  allowed_access_type[v8::ACCESS_HAS] = true;
-  CHECK(CompileRun("other[239]").IsEmpty());
-  // ... and now we can get the descriptor...
-  CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
-            .IsEmpty());
-  // ... and enumerate the property.
+  allowed_access = true;
+  // Now we can enumerate the property.
   ExpectTrue("propertyIsEnumerable.call(other, '239')");
-  allowed_access_type[v8::ACCESS_HAS] = false;
+  allowed_access = false;
 
   // Access a property with JS accessor.
   CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
@@ -8430,9 +8606,7 @@ TEST(AccessControl) {
   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
             .IsEmpty());
 
-  // Enable both ACCESS_HAS and ACCESS_GET.
-  allowed_access_type[v8::ACCESS_HAS] = true;
-  allowed_access_type[v8::ACCESS_GET] = true;
+  allowed_access = true;
 
   ExpectString("other.js_accessor_p", "getter");
   ExpectObject(
@@ -8442,8 +8616,7 @@ TEST(AccessControl) {
   ExpectUndefined(
       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
 
-  allowed_access_type[v8::ACCESS_HAS] = false;
-  allowed_access_type[v8::ACCESS_GET] = false;
+  allowed_access = false;
 
   // Access an element with JS accessor.
   CHECK(CompileRun("other[42] = 2").IsEmpty());
@@ -8451,17 +8624,14 @@ TEST(AccessControl) {
   CHECK(CompileRun("other[42]").IsEmpty());
   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
 
-  // Enable both ACCESS_HAS and ACCESS_GET.
-  allowed_access_type[v8::ACCESS_HAS] = true;
-  allowed_access_type[v8::ACCESS_GET] = true;
+  allowed_access = true;
 
   ExpectString("other[42]", "el_getter");
   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
 
-  allowed_access_type[v8::ACCESS_HAS] = false;
-  allowed_access_type[v8::ACCESS_GET] = false;
+  allowed_access = false;
 
   v8::Handle<Value> value;
 
@@ -8514,8 +8684,7 @@ TEST(AccessControlES5) {
   v8::Handle<v8::ObjectTemplate> global_template =
       v8::ObjectTemplate::New(isolate);
 
-  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
-                                           IndexedAccessBlocker);
+  global_template->SetAccessCheckCallbacks(AccessBlocker, NULL);
 
   // Add accessible accessor.
   global_template->SetAccessor(
@@ -8578,14 +8747,9 @@ TEST(AccessControlES5) {
 }
 
 
-static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name,
-                                 v8::AccessType type, Local<Value> data) {
-  return false;
-}
-
-
-static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key,
-                                   v8::AccessType type, Local<Value> data) {
+static bool AccessAlwaysBlocked(Local<v8::Object> global, Local<Value> name,
+                                v8::AccessType type, Local<Value> data) {
+  i::PrintF("Access blocked.\n");
   return false;
 }
 
@@ -8597,8 +8761,7 @@ THREADED_TEST(AccessControlGetOwnPropertyNames) {
       v8::ObjectTemplate::New(isolate);
 
   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
-  obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
-                                        BlockEverythingIndexed);
+  obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
 
   // Create an environment
   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
@@ -8641,8 +8804,7 @@ TEST(SuperAccessControl) {
   v8::HandleScope handle_scope(isolate);
   v8::Handle<v8::ObjectTemplate> obj_template =
       v8::ObjectTemplate::New(isolate);
-  obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
-                                        BlockEverythingIndexed);
+  obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
   LocalContext env;
   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
 
@@ -8690,6 +8852,32 @@ TEST(SuperAccessControl) {
 }
 
 
+TEST(Regress470113) {
+  i::FLAG_harmony_classes = true;
+  i::FLAG_harmony_object_literals = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  v8::Handle<v8::ObjectTemplate> obj_template =
+      v8::ObjectTemplate::New(isolate);
+  obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
+  LocalContext env;
+  env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
+
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "'use strict';\n"
+        "class C extends Object {\n"
+        "   m() { super.powned = 'Powned!'; }\n"
+        "}\n"
+        "let c = new C();\n"
+        "c.m.call(prohibited)");
+
+    CHECK(try_catch.HasCaught());
+  }
+}
+
+
 static void ConstTenGetter(Local<String> name,
                            const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(v8_num(10));
@@ -8749,31 +8937,18 @@ THREADED_TEST(CrossDomainAccessors) {
 }
 
 
-static int named_access_count = 0;
-static int indexed_access_count = 0;
+static int access_count = 0;
 
-static bool NamedAccessCounter(Local<v8::Object> global,
-                               Local<Value> name,
-                               v8::AccessType type,
-                               Local<Value> data) {
-  named_access_count++;
-  return true;
-}
-
-
-static bool IndexedAccessCounter(Local<v8::Object> global,
-                                 uint32_t key,
-                                 v8::AccessType type,
-                                 Local<Value> data) {
-  indexed_access_count++;
+static bool AccessCounter(Local<v8::Object> global, Local<Value> name,
+                          v8::AccessType type, Local<Value> data) {
+  access_count++;
   return true;
 }
 
 
 // This one is too easily disturbed by other tests.
 TEST(AccessControlIC) {
-  named_access_count = 0;
-  indexed_access_count = 0;
+  access_count = 0;
 
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope handle_scope(isolate);
@@ -8786,8 +8961,7 @@ TEST(AccessControlIC) {
   // called for cross-domain access.
   v8::Handle<v8::ObjectTemplate> object_template =
       v8::ObjectTemplate::New(isolate);
-  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
-                                           IndexedAccessCounter);
+  object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
   Local<v8::Object> object = object_template->NewInstance();
 
   v8::HandleScope scope1(isolate);
@@ -8811,7 +8985,7 @@ TEST(AccessControlIC) {
   value = CompileRun("testProp(obj)");
   CHECK(value->IsNumber());
   CHECK_EQ(1, value->Int32Value());
-  CHECK_EQ(21, named_access_count);
+  CHECK_EQ(21, access_count);
 
   // Check that the named access-control function is called every time.
   CompileRun("var p = 'prop';"
@@ -8825,16 +8999,18 @@ TEST(AccessControlIC) {
   value = CompileRun("testKeyed(obj)");
   CHECK(value->IsNumber());
   CHECK_EQ(1, value->Int32Value());
-  CHECK_EQ(42, named_access_count);
+  CHECK_EQ(42, access_count);
   // Force the inline caches into generic state and try again.
   CompileRun("testKeyed({ a: 0 })");
   CompileRun("testKeyed({ b: 0 })");
   value = CompileRun("testKeyed(obj)");
   CHECK(value->IsNumber());
   CHECK_EQ(1, value->Int32Value());
-  CHECK_EQ(63, named_access_count);
+  CHECK_EQ(63, access_count);
 
   // Check that the indexed access-control function is called every time.
+  access_count = 0;
+
   CompileRun("function testIndexed(obj) {"
              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
              "  for (var j = 0; j < 10; j++) obj[0];"
@@ -8843,15 +9019,16 @@ TEST(AccessControlIC) {
   value = CompileRun("testIndexed(obj)");
   CHECK(value->IsNumber());
   CHECK_EQ(1, value->Int32Value());
-  CHECK_EQ(21, indexed_access_count);
+  CHECK_EQ(21, access_count);
   // Force the inline caches into generic state.
   CompileRun("testIndexed(new Array(1))");
   // Test that the indexed access check is called.
   value = CompileRun("testIndexed(obj)");
   CHECK(value->IsNumber());
   CHECK_EQ(1, value->Int32Value());
-  CHECK_EQ(42, indexed_access_count);
+  CHECK_EQ(42, access_count);
 
+  access_count = 0;
   // Check that the named access check is called when invoking
   // functions on an object that requires access checks.
   CompileRun("obj.f = function() {}");
@@ -8859,7 +9036,8 @@ TEST(AccessControlIC) {
              "  for (var i = 0; i < 10; i++) obj.f();"
              "}");
   CompileRun("testCallNormal(obj)");
-  CHECK_EQ(74, named_access_count);
+  printf("%i\n", access_count);
+  CHECK_EQ(11, access_count);
 
   // Force obj into slow case.
   value = CompileRun("delete obj.prop");
@@ -8870,89 +9048,14 @@ TEST(AccessControlIC) {
   value = CompileRun("testProp(obj);");
   CHECK(value->IsNumber());
   CHECK_EQ(1, value->Int32Value());
-  CHECK_EQ(96, named_access_count);
+  CHECK_EQ(33, access_count);
 
   // Force the call inline cache into dictionary probing mode.
   CompileRun("o.f = function() {}; testCallNormal(o)");
   // Test that the named access check is still called for each
   // invocation of the function.
   value = CompileRun("testCallNormal(obj)");
-  CHECK_EQ(106, named_access_count);
-
-  context1->Exit();
-  context0->Exit();
-}
-
-
-static bool NamedAccessFlatten(Local<v8::Object> global,
-                               Local<Value> name,
-                               v8::AccessType type,
-                               Local<Value> data) {
-  char buf[100];
-  int len;
-
-  CHECK(name->IsString());
-
-  memset(buf, 0x1, sizeof(buf));
-  len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
-  CHECK_EQ(4, len);
-
-  uint16_t buf2[100];
-
-  memset(buf, 0x1, sizeof(buf));
-  len = name.As<String>()->Write(buf2);
-  CHECK_EQ(4, len);
-
-  return true;
-}
-
-
-static bool IndexedAccessFlatten(Local<v8::Object> global,
-                                 uint32_t key,
-                                 v8::AccessType type,
-                                 Local<Value> data) {
-  return true;
-}
-
-
-// Regression test.  In access checks, operations that may cause
-// garbage collection are not allowed.  It used to be the case that
-// using the Write operation on a string could cause a garbage
-// collection due to flattening of the string.  This is no longer the
-// case.
-THREADED_TEST(AccessControlFlatten) {
-  named_access_count = 0;
-  indexed_access_count = 0;
-
-  v8::Isolate* isolate = CcTest::isolate();
-  v8::HandleScope handle_scope(isolate);
-
-  // Create an environment.
-  v8::Local<Context> context0 = Context::New(isolate);
-  context0->Enter();
-
-  // Create an object that requires access-check functions to be
-  // called for cross-domain access.
-  v8::Handle<v8::ObjectTemplate> object_template =
-      v8::ObjectTemplate::New(isolate);
-  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
-                                           IndexedAccessFlatten);
-  Local<v8::Object> object = object_template->NewInstance();
-
-  v8::HandleScope scope1(isolate);
-
-  // Create another environment.
-  v8::Local<Context> context1 = Context::New(isolate);
-  context1->Enter();
-
-  // Make easy access to the object from the other environment.
-  v8::Handle<v8::Object> global1 = context1->Global();
-  global1->Set(v8_str("obj"), object);
-
-  v8::Handle<Value> value;
-
-  value = v8_compile("var p = 'as' + 'df';")->Run();
-  value = v8_compile("obj[p];")->Run();
+  CHECK_EQ(43, access_count);
 
   context1->Exit();
   context0->Exit();
@@ -10869,16 +10972,29 @@ THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
   try_catch.Reset();
   CHECK(result.IsEmpty());
 
+  Maybe<PropertyAttribute> attr =
+      instance->GetRealNamedPropertyAttributes(v8_str("f"));
+  CHECK(!try_catch.HasCaught());
+  CHECK(Just(None) == attr);
+
   result = another->GetRealNamedProperty(v8_str("f"));
   CHECK(try_catch.HasCaught());
   try_catch.Reset();
   CHECK(result.IsEmpty());
 
+  attr = another->GetRealNamedPropertyAttributes(v8_str("f"));
+  CHECK(!try_catch.HasCaught());
+  CHECK(Just(None) == attr);
+
   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
   CHECK(try_catch.HasCaught());
   try_catch.Reset();
   CHECK(result.IsEmpty());
 
+  attr = another->GetRealNamedPropertyAttributesInPrototypeChain(v8_str("f"));
+  CHECK(!try_catch.HasCaught());
+  CHECK(Just(None) == attr);
+
   result = another->Get(v8_str("f"));
   CHECK(try_catch.HasCaught());
   try_catch.Reset();
@@ -10889,6 +11005,10 @@ THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
   try_catch.Reset();
   CHECK(result.IsEmpty());
 
+  attr = with_js_getter->GetRealNamedPropertyAttributes(v8_str("f"));
+  CHECK(!try_catch.HasCaught());
+  CHECK(Just(None) == attr);
+
   result = with_js_getter->Get(v8_str("f"));
   CHECK(try_catch.HasCaught());
   try_catch.Reset();
@@ -12676,61 +12796,13 @@ THREADED_TEST(PropertyEnumeration2) {
   }
 }
 
-static bool NamedSetAccessBlocker(Local<v8::Object> obj,
-                                  Local<Value> name,
-                                  v8::AccessType type,
-                                  Local<Value> data) {
-  return type != v8::ACCESS_SET;
-}
-
-
-static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
-                                    uint32_t key,
-                                    v8::AccessType type,
-                                    Local<Value> data) {
-  return type != v8::ACCESS_SET;
-}
-
-
-THREADED_TEST(DisableAccessChecksWhileConfiguring) {
-  LocalContext context;
-  v8::Isolate* isolate = context->GetIsolate();
-  v8::HandleScope scope(isolate);
-  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
-                                 IndexedSetAccessBlocker);
-  templ->Set(v8_str("x"), v8::True(isolate));
-  Local<v8::Object> instance = templ->NewInstance();
-  context->Global()->Set(v8_str("obj"), instance);
-  Local<Value> value = CompileRun("obj.x");
-  CHECK(value->BooleanValue());
-}
-
-
-static bool NamedGetAccessBlocker(Local<v8::Object> obj,
-                                  Local<Value> name,
-                                  v8::AccessType type,
-                                  Local<Value> data) {
-  return false;
-}
-
-
-static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
-                                    uint32_t key,
-                                    v8::AccessType type,
-                                    Local<Value> data) {
-  return false;
-}
-
-
 
 THREADED_TEST(AccessChecksReenabledCorrectly) {
   LocalContext context;
   v8::Isolate* isolate = context->GetIsolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
-                                 IndexedGetAccessBlocker);
+  templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
   templ->Set(v8_str("a"), v8_str("a"));
   // Add more than 8 (see kMaxFastProperties) properties
   // so that the constructor will force copying map.
@@ -12762,27 +12834,6 @@ THREADED_TEST(AccessChecksReenabledCorrectly) {
 }
 
 
-// This tests that access check information remains on the global
-// object template when creating contexts.
-THREADED_TEST(AccessControlRepeatedContextCreation) {
-  v8::Isolate* isolate = CcTest::isolate();
-  v8::HandleScope handle_scope(isolate);
-  v8::Handle<v8::ObjectTemplate> global_template =
-      v8::ObjectTemplate::New(isolate);
-  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
-                                           IndexedSetAccessBlocker);
-  i::Handle<i::ObjectTemplateInfo> internal_template =
-      v8::Utils::OpenHandle(*global_template);
-  CHECK(!internal_template->constructor()->IsUndefined());
-  i::Handle<i::FunctionTemplateInfo> constructor(
-      i::FunctionTemplateInfo::cast(internal_template->constructor()));
-  CHECK(!constructor->access_check_info()->IsUndefined());
-  v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
-  CHECK(!context0.IsEmpty());
-  CHECK(!constructor->access_check_info()->IsUndefined());
-}
-
-
 THREADED_TEST(TurnOnAccessCheck) {
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope handle_scope(isolate);
@@ -12791,10 +12842,8 @@ THREADED_TEST(TurnOnAccessCheck) {
   // default.
   v8::Handle<v8::ObjectTemplate> global_template =
       v8::ObjectTemplate::New(isolate);
-  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
-                                           IndexedGetAccessBlocker,
-                                           v8::Handle<v8::Value>(),
-                                           false);
+  global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL,
+                                           v8::Handle<v8::Value>(), false);
   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
   Context::Scope context_scope(context);
 
@@ -12850,109 +12899,6 @@ THREADED_TEST(TurnOnAccessCheck) {
 }
 
 
-static const char* kPropertyA = "a";
-static const char* kPropertyH = "h";
-
-static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
-                                       Local<Value> name,
-                                       v8::AccessType type,
-                                       Local<Value> data) {
-  if (!name->IsString()) return false;
-  i::Handle<i::String> name_handle =
-      v8::Utils::OpenHandle(String::Cast(*name));
-  return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
-      && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
-}
-
-
-THREADED_TEST(TurnOnAccessCheckAndRecompile) {
-  v8::Isolate* isolate = CcTest::isolate();
-  v8::HandleScope handle_scope(isolate);
-
-  // Create an environment with access check to the global object disabled by
-  // default. When the registered access checker will block access to properties
-  // a and h.
-  v8::Handle<v8::ObjectTemplate> global_template =
-     v8::ObjectTemplate::New(isolate);
-  global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
-                                           IndexedGetAccessBlocker,
-                                           v8::Handle<v8::Value>(),
-                                           false);
-  v8::Local<Context> context = Context::New(isolate, NULL, global_template);
-  Context::Scope context_scope(context);
-
-  // Set up a property and a number of functions.
-  context->Global()->Set(v8_str("a"), v8_num(1));
-  static const char* source = "function f1() {return a;}"
-                              "function f2() {return a;}"
-                              "function g1() {return h();}"
-                              "function g2() {return h();}"
-                              "function h() {return 1;}";
-
-  CompileRun(source);
-  Local<Function> f1;
-  Local<Function> f2;
-  Local<Function> g1;
-  Local<Function> g2;
-  Local<Function> h;
-  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
-  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
-  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
-  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
-  h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
-
-  // Get the global object.
-  v8::Handle<v8::Object> global = context->Global();
-
-  // Call f1 one time and f2 a number of times. This will ensure that f1 still
-  // uses the runtime system to retreive property a whereas f2 uses global load
-  // inline cache.
-  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
-  for (int i = 0; i < 4; i++) {
-    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
-  }
-
-  // Same for g1 and g2.
-  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
-  for (int i = 0; i < 4; i++) {
-    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
-  }
-
-  // Detach the global and turn on access check now blocking access to property
-  // a and function h.
-  Local<Object> hidden_global = Local<Object>::Cast(
-      context->Global()->GetPrototype());
-  context->DetachGlobal();
-  hidden_global->TurnOnAccessCheck();
-
-  // Failing access check results in exception.
-  CHECK(f1->Call(global, 0, NULL).IsEmpty());
-  CHECK(f2->Call(global, 0, NULL).IsEmpty());
-  CHECK(g1->Call(global, 0, NULL).IsEmpty());
-  CHECK(g2->Call(global, 0, NULL).IsEmpty());
-
-  // No failing access check when just returning a constant.
-  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
-
-  // Now compile the source again. And get the newly compiled functions, except
-  // for h for which access is blocked.
-  CompileRun(source);
-  f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
-  f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
-  g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
-  g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
-  CHECK(hidden_global->Get(v8_str("h")).IsEmpty());
-
-  // Failing access check results in exception.
-  v8::Local<v8::Value> result = f1->Call(global, 0, NULL);
-  CHECK(result.IsEmpty());
-  CHECK(f1->Call(global, 0, NULL).IsEmpty());
-  CHECK(f2->Call(global, 0, NULL).IsEmpty());
-  CHECK(g1->Call(global, 0, NULL).IsEmpty());
-  CHECK(g2->Call(global, 0, NULL).IsEmpty());
-}
-
-
 // Tests that ScriptData can be serialized and deserialized.
 TEST(PreCompileSerialization) {
   v8::V8::Initialize();
@@ -15223,6 +15169,54 @@ TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
 }
 
 
+static void StackTraceFunctionNameListener(v8::Handle<v8::Message> message,
+                                           v8::Handle<Value>) {
+  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
+  CHECK_EQ(5, stack_trace->GetFrameCount());
+  checkStackFrame("origin", "foo:0", 4, 7, false, false,
+                  stack_trace->GetFrame(0));
+  checkStackFrame("origin", "foo:1", 5, 27, false, false,
+                  stack_trace->GetFrame(1));
+  checkStackFrame("origin", "foo", 5, 27, false, false,
+                  stack_trace->GetFrame(2));
+  checkStackFrame("origin", "foo", 5, 27, false, false,
+                  stack_trace->GetFrame(3));
+  checkStackFrame("origin", "", 1, 14, false, false, stack_trace->GetFrame(4));
+}
+
+
+TEST(GetStackTraceContainsFunctionsWithFunctionName) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+
+  CompileRunWithOrigin(
+      "function gen(name, counter) {\n"
+      "  var f = function foo() {\n"
+      "    if (counter === 0)\n"
+      "      throw 1;\n"
+      "    gen(name, counter - 1)();\n"
+      "  };\n"
+      "  if (counter == 3) {\n"
+      "    Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n"
+      "  } else {\n"
+      "    Object.defineProperty(f, 'name', {writable:true});\n"
+      "    if (counter == 2)\n"
+      "      f.name = 42;\n"
+      "    else\n"
+      "      f.name = name + ':' + counter;\n"
+      "  }\n"
+      "  return f;\n"
+      "};",
+      "origin");
+
+  v8::V8::AddMessageListener(StackTraceFunctionNameListener);
+  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
+  CompileRunWithOrigin("gen('foo', 3)();", "origin");
+  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
+  v8::V8::RemoveMessageListeners(StackTraceFunctionNameListener);
+}
+
+
 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
                                      v8::Handle<v8::Value> data) {
   // Use the frame where JavaScript is called from.
@@ -15991,30 +15985,10 @@ static void CreateGarbageInOldSpace() {
 }
 
 
-// Test that idle notification can be handled and eventually returns true.
-TEST(IdleNotification) {
-  const intptr_t MB = 1024 * 1024;
-  const int IdlePauseInMs = 1000;
-  LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
-  intptr_t initial_size = CcTest::heap()->SizeOfObjects();
-  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(IdlePauseInMs);
-  }
-  intptr_t final_size = CcTest::heap()->SizeOfObjects();
-  CHECK(finished);
-  CHECK_LT(final_size, initial_size + 1);
-}
-
-
 // Test that idle notification can be handled and eventually collects garbage.
-TEST(IdleNotificationWithSmallHint) {
+TEST(TestIdleNotification) {
   const intptr_t MB = 1024 * 1024;
-  const int IdlePauseInMs = 900;
+  const double IdlePauseInSeconds = 1.0;
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
@@ -16023,27 +15997,10 @@ TEST(IdleNotificationWithSmallHint) {
   CHECK_GT(size_with_garbage, initial_size + MB);
   bool finished = false;
   for (int i = 0; i < 200 && !finished; i++) {
-    finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
-  }
-  intptr_t final_size = CcTest::heap()->SizeOfObjects();
-  CHECK(finished);
-  CHECK_LT(final_size, initial_size + 1);
-}
-
-
-// Test that idle notification can be handled and eventually collects garbage.
-TEST(IdleNotificationWithLargeHint) {
-  const intptr_t MB = 1024 * 1024;
-  const int IdlePauseInMs = 900;
-  LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
-  intptr_t initial_size = CcTest::heap()->SizeOfObjects();
-  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(IdlePauseInMs);
+    finished = env->GetIsolate()->IdleNotificationDeadline(
+        (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
+         static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
+        IdlePauseInSeconds);
   }
   intptr_t final_size = CcTest::heap()->SizeOfObjects();
   CHECK(finished);
@@ -16188,7 +16145,7 @@ TEST(ExternalizeOldSpaceTwoByteCons) {
   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
   CcTest::heap()->CollectAllAvailableGarbage();
   CHECK(CcTest::heap()->old_pointer_space()->Contains(
-            *v8::Utils::OpenHandle(*cons)));
+      *v8::Utils::OpenHandle(*cons)));
 
   TestResource* resource = new TestResource(
       AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
@@ -16211,7 +16168,7 @@ TEST(ExternalizeOldSpaceOneByteCons) {
   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
   CcTest::heap()->CollectAllAvailableGarbage();
   CHECK(CcTest::heap()->old_pointer_space()->Contains(
-            *v8::Utils::OpenHandle(*cons)));
+      *v8::Utils::OpenHandle(*cons)));
 
   TestOneByteResource* resource =
       new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
@@ -16501,6 +16458,7 @@ THREADED_TEST(SpaghettiStackReThrow) {
 TEST(Regress528) {
   v8::V8::Initialize();
   v8::Isolate* isolate = CcTest::isolate();
+  i::FLAG_retain_maps_for_n_gc = 0;
   v8::HandleScope scope(isolate);
   v8::Local<Context> other_context;
   int gc_count;
@@ -16593,7 +16551,8 @@ THREADED_TEST(ScriptOrigin) {
       v8::String::NewFromUtf8(env->GetIsolate(), "test"),
       v8::Integer::New(env->GetIsolate(), 1),
       v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()),
-      v8::Handle<v8::Integer>(), v8::True(env->GetIsolate()));
+      v8::Handle<v8::Integer>(), v8::True(env->GetIsolate()),
+      v8::String::NewFromUtf8(env->GetIsolate(), "http://sourceMapUrl"));
   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
   v8::Script::Compile(script, &origin)->Run();
@@ -16608,6 +16567,10 @@ THREADED_TEST(ScriptOrigin) {
   CHECK_EQ(1, script_origin_f.ResourceLineOffset()->Int32Value());
   CHECK(script_origin_f.ResourceIsSharedCrossOrigin()->Value());
   CHECK(script_origin_f.ResourceIsEmbedderDebugScript()->Value());
+  printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined());
+
+  CHECK_EQ(0, strcmp("http://sourceMapUrl",
+                     *v8::String::Utf8Value(script_origin_f.SourceMapUrl())));
 
   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
   CHECK_EQ(0, strcmp("test",
@@ -16615,6 +16578,8 @@ THREADED_TEST(ScriptOrigin) {
   CHECK_EQ(1, script_origin_g.ResourceLineOffset()->Int32Value());
   CHECK(script_origin_g.ResourceIsSharedCrossOrigin()->Value());
   CHECK(script_origin_g.ResourceIsEmbedderDebugScript()->Value());
+  CHECK_EQ(0, strcmp("http://sourceMapUrl",
+                     *v8::String::Utf8Value(script_origin_g.SourceMapUrl())));
 }
 
 
@@ -17457,10 +17422,8 @@ TEST(GCInFailedAccessCheckCallback) {
   // check callbacks that will block access.
   v8::Handle<v8::ObjectTemplate> global_template =
       v8::ObjectTemplate::New(isolate);
-  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
-                                           IndexedGetAccessBlocker,
-                                           v8::Handle<v8::Value>(),
-                                           false);
+  global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL,
+                                           v8::Handle<v8::Value>(), false);
 
   // Create a context and set an x property on it's global object.
   LocalContext context0(NULL, global_template);
@@ -18230,18 +18193,22 @@ THREADED_TEST(CreationContext) {
     instance2 = func2->NewInstance();
   }
 
-  CHECK(object1->CreationContext() == context1);
-  CheckContextId(object1, 1);
-  CHECK(func1->CreationContext() == context1);
-  CheckContextId(func1, 1);
-  CHECK(instance1->CreationContext() == context1);
-  CheckContextId(instance1, 1);
-  CHECK(object2->CreationContext() == context2);
-  CheckContextId(object2, 2);
-  CHECK(func2->CreationContext() == context2);
-  CheckContextId(func2, 2);
-  CHECK(instance2->CreationContext() == context2);
-  CheckContextId(instance2, 2);
+  {
+    Handle<Context> other_context = Context::New(isolate);
+    Context::Scope scope(other_context);
+    CHECK(object1->CreationContext() == context1);
+    CheckContextId(object1, 1);
+    CHECK(func1->CreationContext() == context1);
+    CheckContextId(func1, 1);
+    CHECK(instance1->CreationContext() == context1);
+    CheckContextId(instance1, 1);
+    CHECK(object2->CreationContext() == context2);
+    CheckContextId(object2, 2);
+    CHECK(func2->CreationContext() == context2);
+    CheckContextId(func2, 2);
+    CHECK(instance2->CreationContext() == context2);
+    CheckContextId(instance2, 2);
+  }
 
   {
     Context::Scope scope(context1);
@@ -18288,6 +18255,8 @@ THREADED_TEST(CreationContextOfJsFunction) {
     function = CompileRun("function foo() {}; foo").As<Object>();
   }
 
+  Handle<Context> other_context = Context::New(CcTest::isolate());
+  Context::Scope scope(other_context);
   CHECK(function->CreationContext() == context);
   CheckContextId(function, 1);
 }
@@ -18596,33 +18565,13 @@ THREADED_TEST(Regress1516) {
 }
 
 
-static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
-                                                Local<Value> name,
-                                                v8::AccessType type,
-                                                Local<Value> data) {
-  // Only block read access to __proto__.
-  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.As<v8::String>()->WriteUtf8(buffer));
-    return strncmp(buffer, "__proto__", 9) != 0;
-  }
-
-  return true;
-}
-
-
 THREADED_TEST(Regress93759) {
   v8::Isolate* isolate = CcTest::isolate();
   HandleScope scope(isolate);
 
   // Template for object with security check.
   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
-  // We don't do indexing, so any callback can be used for that.
-  no_proto_template->SetAccessCheckCallbacks(
-      BlockProtoNamedSecurityTestCallback,
-      IndexedSecurityTestCallback);
+  no_proto_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
 
   // Templates for objects with hidden prototypes and possibly security check.
   Local<FunctionTemplate> hidden_proto_template =
@@ -18632,8 +18581,7 @@ THREADED_TEST(Regress93759) {
   Local<FunctionTemplate> protected_hidden_proto_template =
       v8::FunctionTemplate::New(isolate);
   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
-      BlockProtoNamedSecurityTestCallback,
-      IndexedSecurityTestCallback);
+      AccessAlwaysBlocked, NULL);
   protected_hidden_proto_template->SetHiddenPrototype(true);
 
   // Context for "foreign" objects used in test.
@@ -18644,12 +18592,10 @@ THREADED_TEST(Regress93759) {
   Local<Object> simple_object = Object::New(isolate);
 
   // Object with explicit security check.
-  Local<Object> protected_object =
-      no_proto_template->NewInstance();
+  Local<Object> protected_object = no_proto_template->NewInstance();
 
   // JSGlobalProxy object, always have security check.
-  Local<Object> proxy_object =
-      context->Global();
+  Local<Object> proxy_object = context->Global();
 
   // Global object, the  prototype of proxy_object. No security checks.
   Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate);
@@ -19815,24 +19761,6 @@ THREADED_TEST(SemaphoreInterruption) {
 #endif  // V8_OS_POSIX
 
 
-static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
-                                     Local<Value> name,
-                                     v8::AccessType type,
-                                     Local<Value> data) {
-  i::PrintF("Named access blocked.\n");
-  return false;
-}
-
-
-static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
-                                     uint32_t key,
-                                     v8::AccessType type,
-                                     Local<Value> data) {
-  i::PrintF("Indexed access blocked.\n");
-  return false;
-}
-
-
 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
   CHECK(false);
 }
@@ -19847,8 +19775,7 @@ TEST(JSONStringifyAccessCheck) {
   // check callbacks that will block access.
   v8::Handle<v8::ObjectTemplate> global_template =
       v8::ObjectTemplate::New(isolate);
-  global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
-                                           IndexAccessAlwaysBlocked);
+  global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
 
   // Create a context and set an x property on it's global object.
   LocalContext context0(NULL, global_template);
@@ -19946,8 +19873,7 @@ TEST(AccessCheckThrows) {
   // check callbacks that will block access.
   v8::Handle<v8::ObjectTemplate> global_template =
       v8::ObjectTemplate::New(isolate);
-  global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
-                                           IndexAccessAlwaysBlocked);
+  global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
 
   // Create a context and set an x property on it's global object.
   LocalContext context0(NULL, global_template);
@@ -20100,6 +20026,7 @@ class RequestInterruptTestWithFunctionCall
         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
     env_->Global()->Set(v8_str("ShouldContinue"), func);
 
+    i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
     CompileRun("while (ShouldContinue()) { }");
   }
 };
@@ -20115,6 +20042,7 @@ class RequestInterruptTestWithMethodCall
         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
 
+    i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
   }
 };
@@ -20130,6 +20058,7 @@ class RequestInterruptTestWithAccessor
         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
 
+    i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
   }
 };
@@ -20147,6 +20076,7 @@ class RequestInterruptTestWithNativeAccessor
         v8::External::New(isolate_, this));
     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
 
+    i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
   }
 
@@ -20176,6 +20106,7 @@ class RequestInterruptTestWithMethodCallAndInterceptor
 
     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
 
+    i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
   }
 
@@ -20200,6 +20131,7 @@ class RequestInterruptTestWithMathAbs
         v8::External::New(isolate_, this)));
 
     i::FLAG_allow_natives_syntax = true;
+    i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
     CompileRun("function loopish(o) {"
                "  var pre = 10;"
                "  while (o.abs(1) > 0) {"
@@ -20283,6 +20215,7 @@ class RequestMultipleInterrupts : public RequestInterruptTestBase {
         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
     env_->Global()->Set(v8_str("ShouldContinue"), func);
 
+    i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
     CompileRun("while (ShouldContinue()) { }");
   }
 
@@ -21002,42 +20935,42 @@ TEST(Regress354123) {
   v8::HandleScope scope(isolate);
 
   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
-  templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
+  templ->SetAccessCheckCallbacks(AccessCounter, NULL);
   current->Global()->Set(v8_str("friend"), templ->NewInstance());
 
   // Test access using __proto__ from the prototype chain.
-  named_access_count = 0;
+  access_count = 0;
   CompileRun("friend.__proto__ = {};");
-  CHECK_EQ(2, named_access_count);
+  CHECK_EQ(2, access_count);
   CompileRun("friend.__proto__;");
-  CHECK_EQ(4, named_access_count);
+  CHECK_EQ(4, access_count);
 
   // Test access using __proto__ as a hijacked function (A).
-  named_access_count = 0;
+  access_count = 0;
   CompileRun("var p = Object.prototype;"
              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
              "f.call(friend, {});");
-  CHECK_EQ(1, named_access_count);
+  CHECK_EQ(1, access_count);
   CompileRun("var p = Object.prototype;"
              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
              "f.call(friend);");
-  CHECK_EQ(2, named_access_count);
+  CHECK_EQ(2, access_count);
 
   // Test access using __proto__ as a hijacked function (B).
-  named_access_count = 0;
+  access_count = 0;
   CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
              "f.call(friend, {});");
-  CHECK_EQ(1, named_access_count);
+  CHECK_EQ(1, access_count);
   CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
              "f.call(friend);");
-  CHECK_EQ(2, named_access_count);
+  CHECK_EQ(2, access_count);
 
   // Test access using Object.setPrototypeOf reflective method.
-  named_access_count = 0;
+  access_count = 0;
   CompileRun("Object.setPrototypeOf(friend, {});");
-  CHECK_EQ(1, named_access_count);
+  CHECK_EQ(1, access_count);
   CompileRun("Object.getPrototypeOf(friend);");
-  CHECK_EQ(2, named_access_count);
+  CHECK_EQ(2, access_count);
 }
 
 
@@ -21192,8 +21125,7 @@ TEST(Regress411877) {
   v8::HandleScope handle_scope(isolate);
   v8::Handle<v8::ObjectTemplate> object_template =
       v8::ObjectTemplate::New(isolate);
-  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
-                                           IndexedAccessCounter);
+  object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
 
   v8::Handle<Context> context = Context::New(isolate);
   v8::Context::Scope context_scope(context);
@@ -21208,8 +21140,7 @@ TEST(GetHiddenPropertyTableAfterAccessCheck) {
   v8::HandleScope handle_scope(isolate);
   v8::Handle<v8::ObjectTemplate> object_template =
       v8::ObjectTemplate::New(isolate);
-  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
-                                           IndexedAccessCounter);
+  object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
 
   v8::Handle<Context> context = Context::New(isolate);
   v8::Context::Scope context_scope(context);
@@ -21227,8 +21158,7 @@ TEST(Regress411793) {
   v8::HandleScope handle_scope(isolate);
   v8::Handle<v8::ObjectTemplate> object_template =
       v8::ObjectTemplate::New(isolate);
-  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
-                                           IndexedAccessCounter);
+  object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
 
   v8::Handle<Context> context = Context::New(isolate);
   v8::Context::Scope context_scope(context);
@@ -21806,6 +21736,7 @@ TEST(TurboAsmDisablesNeuter) {
       "Module(this, {}, buffer).load();"
       "buffer";
 
+  i::FLAG_turbo_osr = false;  // TODO(titzer): test requires eager TF.
   v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
   CHECK_EQ(should_be_neuterable, result->IsNeuterable());
 
@@ -21820,6 +21751,7 @@ TEST(TurboAsmDisablesNeuter) {
       "Module(this, {}, buffer).store();"
       "buffer";
 
+  i::FLAG_turbo_osr = false;  // TODO(titzer): test requires eager TF.
   result = CompileRun(store).As<v8::ArrayBuffer>();
   CHECK_EQ(should_be_neuterable, result->IsNeuterable());
 }
@@ -21833,8 +21765,7 @@ TEST(GetPrototypeAccessControl) {
 
   v8::Handle<v8::ObjectTemplate> obj_template =
       v8::ObjectTemplate::New(isolate);
-  obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
-                                        BlockEverythingIndexed);
+  obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
 
   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
 
@@ -21917,7 +21848,6 @@ TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
 TEST(NewStringRangeError) {
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope handle_scope(isolate);
-  LocalContext env;
   const int length = i::String::kMaxLength + 1;
   const int buffer_size = length * sizeof(uint16_t);
   void* buffer = malloc(buffer_size);
@@ -21928,21 +21858,21 @@ TEST(NewStringRangeError) {
     char* data = reinterpret_cast<char*>(buffer);
     CHECK(v8::String::NewFromUtf8(isolate, data, v8::String::kNormalString,
                                   length).IsEmpty());
-    CHECK(try_catch.HasCaught());
+    CHECK(!try_catch.HasCaught());
   }
   {
     v8::TryCatch try_catch;
     uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
     CHECK(v8::String::NewFromOneByte(isolate, data, v8::String::kNormalString,
                                      length).IsEmpty());
-    CHECK(try_catch.HasCaught());
+    CHECK(!try_catch.HasCaught());
   }
   {
     v8::TryCatch try_catch;
     uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
     CHECK(v8::String::NewFromTwoByte(isolate, data, v8::String::kNormalString,
                                      length).IsEmpty());
-    CHECK(try_catch.HasCaught());
+    CHECK(!try_catch.HasCaught());
   }
   free(buffer);
 }
diff --git a/deps/v8/test/cctest/test-array-list.cc b/deps/v8/test/cctest/test-array-list.cc
new file mode 100644 (file)
index 0000000..2852043
--- /dev/null
@@ -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 <stdlib.h>
+
+#include "src/v8.h"
+
+#include "src/factory.h"
+#include "test/cctest/cctest.h"
+
+namespace {
+
+using namespace v8::internal;
+
+
+TEST(ArrayList) {
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  Handle<ArrayList> array(
+      ArrayList::cast(isolate->heap()->empty_fixed_array()));
+  CHECK_EQ(0, array->Length());
+  array = ArrayList::Add(array, handle(Smi::FromInt(100), isolate));
+  CHECK_EQ(1, array->Length());
+  CHECK_EQ(100, Smi::cast(array->Get(0))->value());
+  array = ArrayList::Add(array, handle(Smi::FromInt(200), isolate),
+                         handle(Smi::FromInt(300), isolate));
+  CHECK_EQ(3, array->Length());
+  CHECK_EQ(100, Smi::cast(array->Get(0))->value());
+  CHECK_EQ(200, Smi::cast(array->Get(1))->value());
+  CHECK_EQ(300, Smi::cast(array->Get(2))->value());
+  array->Set(2, Smi::FromInt(400));
+  CHECK_EQ(400, Smi::cast(array->Get(2))->value());
+  array->Clear(2, isolate->heap()->undefined_value());
+  array->SetLength(2);
+  CHECK_EQ(2, array->Length());
+  CHECK_EQ(100, Smi::cast(array->Get(0))->value());
+  CHECK_EQ(200, Smi::cast(array->Get(1))->value());
+}
+}
index df8477b..e54c489 100644 (file)
@@ -11223,3 +11223,173 @@ TEST(pool_size) {
 
   TEARDOWN();
 }
+
+
+TEST(jump_tables_forward) {
+  // Test jump tables with forward jumps.
+  const int kNumCases = 512;
+
+  INIT_V8();
+  SETUP_SIZE(kNumCases * 5 * kInstructionSize + 8192);
+  START();
+
+  int32_t values[kNumCases];
+  isolate->random_number_generator()->NextBytes(values, sizeof(values));
+  int32_t results[kNumCases];
+  memset(results, 0, sizeof(results));
+  uintptr_t results_ptr = reinterpret_cast<uintptr_t>(results);
+
+  Label loop;
+  Label labels[kNumCases];
+  Label done;
+
+  const Register& index = x0;
+  STATIC_ASSERT(sizeof(results[0]) == 4);
+  const Register& value = w1;
+  const Register& target = x2;
+
+  __ Mov(index, 0);
+  __ Mov(target, results_ptr);
+  __ Bind(&loop);
+
+  {
+    Assembler::BlockPoolsScope block_pools(&masm);
+    Label base;
+
+    __ Adr(x10, &base);
+    __ Ldr(x11, MemOperand(x10, index, LSL, kPointerSizeLog2));
+    __ Br(x11);
+    __ Bind(&base);
+    for (int i = 0; i < kNumCases; ++i) {
+      __ dcptr(&labels[i]);
+    }
+  }
+
+  for (int i = 0; i < kNumCases; ++i) {
+    __ Bind(&labels[i]);
+    __ Mov(value, values[i]);
+    __ B(&done);
+  }
+
+  __ Bind(&done);
+  __ Str(value, MemOperand(target, 4, PostIndex));
+  __ Add(index, index, 1);
+  __ Cmp(index, kNumCases);
+  __ B(ne, &loop);
+
+  END();
+
+  RUN();
+
+  for (int i = 0; i < kNumCases; ++i) {
+    CHECK_EQ(values[i], results[i]);
+  }
+
+  TEARDOWN();
+}
+
+
+TEST(jump_tables_backward) {
+  // Test jump tables with backward jumps.
+  const int kNumCases = 512;
+
+  INIT_V8();
+  SETUP_SIZE(kNumCases * 5 * kInstructionSize + 8192);
+  START();
+
+  int32_t values[kNumCases];
+  isolate->random_number_generator()->NextBytes(values, sizeof(values));
+  int32_t results[kNumCases];
+  memset(results, 0, sizeof(results));
+  uintptr_t results_ptr = reinterpret_cast<uintptr_t>(results);
+
+  Label loop;
+  Label labels[kNumCases];
+  Label done;
+
+  const Register& index = x0;
+  STATIC_ASSERT(sizeof(results[0]) == 4);
+  const Register& value = w1;
+  const Register& target = x2;
+
+  __ Mov(index, 0);
+  __ Mov(target, results_ptr);
+  __ B(&loop);
+
+  for (int i = 0; i < kNumCases; ++i) {
+    __ Bind(&labels[i]);
+    __ Mov(value, values[i]);
+    __ B(&done);
+  }
+
+  __ Bind(&loop);
+  {
+    Assembler::BlockPoolsScope block_pools(&masm);
+    Label base;
+
+    __ Adr(x10, &base);
+    __ Ldr(x11, MemOperand(x10, index, LSL, kPointerSizeLog2));
+    __ Br(x11);
+    __ Bind(&base);
+    for (int i = 0; i < kNumCases; ++i) {
+      __ dcptr(&labels[i]);
+    }
+  }
+
+  __ Bind(&done);
+  __ Str(value, MemOperand(target, 4, PostIndex));
+  __ Add(index, index, 1);
+  __ Cmp(index, kNumCases);
+  __ B(ne, &loop);
+
+  END();
+
+  RUN();
+
+  for (int i = 0; i < kNumCases; ++i) {
+    CHECK_EQ(values[i], results[i]);
+  }
+
+  TEARDOWN();
+}
+
+
+TEST(internal_reference_linked) {
+  // Test internal reference when they are linked in a label chain.
+
+  INIT_V8();
+  SETUP();
+  START();
+
+  Label done;
+
+  __ Mov(x0, 0);
+  __ Cbnz(x0, &done);
+
+  {
+    Assembler::BlockPoolsScope block_pools(&masm);
+    Label base;
+
+    __ Adr(x10, &base);
+    __ Ldr(x11, MemOperand(x10));
+    __ Br(x11);
+    __ Bind(&base);
+    __ dcptr(&done);
+  }
+
+  // Dead code, just to extend the label chain.
+  __ B(&done);
+  __ dcptr(&done);
+  __ Tbz(x0, 1, &done);
+
+  __ Bind(&done);
+  __ Mov(x0, 1);
+
+  END();
+
+  RUN();
+
+  CHECK_EQUAL_64(0x1, x0);
+
+  TEARDOWN();
+}
index 46592a0..5a7ad02 100644 (file)
@@ -34,7 +34,6 @@
 #include "src/factory.h"
 #include "src/macro-assembler.h"
 #include "src/ostreams.h"
-#include "src/serialize.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
index d4cabbc..e55fb24 100644 (file)
@@ -1585,7 +1585,7 @@ TEST(jump_tables3) {
 
   __ bind(&done);
   __ ld(ra, MemOperand(sp));
-  __ addiu(sp, sp, 8);
+  __ daddiu(sp, sp, 8);
   __ jr(ra);
   __ nop();
 
@@ -1594,7 +1594,7 @@ TEST(jump_tables3) {
   Handle<Code> code = isolate->factory()->NewCode(
       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
 #ifdef OBJECT_PRINT
-//  code->Print(std::cout);
+  code->Print(std::cout);
 #endif
   F1 f = FUNCTION_CAST<F1>(code->entry());
   for (int i = 0; i < kNumCases; ++i) {
index f5d59de..ca88309 100644 (file)
@@ -34,7 +34,6 @@
 #include "src/factory.h"
 #include "src/macro-assembler.h"
 #include "src/ostreams.h"
-#include "src/serialize.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
index c07be84..f83bbbd 100644 (file)
@@ -34,7 +34,6 @@
 #include "src/factory.h"
 #include "src/macro-assembler.h"
 #include "src/ostreams.h"
-#include "src/serialize.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
index faf5332..ed8b1c6 100644 (file)
@@ -60,7 +60,7 @@ static Handle<JSFunction> Compile(const char* source) {
   Handle<String> source_code = isolate->factory()->NewStringFromUtf8(
       CStrVector(source)).ToHandleChecked();
   Handle<SharedFunctionInfo> shared_function = Compiler::CompileScript(
-      source_code, Handle<String>(), 0, 0, false, false,
+      source_code, Handle<String>(), 0, 0, false, false, Handle<Object>(),
       Handle<Context>(isolate->native_context()), NULL, NULL,
       v8::ScriptCompiler::kNoCompileOptions, NOT_NATIVES_CODE, false);
   return isolate->factory()->NewFunctionFromSharedFunctionInfo(
index 4536576..8b9b2cf 100644 (file)
@@ -284,8 +284,9 @@ TEST(ConstantPoolCompacting) {
   Page* first_page = heap->old_data_space()->anchor()->next_page();
   {
     HandleScope scope(isolate);
+    int dummy_array_size = Page::kMaxRegularHeapObjectSize - 92 * KB;
     Handle<HeapObject> temp =
-        factory->NewFixedDoubleArray(900 * KB / kDoubleSize, TENURED);
+        factory->NewFixedDoubleArray(dummy_array_size / kDoubleSize, TENURED);
     CHECK(heap->InOldDataSpace(temp->address()));
     Handle<HeapObject> heap_ptr =
         factory->NewHeapNumber(5.0, IMMUTABLE, TENURED);
index b7881ed..7894251 100644 (file)
@@ -362,3 +362,58 @@ TEST(BitField64) {
   CHECK(x == MiddleBits::encode(3));
   CHECK_EQ(3, MiddleBits::decode(x));
 }
+
+
+static void CheckNonArrayIndex(bool expected, const char* chars) {
+  auto isolate = CcTest::i_isolate();
+  auto string = isolate->factory()->NewStringFromAsciiChecked(chars);
+  CHECK_EQ(expected, IsNonArrayIndexInteger(*string));
+}
+
+
+TEST(NonArrayIndexParsing) {
+  auto isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  CheckNonArrayIndex(false, "");
+  CheckNonArrayIndex(false, "-");
+  CheckNonArrayIndex(false, "0");
+  CheckNonArrayIndex(false, "01");
+  CheckNonArrayIndex(false, "-01");
+  CheckNonArrayIndex(false, "4294967295");
+  CheckNonArrayIndex(false, "429496.7295");
+  CheckNonArrayIndex(false, "43s3");
+  CheckNonArrayIndex(true, "-0");
+  CheckNonArrayIndex(true, "-1");
+  CheckNonArrayIndex(true, "4294967296");
+  CheckNonArrayIndex(true, "-4294967296");
+  CheckNonArrayIndex(
+      true,
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296");
+  CheckNonArrayIndex(
+      true,
+      "-429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296"
+      "429496729642949672964294967296429496729642949672964294967296");
+}
index e2b6db0..a8cbdd5 100644 (file)
@@ -56,6 +56,16 @@ static v8::Local<v8::Function> GetFunction(v8::Context* env, const char* name) {
 }
 
 
+static int offset(const char* src, const char* substring) {
+  return static_cast<int>(strstr(src, substring) - src);
+}
+
+
+static const char* reason(const i::Deoptimizer::DeoptReason reason) {
+  return i::Deoptimizer::GetDeoptReason(reason);
+}
+
+
 TEST(StartStop) {
   i::Isolate* isolate = CcTest::i_isolate();
   CpuProfilesCollection profiles(isolate->heap());
@@ -433,8 +443,7 @@ static v8::CpuProfile* RunProfiler(
 static bool ContainsString(v8::Handle<v8::String> string,
                            const Vector<v8::Handle<v8::String> >& vector) {
   for (int i = 0; i < vector.length(); i++) {
-    if (string->Equals(vector[i]))
-      return true;
+    if (string->Equals(vector[i])) return true;
   }
   return false;
 }
@@ -445,18 +454,31 @@ static void CheckChildrenNames(const v8::CpuProfileNode* node,
   int count = node->GetChildrenCount();
   for (int i = 0; i < count; i++) {
     v8::Handle<v8::String> name = node->GetChild(i)->GetFunctionName();
-    CHECK(ContainsString(name, names));
+    if (!ContainsString(name, names)) {
+      char buffer[100];
+      i::SNPrintF(Vector<char>(buffer, arraysize(buffer)),
+                  "Unexpected child '%s' found in '%s'",
+                  *v8::String::Utf8Value(name),
+                  *v8::String::Utf8Value(node->GetFunctionName()));
+      FATAL(buffer);
+    }
     // Check that there are no duplicates.
     for (int j = 0; j < count; j++) {
       if (j == i) continue;
-      CHECK(!name->Equals(node->GetChild(j)->GetFunctionName()));
+      if (name->Equals(node->GetChild(j)->GetFunctionName())) {
+        char buffer[100];
+        i::SNPrintF(Vector<char>(buffer, arraysize(buffer)),
+                    "Second child with the same name '%s' found in '%s'",
+                    *v8::String::Utf8Value(name),
+                    *v8::String::Utf8Value(node->GetFunctionName()));
+        FATAL(buffer);
+      }
     }
   }
 }
 
 
-static const v8::CpuProfileNode* FindChild(v8::Isolate* isolate,
-                                           const v8::CpuProfileNode* node,
+static const v8::CpuProfileNode* FindChild(const v8::CpuProfileNode* node,
                                            const char* name) {
   int count = node->GetChildrenCount();
   v8::Handle<v8::String> nameHandle = v8_str(name);
@@ -468,10 +490,9 @@ static const v8::CpuProfileNode* FindChild(v8::Isolate* isolate,
 }
 
 
-static const v8::CpuProfileNode* GetChild(v8::Isolate* isolate,
-                                          const v8::CpuProfileNode* node,
+static const v8::CpuProfileNode* GetChild(const v8::CpuProfileNode* node,
                                           const char* name) {
-  const v8::CpuProfileNode* result = FindChild(isolate, node, name);
+  const v8::CpuProfileNode* result = FindChild(node, name);
   if (!result) {
     char buffer[100];
     i::SNPrintF(Vector<char>(buffer, arraysize(buffer)),
@@ -482,26 +503,24 @@ static const v8::CpuProfileNode* GetChild(v8::Isolate* isolate,
 }
 
 
-static void CheckSimpleBranch(v8::Isolate* isolate,
-                              const v8::CpuProfileNode* node,
+static void CheckSimpleBranch(const v8::CpuProfileNode* node,
                               const char* names[], int length) {
   for (int i = 0; i < length; i++) {
     const char* name = names[i];
-    node = GetChild(isolate, node, name);
+    node = GetChild(node, name);
     int expectedChildrenCount = (i == length - 1) ? 0 : 1;
     CHECK_EQ(expectedChildrenCount, node->GetChildrenCount());
   }
 }
 
 
-static const v8::CpuProfileNode* GetSimpleBranch(v8::Isolate* isolate,
-                                                 const v8::CpuProfileNode* node,
-                                                 const char* names[],
-                                                 int length) {
+static const ProfileNode* GetSimpleBranch(v8::CpuProfile* profile,
+                                          const char* names[], int length) {
+  const v8::CpuProfileNode* node = profile->GetTopDownRoot();
   for (int i = 0; i < length; i++) {
-    node = GetChild(isolate, node, names[i]);
+    node = GetChild(node, names[i]);
   }
-  return node;
+  return reinterpret_cast<const ProfileNode*>(node);
 }
 
 
@@ -577,23 +596,18 @@ TEST(CollectCpuProfile) {
   names[2] = v8_str("start");
   CheckChildrenNames(root, names);
 
-  const v8::CpuProfileNode* startNode =
-      GetChild(env->GetIsolate(), root, "start");
+  const v8::CpuProfileNode* startNode = GetChild(root, "start");
   CHECK_EQ(1, startNode->GetChildrenCount());
 
-  const v8::CpuProfileNode* fooNode =
-      GetChild(env->GetIsolate(), startNode, "foo");
+  const v8::CpuProfileNode* fooNode = GetChild(startNode, "foo");
   CHECK_EQ(3, fooNode->GetChildrenCount());
 
   const char* barBranch[] = { "bar", "delay", "loop" };
-  CheckSimpleBranch(env->GetIsolate(), fooNode, barBranch,
-                    arraysize(barBranch));
+  CheckSimpleBranch(fooNode, barBranch, arraysize(barBranch));
   const char* bazBranch[] = { "baz", "delay", "loop" };
-  CheckSimpleBranch(env->GetIsolate(), fooNode, bazBranch,
-                    arraysize(bazBranch));
+  CheckSimpleBranch(fooNode, bazBranch, arraysize(bazBranch));
   const char* delayBranch[] = { "delay", "loop" };
-  CheckSimpleBranch(env->GetIsolate(), fooNode, delayBranch,
-                    arraysize(delayBranch));
+  CheckSimpleBranch(fooNode, delayBranch, arraysize(delayBranch));
 
   profile->Delete();
 }
@@ -650,11 +664,10 @@ TEST(HotDeoptNoFrameEntry) {
   names[2] = v8_str("start");
   CheckChildrenNames(root, names);
 
-  const v8::CpuProfileNode* startNode =
-      GetChild(env->GetIsolate(), root, "start");
+  const v8::CpuProfileNode* startNode = GetChild(root, "start");
   CHECK_EQ(1, startNode->GetChildrenCount());
 
-  GetChild(env->GetIsolate(), startNode, "foo");
+  GetChild(startNode, "foo");
 
   profile->Delete();
 }
@@ -736,17 +749,15 @@ TEST(SampleWhenFrameIsNotSetup) {
   names[2] = v8_str("start");
   CheckChildrenNames(root, names);
 
-  const v8::CpuProfileNode* startNode =
-      FindChild(env->GetIsolate(), root, "start");
+  const v8::CpuProfileNode* startNode = FindChild(root, "start");
   // On slow machines there may be no meaningfull samples at all, skip the
   // check there.
   if (startNode && startNode->GetChildrenCount() > 0) {
     CHECK_EQ(1, startNode->GetChildrenCount());
-    const v8::CpuProfileNode* delayNode =
-        GetChild(env->GetIsolate(), startNode, "delay");
+    const v8::CpuProfileNode* delayNode = GetChild(startNode, "delay");
     if (delayNode->GetChildrenCount() > 0) {
       CHECK_EQ(1, delayNode->GetChildrenCount());
-      GetChild(env->GetIsolate(), delayNode, "loop");
+      GetChild(delayNode, "loop");
     }
   }
 
@@ -842,10 +853,9 @@ TEST(NativeAccessorUninitializedIC) {
       RunProfiler(env.local(), function, args, arraysize(args), 180);
 
   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
-  const v8::CpuProfileNode* startNode =
-      GetChild(isolate, root, "start");
-  GetChild(isolate, startNode, "get foo");
-  GetChild(isolate, startNode, "set foo");
+  const v8::CpuProfileNode* startNode = GetChild(root, "start");
+  GetChild(startNode, "get foo");
+  GetChild(startNode, "set foo");
 
   profile->Delete();
 }
@@ -894,10 +904,9 @@ TEST(NativeAccessorMonomorphicIC) {
       RunProfiler(env.local(), function, args, arraysize(args), 200);
 
   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
-  const v8::CpuProfileNode* startNode =
-      GetChild(isolate, root, "start");
-  GetChild(isolate, startNode, "get foo");
-  GetChild(isolate, startNode, "set foo");
+  const v8::CpuProfileNode* startNode = GetChild(root, "start");
+  GetChild(startNode, "get foo");
+  GetChild(startNode, "set foo");
 
   profile->Delete();
 }
@@ -944,9 +953,8 @@ TEST(NativeMethodUninitializedIC) {
       RunProfiler(env.local(), function, args, arraysize(args), 100);
 
   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
-  const v8::CpuProfileNode* startNode =
-      GetChild(isolate, root, "start");
-  GetChild(isolate, startNode, "fooMethod");
+  const v8::CpuProfileNode* startNode = GetChild(root, "start");
+  GetChild(startNode, "fooMethod");
 
   profile->Delete();
 }
@@ -997,10 +1005,9 @@ TEST(NativeMethodMonomorphicIC) {
       RunProfiler(env.local(), function, args, arraysize(args), 100);
 
   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
-  GetChild(isolate, root, "start");
-  const v8::CpuProfileNode* startNode =
-      GetChild(isolate, root, "start");
-  GetChild(isolate, startNode, "fooMethod");
+  GetChild(root, "start");
+  const v8::CpuProfileNode* startNode = GetChild(root, "start");
+  GetChild(startNode, "fooMethod");
 
   profile->Delete();
 }
@@ -1034,9 +1041,8 @@ TEST(BoundFunctionCall) {
   // Don't allow |foo| node to be at the top level.
   CheckChildrenNames(root, names);
 
-  const v8::CpuProfileNode* startNode =
-      GetChild(env->GetIsolate(), root, "start");
-  GetChild(env->GetIsolate(), startNode, "foo");
+  const v8::CpuProfileNode* startNode = GetChild(root, "start");
+  GetChild(startNode, "foo");
 
   profile->Delete();
 }
@@ -1086,10 +1092,10 @@ TEST(TickLines) {
   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
   profiles->StartProfiling("", false);
   ProfileGenerator generator(profiles);
-  ProfilerEventsProcessor* processor = new ProfilerEventsProcessor(
-      &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100));
+  SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
+      &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100)));
   processor->Start();
-  CpuProfiler profiler(isolate, profiles, &generator, processor);
+  CpuProfiler profiler(isolate, profiles, &generator, processor.get());
 
   // Enqueue code creation events.
   i::Handle<i::String> str = factory->NewStringFromAsciiChecked(func_name);
@@ -1099,7 +1105,7 @@ TEST(TickLines) {
                            *str, line, column);
 
   // Enqueue a tick event to enable code events processing.
-  EnqueueTickSampleEvent(processor, code_address);
+  EnqueueTickSampleEvent(processor.get(), code_address);
 
   processor->StopSynchronously();
 
@@ -1197,8 +1203,7 @@ TEST(FunctionCallSample) {
   // won't be |start| node in the profiles.
   bool is_gc_stress_testing =
       (i::FLAG_gc_interval != -1) || i::FLAG_stress_compaction;
-  const v8::CpuProfileNode* startNode =
-      FindChild(env->GetIsolate(), root, "start");
+  const v8::CpuProfileNode* startNode = FindChild(root, "start");
   CHECK(is_gc_stress_testing || startNode);
   if (startNode) {
     ScopedVector<v8::Handle<v8::String> > names(2);
@@ -1207,8 +1212,8 @@ TEST(FunctionCallSample) {
     CheckChildrenNames(startNode, names);
   }
 
-  const v8::CpuProfileNode* unresolvedNode = FindChild(
-      env->GetIsolate(), root, i::ProfileGenerator::kUnresolvedFunctionName);
+  const v8::CpuProfileNode* unresolvedNode =
+      FindChild(root, i::ProfileGenerator::kUnresolvedFunctionName);
   if (unresolvedNode) {
     ScopedVector<v8::Handle<v8::String> > names(1);
     names[0] = v8_str("call");
@@ -1270,8 +1275,7 @@ TEST(FunctionApplySample) {
     CheckChildrenNames(root, names);
   }
 
-  const v8::CpuProfileNode* startNode =
-      FindChild(env->GetIsolate(), root, "start");
+  const v8::CpuProfileNode* startNode = FindChild(root, "start");
   if (startNode) {
     {
       ScopedVector<v8::Handle<v8::String> > names(2);
@@ -1280,8 +1284,7 @@ TEST(FunctionApplySample) {
       CheckChildrenNames(startNode, names);
     }
 
-    const v8::CpuProfileNode* testNode =
-        FindChild(env->GetIsolate(), startNode, "test");
+    const v8::CpuProfileNode* testNode = FindChild(startNode, "test");
     if (testNode) {
       ScopedVector<v8::Handle<v8::String> > names(3);
       names[0] = v8_str("bar");
@@ -1293,12 +1296,11 @@ TEST(FunctionApplySample) {
     }
 
     if (const v8::CpuProfileNode* unresolvedNode =
-            FindChild(env->GetIsolate(), startNode,
-                      ProfileGenerator::kUnresolvedFunctionName)) {
+            FindChild(startNode, ProfileGenerator::kUnresolvedFunctionName)) {
       ScopedVector<v8::Handle<v8::String> > names(1);
       names[0] = v8_str("apply");
       CheckChildrenNames(unresolvedNode, names);
-      GetChild(env->GetIsolate(), unresolvedNode, "apply");
+      GetChild(unresolvedNode, "apply");
     }
   }
 
@@ -1354,10 +1356,9 @@ TEST(CpuProfileDeepStack) {
     CheckChildrenNames(root, names);
   }
 
-  const v8::CpuProfileNode* node =
-      GetChild(env->GetIsolate(), root, "start");
+  const v8::CpuProfileNode* node = GetChild(root, "start");
   for (int i = 0; i < 250; ++i) {
-    node = GetChild(env->GetIsolate(), node, "foo");
+    node = GetChild(node, "foo");
   }
   // TODO(alph):
   // In theory there must be one more 'foo' and a 'startProfiling' nodes,
@@ -1419,18 +1420,16 @@ TEST(JsNativeJsSample) {
     CheckChildrenNames(root, names);
   }
 
-  const v8::CpuProfileNode* startNode =
-      GetChild(env->GetIsolate(), root, "start");
+  const v8::CpuProfileNode* startNode = GetChild(root, "start");
   CHECK_EQ(1, startNode->GetChildrenCount());
   const v8::CpuProfileNode* nativeFunctionNode =
-      GetChild(env->GetIsolate(), startNode, "CallJsFunction");
+      GetChild(startNode, "CallJsFunction");
 
   CHECK_EQ(1, nativeFunctionNode->GetChildrenCount());
-  const v8::CpuProfileNode* barNode =
-      GetChild(env->GetIsolate(), nativeFunctionNode, "bar");
+  const v8::CpuProfileNode* barNode = GetChild(nativeFunctionNode, "bar");
 
   CHECK_EQ(1, barNode->GetChildrenCount());
-  GetChild(env->GetIsolate(), barNode, "foo");
+  GetChild(barNode, "foo");
 
   profile->Delete();
 }
@@ -1481,22 +1480,20 @@ TEST(JsNativeJsRuntimeJsSample) {
   names[2] = v8_str("start");
   CheckChildrenNames(root, names);
 
-  const v8::CpuProfileNode* startNode =
-      GetChild(env->GetIsolate(), root, "start");
+  const v8::CpuProfileNode* startNode = GetChild(root, "start");
   CHECK_EQ(1, startNode->GetChildrenCount());
   const v8::CpuProfileNode* nativeFunctionNode =
-      GetChild(env->GetIsolate(), startNode, "CallJsFunction");
+      GetChild(startNode, "CallJsFunction");
 
   CHECK_EQ(1, nativeFunctionNode->GetChildrenCount());
-  const v8::CpuProfileNode* barNode =
-      GetChild(env->GetIsolate(), nativeFunctionNode, "bar");
+  const v8::CpuProfileNode* barNode = GetChild(nativeFunctionNode, "bar");
 
   // The child is in fact a bound foo.
   // A bound function has a wrapper that may make calls to
   // other functions e.g. "get length".
   CHECK_LE(1, barNode->GetChildrenCount());
   CHECK_GE(2, barNode->GetChildrenCount());
-  GetChild(env->GetIsolate(), barNode, "foo");
+  GetChild(barNode, "foo");
 
   profile->Delete();
 }
@@ -1560,22 +1557,19 @@ TEST(JsNative1JsNative2JsSample) {
   names[2] = v8_str("start");
   CheckChildrenNames(root, names);
 
-  const v8::CpuProfileNode* startNode =
-      GetChild(env->GetIsolate(), root, "start");
+  const v8::CpuProfileNode* startNode = GetChild(root, "start");
   CHECK_EQ(1, startNode->GetChildrenCount());
   const v8::CpuProfileNode* nativeNode1 =
-      GetChild(env->GetIsolate(), startNode, "CallJsFunction1");
+      GetChild(startNode, "CallJsFunction1");
 
   CHECK_EQ(1, nativeNode1->GetChildrenCount());
-  const v8::CpuProfileNode* barNode =
-      GetChild(env->GetIsolate(), nativeNode1, "bar");
+  const v8::CpuProfileNode* barNode = GetChild(nativeNode1, "bar");
 
   CHECK_EQ(1, barNode->GetChildrenCount());
-  const v8::CpuProfileNode* nativeNode2 =
-      GetChild(env->GetIsolate(), barNode, "CallJsFunction2");
+  const v8::CpuProfileNode* nativeNode2 = GetChild(barNode, "CallJsFunction2");
 
   CHECK_EQ(1, nativeNode2->GetChildrenCount());
-  GetChild(env->GetIsolate(), nativeNode2, "foo");
+  GetChild(nativeNode2, "foo");
 
   profile->Delete();
 }
@@ -1620,12 +1614,12 @@ TEST(IdleTime) {
   CheckChildrenNames(root, names);
 
   const v8::CpuProfileNode* programNode =
-      GetChild(env->GetIsolate(), root, ProfileGenerator::kProgramEntryName);
+      GetChild(root, ProfileGenerator::kProgramEntryName);
   CHECK_EQ(0, programNode->GetChildrenCount());
   CHECK_GE(programNode->GetHitCount(), 3u);
 
   const v8::CpuProfileNode* idleNode =
-      GetChild(env->GetIsolate(), root, ProfileGenerator::kIdleEntryName);
+      GetChild(root, ProfileGenerator::kIdleEntryName);
   CHECK_EQ(0, idleNode->GetChildrenCount());
   CHECK_GE(idleNode->GetHitCount(), 3u);
 
@@ -1672,16 +1666,16 @@ TEST(FunctionDetails) {
   //  0        foo 18 #4 TryCatchStatement script_a:2
   //  1          bar 18 #5 no reason script_a:3
   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
-  const v8::CpuProfileNode* script = GetChild(env->GetIsolate(), root, "");
+  const v8::CpuProfileNode* script = GetChild(root, "");
   CheckFunctionDetails(env->GetIsolate(), script, "", "script_b",
                        script_b->GetUnboundScript()->GetId(), 1, 1);
-  const v8::CpuProfileNode* baz = GetChild(env->GetIsolate(), script, "baz");
+  const v8::CpuProfileNode* baz = GetChild(script, "baz");
   CheckFunctionDetails(env->GetIsolate(), baz, "baz", "script_b",
                        script_b->GetUnboundScript()->GetId(), 3, 16);
-  const v8::CpuProfileNode* foo = GetChild(env->GetIsolate(), baz, "foo");
+  const v8::CpuProfileNode* foo = GetChild(baz, "foo");
   CheckFunctionDetails(env->GetIsolate(), foo, "foo", "script_a",
                        script_a->GetUnboundScript()->GetId(), 2, 1);
-  const v8::CpuProfileNode* bar = GetChild(env->GetIsolate(), foo, "bar");
+  const v8::CpuProfileNode* bar = GetChild(foo, "bar");
   CheckFunctionDetails(env->GetIsolate(), bar, "bar", "script_a",
                        script_a->GetUnboundScript()->GetId(), 3, 14);
 }
@@ -1720,39 +1714,17 @@ TEST(DontStopOnFinishedProfileDelete) {
 }
 
 
-static const char* collect_deopt_events_test_source =
-    "function opt_function(left, right, depth) {\n"
-    "  if (depth) return opt_function(left, right, depth - 1);\n"
-    "\n"
-    "  var k = left / 10;\n"
-    "  var r = 10 / right;\n"
-    "  return k + r;"
-    "}\n"
-    "\n"
-    "function test(left, right) {\n"
-    "  return opt_function(left, right, 1);\n"
-    "}\n"
-    "\n"
-    "startProfiling();\n"
-    "\n"
-    "test(10, 10);\n"
-    "\n"
-    "%OptimizeFunctionOnNextCall(opt_function)\n"
-    "\n"
-    "test(10, 10);\n"
-    "\n"
-    "test(undefined, 10);\n"
-    "\n"
-    "%OptimizeFunctionOnNextCall(opt_function)\n"
-    "\n"
-    "test(10, 10);\n"
-    "\n"
-    "test(10, 0);\n"
-    "\n"
-    "stopProfiling();\n"
-    "\n";
+const char* GetBranchDeoptReason(i::CpuProfile* iprofile, const char* branch[],
+                                 int length) {
+  v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
+  const ProfileNode* iopt_function = NULL;
+  iopt_function = GetSimpleBranch(profile, branch, length);
+  CHECK_EQ(1, iopt_function->deopt_infos().size());
+  return iopt_function->deopt_infos()[0].deopt_reason;
+}
 
 
+// deopt at top function
 TEST(CollectDeoptEvents) {
   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
   i::FLAG_allow_natives_syntax = true;
@@ -1763,21 +1735,90 @@ TEST(CollectDeoptEvents) {
   v8::CpuProfiler* profiler = isolate->GetCpuProfiler();
   i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
 
-  v8::Script::Compile(v8_str(collect_deopt_events_test_source))->Run();
+  const char opt_source[] =
+      "function opt_function%d(value, depth) {\n"
+      "  if (depth) return opt_function%d(value, depth - 1);\n"
+      "\n"
+      "  return  10 / value;\n"
+      "}\n"
+      "\n";
+
+  for (int i = 0; i < 3; ++i) {
+    i::EmbeddedVector<char, sizeof(opt_source) + 100> buffer;
+    i::SNPrintF(buffer, opt_source, i, i);
+    v8::Script::Compile(v8_str(buffer.start()))->Run();
+  }
+
+  const char* source =
+      "startProfiling();\n"
+      "\n"
+      "opt_function0(1, 1);\n"
+      "\n"
+      "%OptimizeFunctionOnNextCall(opt_function0)\n"
+      "\n"
+      "opt_function0(1, 1);\n"
+      "\n"
+      "opt_function0(undefined, 1);\n"
+      "\n"
+      "opt_function1(1, 1);\n"
+      "\n"
+      "%OptimizeFunctionOnNextCall(opt_function1)\n"
+      "\n"
+      "opt_function1(1, 1);\n"
+      "\n"
+      "opt_function1(NaN, 1);\n"
+      "\n"
+      "opt_function2(1, 1);\n"
+      "\n"
+      "%OptimizeFunctionOnNextCall(opt_function2)\n"
+      "\n"
+      "opt_function2(1, 1);\n"
+      "\n"
+      "opt_function2(0, 1);\n"
+      "\n"
+      "stopProfiling();\n"
+      "\n";
+
+  v8::Script::Compile(v8_str(source))->Run();
   i::CpuProfile* iprofile = iprofiler->GetProfile(0);
   iprofile->Print();
-  v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
-  const char* branch[] = {"", "test", "opt_function", "opt_function"};
-  const v8::CpuProfileNode* opt_function = GetSimpleBranch(
-      env->GetIsolate(), profile->GetTopDownRoot(), branch, arraysize(branch));
-  CHECK(opt_function);
-  const i::ProfileNode* iopt_function =
-      reinterpret_cast<const i::ProfileNode*>(opt_function);
-  CHECK_EQ(2, iopt_function->deopt_infos().length());
-  CHECK_EQ(i::Deoptimizer::GetDeoptReason(i::Deoptimizer::kNotAHeapNumber),
-           iopt_function->deopt_infos()[0].deopt_reason);
-  CHECK_EQ(i::Deoptimizer::GetDeoptReason(i::Deoptimizer::kDivisionByZero),
-           iopt_function->deopt_infos()[1].deopt_reason);
+  /* The expected profile
+  [Top down]:
+      0  (root) 0 #1
+     23     32 #2
+      1      opt_function2 31 #7
+      1        opt_function2 31 #8
+                  ;;; deopted at script_id: 31 position: 106 with reason
+  'division by zero'.
+      2      opt_function0 29 #3
+      4        opt_function0 29 #4
+                  ;;; deopted at script_id: 29 position: 108 with reason 'not a
+  heap number'.
+      0      opt_function1 30 #5
+      1        opt_function1 30 #6
+                  ;;; deopted at script_id: 30 position: 108 with reason 'lost
+  precision or NaN'.
+  */
+
+  {
+    const char* branch[] = {"", "opt_function0", "opt_function0"};
+    CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber),
+             GetBranchDeoptReason(iprofile, branch, arraysize(branch)));
+  }
+  {
+    const char* branch[] = {"", "opt_function1", "opt_function1"};
+    const char* deopt_reason =
+        GetBranchDeoptReason(iprofile, branch, arraysize(branch));
+    if (deopt_reason != reason(i::Deoptimizer::kNaN) &&
+        deopt_reason != reason(i::Deoptimizer::kLostPrecisionOrNaN)) {
+      FATAL(deopt_reason);
+    }
+  }
+  {
+    const char* branch[] = {"", "opt_function2", "opt_function2"};
+    CHECK_EQ(reason(i::Deoptimizer::kDivisionByZero),
+             GetBranchDeoptReason(iprofile, branch, arraysize(branch)));
+  }
   iprofiler->DeleteProfile(iprofile);
 }
 
@@ -1796,3 +1837,197 @@ TEST(SourceLocation) {
 
   v8::Script::Compile(v8_str(source))->Run();
 }
+
+
+static const char* inlined_source =
+    "function opt_function(left, right) { var k = left / 10; var r = 10 / "
+    "right; return k + r; }\n";
+//   0.........1.........2.........3.........4....*....5.........6......*..7
+
+
+// deopt at the first level inlined function
+TEST(DeoptAtFirstLevelInlinedSource) {
+  if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
+  i::FLAG_allow_natives_syntax = true;
+  v8::HandleScope scope(CcTest::isolate());
+  v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
+  v8::Context::Scope context_scope(env);
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::CpuProfiler* profiler = isolate->GetCpuProfiler();
+  i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
+
+  //   0.........1.........2.........3.........4.........5.........6.........7
+  const char* source =
+      "function test(left, right) { return opt_function(left, right); }\n"
+      "\n"
+      "startProfiling();\n"
+      "\n"
+      "test(10, 10);\n"
+      "\n"
+      "%OptimizeFunctionOnNextCall(test)\n"
+      "\n"
+      "test(10, 10);\n"
+      "\n"
+      "test(undefined, 10);\n"
+      "\n"
+      "stopProfiling();\n"
+      "\n";
+
+  v8::Handle<v8::Script> inlined_script = v8_compile(inlined_source);
+  inlined_script->Run();
+  int inlined_script_id = inlined_script->GetUnboundScript()->GetId();
+
+  v8::Handle<v8::Script> script = v8_compile(source);
+  script->Run();
+  int script_id = script->GetUnboundScript()->GetId();
+
+  i::CpuProfile* iprofile = iprofiler->GetProfile(0);
+  iprofile->Print();
+  /* The expected profile output
+  [Top down]:
+      0  (root) 0 #1
+     10     30 #2
+      1      test 30 #3
+                ;;; deopted at script_id: 29 position: 45 with reason 'not a
+  heap number'.
+                ;;;     Inline point: script_id 30 position: 36.
+      4        opt_function 29 #4
+  */
+  v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
+
+  const char* branch[] = {"", "test"};
+  const ProfileNode* itest_node =
+      GetSimpleBranch(profile, branch, arraysize(branch));
+  const std::vector<i::DeoptInfo>& deopt_infos = itest_node->deopt_infos();
+  CHECK_EQ(1, deopt_infos.size());
+
+  const i::DeoptInfo& info = deopt_infos[0];
+  CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber), info.deopt_reason);
+  CHECK_EQ(2, info.stack.size());
+  CHECK_EQ(inlined_script_id, info.stack[0].script_id);
+  CHECK_EQ(offset(inlined_source, "left /"), info.stack[0].position);
+  CHECK_EQ(script_id, info.stack[1].script_id);
+  CHECK_EQ(offset(source, "opt_function(left,"), info.stack[1].position);
+
+  iprofiler->DeleteProfile(iprofile);
+}
+
+
+// deopt at the second level inlined function
+TEST(DeoptAtSecondLevelInlinedSource) {
+  if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
+  i::FLAG_allow_natives_syntax = true;
+  v8::HandleScope scope(CcTest::isolate());
+  v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
+  v8::Context::Scope context_scope(env);
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::CpuProfiler* profiler = isolate->GetCpuProfiler();
+  i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
+
+  //   0.........1.........2.........3.........4.........5.........6.........7
+  const char* source =
+      "function test2(left, right) { return opt_function(left, right); }\n"
+      "function test1(left, right) { return test2(left, right); }\n"
+      "\n"
+      "startProfiling();\n"
+      "\n"
+      "test1(10, 10);\n"
+      "\n"
+      "%OptimizeFunctionOnNextCall(test1)\n"
+      "\n"
+      "test1(10, 10);\n"
+      "\n"
+      "test1(undefined, 10);\n"
+      "\n"
+      "stopProfiling();\n"
+      "\n";
+
+  v8::Handle<v8::Script> inlined_script = v8_compile(inlined_source);
+  inlined_script->Run();
+  int inlined_script_id = inlined_script->GetUnboundScript()->GetId();
+
+  v8::Handle<v8::Script> script = v8_compile(source);
+  script->Run();
+  int script_id = script->GetUnboundScript()->GetId();
+
+  i::CpuProfile* iprofile = iprofiler->GetProfile(0);
+  iprofile->Print();
+  /* The expected profile output
+  [Top down]:
+      0  (root) 0 #1
+     11     30 #2
+      1      test1 30 #3
+                ;;; deopted at script_id: 29 position: 45 with reason 'not a
+  heap number'.
+                ;;;     Inline point: script_id 30 position: 37.
+                ;;;     Inline point: script_id 30 position: 103.
+      1        test2 30 #4
+      3          opt_function 29 #5
+  */
+
+  v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
+
+  const char* branch[] = {"", "test1"};
+  const ProfileNode* itest_node =
+      GetSimpleBranch(profile, branch, arraysize(branch));
+  const std::vector<i::DeoptInfo>& deopt_infos = itest_node->deopt_infos();
+  CHECK_EQ(1, deopt_infos.size());
+
+  const i::DeoptInfo info = deopt_infos[0];
+  CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber), info.deopt_reason);
+  CHECK_EQ(3, info.stack.size());
+  CHECK_EQ(inlined_script_id, info.stack[0].script_id);
+  CHECK_EQ(offset(inlined_source, "left /"), info.stack[0].position);
+  CHECK_EQ(script_id, info.stack[1].script_id);
+  CHECK_EQ(offset(source, "opt_function(left,"), info.stack[1].position);
+  CHECK_EQ(offset(source, "test2(left, right);"), info.stack[2].position);
+
+  iprofiler->DeleteProfile(iprofile);
+}
+
+
+// deopt in untracked function
+TEST(DeoptUntrackedFunction) {
+  if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
+  i::FLAG_allow_natives_syntax = true;
+  v8::HandleScope scope(CcTest::isolate());
+  v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
+  v8::Context::Scope context_scope(env);
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::CpuProfiler* profiler = isolate->GetCpuProfiler();
+  i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
+
+  //   0.........1.........2.........3.........4.........5.........6.........7
+  const char* source =
+      "function test(left, right) { return opt_function(left, right); }\n"
+      "\n"
+      "test(10, 10);\n"
+      "\n"
+      "%OptimizeFunctionOnNextCall(test)\n"
+      "\n"
+      "test(10, 10);\n"
+      "\n"
+      "startProfiling();\n"  // profiler started after compilation.
+      "\n"
+      "test(undefined, 10);\n"
+      "\n"
+      "stopProfiling();\n"
+      "\n";
+
+  v8::Handle<v8::Script> inlined_script = v8_compile(inlined_source);
+  inlined_script->Run();
+
+  v8::Handle<v8::Script> script = v8_compile(source);
+  script->Run();
+
+  i::CpuProfile* iprofile = iprofiler->GetProfile(0);
+  iprofile->Print();
+  v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
+
+  const char* branch[] = {"", "test"};
+  const ProfileNode* itest_node =
+      GetSimpleBranch(profile, branch, arraysize(branch));
+  CHECK_EQ(0, itest_node->deopt_infos().size());
+
+  iprofiler->DeleteProfile(iprofile);
+}
index 2f722c2..2bcc625 100644 (file)
@@ -28,7 +28,6 @@
 #include "src/v8.h"
 
 #include "src/global-handles.h"
-#include "src/snapshot.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
index a4a993a..5929379 100644 (file)
@@ -416,7 +416,7 @@ void CheckDebuggerUnloaded(bool check_functions) {
           if (RelocInfo::IsCodeTarget(rmode)) {
             CHECK(!Debug::IsDebugBreak(it.rinfo()->target_address()));
           } else if (RelocInfo::IsJSReturn(rmode)) {
-            CHECK(!Debug::IsDebugBreakAtReturn(it.rinfo()));
+            CHECK(!it.rinfo()->IsPatchedReturnSequence());
           }
         }
       }
@@ -437,47 +437,36 @@ static void CheckDebuggerUnloaded(bool check_functions = false) {
 }
 
 
-// Inherit from BreakLocationIterator to get access to protected parts for
-// testing.
-class TestBreakLocationIterator: public v8::internal::BreakLocationIterator {
- public:
-  explicit TestBreakLocationIterator(Handle<v8::internal::DebugInfo> debug_info)
-    : BreakLocationIterator(debug_info, v8::internal::SOURCE_BREAK_LOCATIONS) {}
-  v8::internal::RelocIterator* it() { return reloc_iterator_; }
-  v8::internal::RelocIterator* it_original() {
-    return reloc_iterator_original_;
-  }
-};
-
-
 // Compile a function, set a break point and check that the call at the break
 // location in the code is the expected debug_break function.
 void CheckDebugBreakFunction(DebugLocalContext* env,
                              const char* source, const char* name,
                              int position, v8::internal::RelocInfo::Mode mode,
                              Code* debug_break) {
-  v8::internal::Debug* debug = CcTest::i_isolate()->debug();
+  i::Debug* debug = CcTest::i_isolate()->debug();
 
   // Create function and set the break point.
-  Handle<v8::internal::JSFunction> fun = v8::Utils::OpenHandle(
-      *CompileFunction(env, source, name));
+  Handle<i::JSFunction> fun =
+      v8::Utils::OpenHandle(*CompileFunction(env, source, name));
   int bp = SetBreakPoint(fun, position);
 
   // Check that the debug break function is as expected.
-  Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
+  Handle<i::SharedFunctionInfo> shared(fun->shared());
   CHECK(Debug::HasDebugInfo(shared));
-  TestBreakLocationIterator it1(Debug::GetDebugInfo(shared));
-  it1.FindBreakLocationFromPosition(position, v8::internal::STATEMENT_ALIGNED);
-  v8::internal::RelocInfo::Mode actual_mode = it1.it()->rinfo()->rmode();
-  if (actual_mode == v8::internal::RelocInfo::CODE_TARGET_WITH_ID) {
-    actual_mode = v8::internal::RelocInfo::CODE_TARGET;
+  i::BreakLocation location = i::BreakLocation::FromPosition(
+      Debug::GetDebugInfo(shared), i::SOURCE_BREAK_LOCATIONS, position,
+      i::STATEMENT_ALIGNED);
+  i::RelocInfo::Mode actual_mode = location.rmode();
+  if (actual_mode == i::RelocInfo::CODE_TARGET_WITH_ID) {
+    actual_mode = i::RelocInfo::CODE_TARGET;
   }
   CHECK_EQ(mode, actual_mode);
-  if (mode != v8::internal::RelocInfo::JS_RETURN) {
-    CHECK_EQ(debug_break,
-        Code::GetCodeFromTargetAddress(it1.it()->rinfo()->target_address()));
+  if (mode != i::RelocInfo::JS_RETURN) {
+    CHECK_EQ(debug_break, *location.CodeTarget());
   } else {
-    CHECK(Debug::IsDebugBreakAtReturn(it1.it()->rinfo()));
+    i::RelocInfo rinfo = location.rinfo();
+    CHECK(i::RelocInfo::IsJSReturn(rinfo.rmode()));
+    CHECK(rinfo.IsPatchedReturnSequence());
   }
 
   // Clear the break point and check that the debug break function is no longer
@@ -485,15 +474,17 @@ void CheckDebugBreakFunction(DebugLocalContext* env,
   ClearBreakPoint(bp);
   CHECK(!debug->HasDebugInfo(shared));
   CHECK(debug->EnsureDebugInfo(shared, fun));
-  TestBreakLocationIterator it2(Debug::GetDebugInfo(shared));
-  it2.FindBreakLocationFromPosition(position, v8::internal::STATEMENT_ALIGNED);
-  actual_mode = it2.it()->rinfo()->rmode();
-  if (actual_mode == v8::internal::RelocInfo::CODE_TARGET_WITH_ID) {
-    actual_mode = v8::internal::RelocInfo::CODE_TARGET;
+  location = i::BreakLocation::FromPosition(Debug::GetDebugInfo(shared),
+                                            i::SOURCE_BREAK_LOCATIONS, position,
+                                            i::STATEMENT_ALIGNED);
+  actual_mode = location.rmode();
+  if (actual_mode == i::RelocInfo::CODE_TARGET_WITH_ID) {
+    actual_mode = i::RelocInfo::CODE_TARGET;
   }
   CHECK_EQ(mode, actual_mode);
-  if (mode == v8::internal::RelocInfo::JS_RETURN) {
-    CHECK(!Debug::IsDebugBreakAtReturn(it2.it()->rinfo()));
+  if (mode == i::RelocInfo::JS_RETURN) {
+    i::RelocInfo rinfo = location.rinfo();
+    CHECK(!rinfo.IsPatchedReturnSequence());
   }
 }
 
@@ -6706,6 +6697,7 @@ TEST(ProcessDebugMessagesThreaded) {
       v8::FunctionTemplate::New(isolate, StartSendingCommands);
   env->Global()->Set(v8_str("start"), start->GetFunction());
 
+  i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
   CompileRun("start(); while (true) { }");
 
   CHECK_EQ(20, counting_message_handler_counter);
@@ -7655,7 +7647,6 @@ static void DebugHarmonyScopingListener(
 
 
 TEST(DebugBreakInLexicalScopes) {
-  i::FLAG_harmony_scoping = true;
   i::FLAG_allow_natives_syntax = true;
 
   DebugLocalContext env;
index 5d487bb..f3dc777 100644 (file)
@@ -637,7 +637,6 @@ TEST(CrossScriptReferences) {
 
 
 TEST(CrossScriptReferences_Simple) {
-  i::FLAG_harmony_scoping = true;
   i::FLAG_use_strict = true;
 
   v8::Isolate* isolate = CcTest::isolate();
@@ -652,7 +651,6 @@ TEST(CrossScriptReferences_Simple) {
 
 
 TEST(CrossScriptReferences_Simple2) {
-  i::FLAG_harmony_scoping = true;
   i::FLAG_use_strict = true;
 
   v8::Isolate* isolate = CcTest::isolate();
@@ -675,8 +673,6 @@ TEST(CrossScriptReferences_Simple2) {
 
 
 TEST(CrossScriptReferencesHarmony) {
-  i::FLAG_harmony_scoping = true;
-
   v8::Isolate* isolate = CcTest::isolate();
   HandleScope scope(isolate);
 
@@ -818,9 +814,27 @@ TEST(CrossScriptReferencesHarmony) {
 }
 
 
+TEST(CrossScriptReferencesHarmonyRegress) {
+  v8::Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+  SimpleContext context;
+  context.Check(
+      "'use strict';"
+      "function i1() { "
+      "  let y = 10; return (typeof x2 === 'undefined' ? 0 : 2) + y"
+      "}"
+      "i1();"
+      "i1();",
+      EXPECT_RESULT, Number::New(isolate, 10));
+  context.Check(
+      "'use strict';"
+      "let x2 = 2; i1();",
+      EXPECT_RESULT, Number::New(isolate, 12));
+}
+
+
 TEST(GlobalLexicalOSR) {
   i::FLAG_use_strict = true;
-  i::FLAG_harmony_scoping = true;
 
   v8::Isolate* isolate = CcTest::isolate();
   HandleScope scope(isolate);
@@ -844,7 +858,6 @@ TEST(GlobalLexicalOSR) {
 
 TEST(CrossScriptConflicts) {
   i::FLAG_use_strict = true;
-  i::FLAG_harmony_scoping = true;
 
   HandleScope scope(CcTest::isolate());
 
@@ -880,8 +893,6 @@ TEST(CrossScriptConflicts) {
 
 
 TEST(CrossScriptDynamicLookup) {
-  i::FLAG_harmony_scoping = true;
-
   HandleScope handle_scope(CcTest::isolate());
 
   {
@@ -913,8 +924,6 @@ TEST(CrossScriptDynamicLookup) {
 
 
 TEST(CrossScriptGlobal) {
-  i::FLAG_harmony_scoping = true;
-
   HandleScope handle_scope(CcTest::isolate());
   {
     SimpleContext context;
@@ -957,8 +966,6 @@ TEST(CrossScriptGlobal) {
 
 
 TEST(CrossScriptStaticLookupUndeclared) {
-  i::FLAG_harmony_scoping = true;
-
   HandleScope handle_scope(CcTest::isolate());
 
   {
@@ -991,7 +998,6 @@ TEST(CrossScriptStaticLookupUndeclared) {
 
 
 TEST(CrossScriptLoadICs) {
-  i::FLAG_harmony_scoping = true;
   i::FLAG_allow_natives_syntax = true;
 
   HandleScope handle_scope(CcTest::isolate());
@@ -1047,7 +1053,6 @@ TEST(CrossScriptLoadICs) {
 
 
 TEST(CrossScriptStoreICs) {
-  i::FLAG_harmony_scoping = true;
   i::FLAG_allow_natives_syntax = true;
 
   HandleScope handle_scope(CcTest::isolate());
@@ -1125,7 +1130,6 @@ TEST(CrossScriptStoreICs) {
 
 
 TEST(CrossScriptAssignmentToConst) {
-  i::FLAG_harmony_scoping = true;
   i::FLAG_allow_natives_syntax = true;
 
   HandleScope handle_scope(CcTest::isolate());
@@ -1148,7 +1152,6 @@ TEST(CrossScriptAssignmentToConst) {
 
 
 TEST(Regress425510) {
-  i::FLAG_harmony_scoping = true;
   i::FLAG_allow_natives_syntax = true;
 
   HandleScope handle_scope(CcTest::isolate());
@@ -1163,3 +1166,85 @@ TEST(Regress425510) {
     }
   }
 }
+
+
+TEST(Regress3941) {
+  i::FLAG_allow_natives_syntax = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    context.Check("function f() { x = 1; }", EXPECT_RESULT,
+                  Undefined(CcTest::isolate()));
+    context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION);
+  }
+
+
+  {
+    // Train ICs.
+    SimpleContext context;
+    context.Check("function f() { x = 1; }", EXPECT_RESULT,
+                  Undefined(CcTest::isolate()));
+    for (int i = 0; i < 4; i++) {
+      context.Check("f(); x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+    }
+    context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION);
+  }
+
+
+  {
+    // Optimize.
+    SimpleContext context;
+    context.Check("function f() { x = 1; }", EXPECT_RESULT,
+                  Undefined(CcTest::isolate()));
+    for (int i = 0; i < 4; i++) {
+      context.Check("f(); x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(f); f(); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 1));
+
+    context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION);
+  }
+}
+
+
+TEST(Regress3941_Reads) {
+  i::FLAG_allow_natives_syntax = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    context.Check("function f() { return x; }", EXPECT_RESULT,
+                  Undefined(CcTest::isolate()));
+    context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION);
+  }
+
+
+  {
+    // Train ICs.
+    SimpleContext context;
+    context.Check("function f() { return x; }", EXPECT_RESULT,
+                  Undefined(CcTest::isolate()));
+    for (int i = 0; i < 4; i++) {
+      context.Check("f()", EXPECT_EXCEPTION);
+    }
+    context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION);
+  }
+
+
+  {
+    // Optimize.
+    SimpleContext context;
+    context.Check("function f() { return x; }", EXPECT_RESULT,
+                  Undefined(CcTest::isolate()));
+    for (int i = 0; i < 4; i++) {
+      context.Check("f()", EXPECT_EXCEPTION);
+    }
+    context.Check("%OptimizeFunctionOnNextCall(f);", EXPECT_RESULT,
+                  Undefined(CcTest::isolate()));
+
+    context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION);
+  }
+}
index 095c636..502b641 100644 (file)
@@ -34,7 +34,6 @@
 #include "src/disasm.h"
 #include "src/disassembler.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
index a2eaa15..ca4a4f2 100644 (file)
@@ -34,7 +34,6 @@
 #include "src/disassembler.h"
 #include "src/ic/ic.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
@@ -442,6 +441,10 @@ TEST(DisasmIa320) {
     __ subsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ divsd(xmm1, xmm0);
     __ divsd(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ minsd(xmm1, xmm0);
+    __ minsd(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ maxsd(xmm1, xmm0);
+    __ maxsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ ucomisd(xmm0, xmm1);
     __ cmpltsd(xmm0, xmm1);
 
@@ -451,6 +454,11 @@ TEST(DisasmIa320) {
     __ psrlq(xmm0, 17);
     __ psrlq(xmm0, xmm1);
     __ por(xmm0, xmm1);
+
+    __ pcmpeqd(xmm1, xmm0);
+
+    __ punpckldq(xmm1, xmm6);
+    __ punpckhdq(xmm7, xmm5);
   }
 
   // cmov.
@@ -494,6 +502,10 @@ TEST(DisasmIa320) {
       __ vsubsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
       __ vdivsd(xmm0, xmm1, xmm2);
       __ vdivsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vminsd(xmm0, xmm1, xmm2);
+      __ vminsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vmaxsd(xmm0, xmm1, xmm2);
+      __ vmaxsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
     }
   }
 
index 131f413..ca928a6 100644 (file)
@@ -34,7 +34,6 @@
 #include "src/disasm.h"
 #include "src/disassembler.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
index d682d33..a2a93c6 100644 (file)
@@ -34,7 +34,6 @@
 #include "src/disasm.h"
 #include "src/disassembler.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
index 87b9ade..ed409f2 100644 (file)
@@ -34,7 +34,6 @@
 #include "src/disasm.h"
 #include "src/disassembler.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
index 6cd58ec..cdedc8b 100644 (file)
@@ -34,7 +34,6 @@
 #include "src/disassembler.h"
 #include "src/ic/ic.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
@@ -89,6 +88,9 @@ TEST(DisasmX64) {
   __ addq(rdi, Operand(rbp, rcx, times_4, -3999));
   __ addq(Operand(rbp, rcx, times_4, 12), Immediate(12));
 
+  __ bsrl(rax, r15);
+  __ bsrl(r9, Operand(rcx, times_8, 91919));
+
   __ nop();
   __ addq(rbx, Immediate(12));
   __ nop();
@@ -436,6 +438,10 @@ TEST(DisasmX64) {
     __ subsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ divsd(xmm1, xmm0);
     __ divsd(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ minsd(xmm1, xmm0);
+    __ minsd(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ maxsd(xmm1, xmm0);
+    __ maxsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ ucomisd(xmm0, xmm1);
 
     __ andpd(xmm0, xmm1);
@@ -446,6 +452,9 @@ TEST(DisasmX64) {
     __ psrlq(xmm0, 6);
 
     __ pcmpeqd(xmm1, xmm0);
+
+    __ punpckldq(xmm1, xmm11);
+    __ punpckhdq(xmm8, xmm15);
   }
 
   // cmov.
@@ -472,6 +481,10 @@ TEST(DisasmX64) {
     if (CpuFeatures::IsSupported(SSE4_1)) {
       CpuFeatureScope scope(&assm, SSE4_1);
       __ extractps(rax, xmm1, 0);
+      __ pextrd(rbx, xmm15, 0);
+      __ pextrd(r12, xmm0, 1);
+      __ pinsrd(xmm9, r9, 0);
+      __ pinsrd(xmm5, rax, 1);
     }
   }
 
@@ -486,7 +499,11 @@ TEST(DisasmX64) {
       __ 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));
+      __ vdivsd(xmm0, xmm1, Operand(rbx, rcx, times_2, 10000));
+      __ vminsd(xmm8, xmm1, xmm2);
+      __ vminsd(xmm9, xmm1, Operand(rbx, rcx, times_8, 10000));
+      __ vmaxsd(xmm8, xmm1, xmm2);
+      __ vmaxsd(xmm9, xmm1, Operand(rbx, rcx, times_1, 10000));
     }
   }
 
index e9b0dc5..a3433b2 100644 (file)
@@ -34,7 +34,6 @@
 #include "src/disassembler.h"
 #include "src/ic/ic.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
index 89c475e..f53dfde 100644 (file)
@@ -22,10 +22,11 @@ TEST(VectorStructure) {
   v8::HandleScope scope(context->GetIsolate());
   Isolate* isolate = CcTest::i_isolate();
   Factory* factory = isolate->factory();
+  Zone* zone = isolate->runtime_zone();
 
   // Empty vectors are the empty fixed array.
   FeedbackVectorSpec empty;
-  Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(empty);
+  Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(&empty);
   CHECK(Handle<FixedArray>::cast(vector)
             .is_identical_to(factory->empty_fixed_array()));
   // Which can nonetheless be queried.
@@ -34,24 +35,21 @@ TEST(VectorStructure) {
   CHECK_EQ(0, vector->Slots());
   CHECK_EQ(0, vector->ICSlots());
 
-  FeedbackVectorSpec one_slot(1, 0);
-  vector = factory->NewTypeFeedbackVector(one_slot);
+  FeedbackVectorSpec one_slot(1);
+  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);
+  FeedbackVectorSpec one_icslot(0, Code::CALL_IC);
+  vector = factory->NewTypeFeedbackVector(&one_icslot);
   CHECK_EQ(0, vector->Slots());
   CHECK_EQ(1, vector->ICSlots());
 
-  FeedbackVectorSpec spec(3, 5);
+  ZoneFeedbackVectorSpec spec(zone, 3, 5);
   if (FLAG_vector_ics) {
     for (int i = 0; i < 5; i++) spec.SetKind(i, Code::CALL_IC);
   }
-  vector = factory->NewTypeFeedbackVector(spec);
+  vector = factory->NewTypeFeedbackVector(&spec);
   CHECK_EQ(3, vector->Slots());
   CHECK_EQ(5, vector->ICSlots());
 
@@ -71,8 +69,8 @@ TEST(VectorStructure) {
   CHECK_EQ(index,
            TypeFeedbackVector::kReservedIndexCount + metadata_length + 3);
   CHECK(FeedbackVectorICSlot(0) == vector->ToICSlot(index));
-
-  CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 + 5,
+  CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 +
+               5 * TypeFeedbackVector::elements_per_ic_slot(),
            vector->length());
 }
 
@@ -88,8 +86,9 @@ TEST(VectorICMetadata) {
   }
   Isolate* isolate = CcTest::i_isolate();
   Factory* factory = isolate->factory();
+  Zone* zone = isolate->runtime_zone();
 
-  FeedbackVectorSpec spec(10, 3 * 10);
+  ZoneFeedbackVectorSpec spec(zone, 10, 3 * 10);
   // Set metadata.
   for (int i = 0; i < 30; i++) {
     Code::Kind kind;
@@ -103,7 +102,7 @@ TEST(VectorICMetadata) {
     spec.SetKind(i, kind);
   }
 
-  Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec);
+  Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(&spec);
   CHECK_EQ(10, vector->Slots());
   CHECK_EQ(3 * 10, vector->ICSlots());
 
@@ -136,8 +135,8 @@ TEST(VectorSlotClearing) {
   // 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);
+  FeedbackVectorSpec spec(5);
+  Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(&spec);
 
   // Fill with information
   vector->Set(FeedbackVectorSlot(0), Smi::FromInt(1));
@@ -307,6 +306,34 @@ TEST(VectorLoadICStates) {
 }
 
 
+TEST(VectorLoadICSlotSharing) {
+  if (i::FLAG_always_opt || !i::FLAG_vector_ics) return;
+  CcTest::InitializeVM();
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+
+  // Function f has 3 LoadICs, one for each o, but the ICs share the same
+  // feedback vector IC slot.
+  CompileRun(
+      "var o = 10;"
+      "function f() {"
+      "  var x = o + 10;"
+      "  return o + x + o;"
+      "}"
+      "f();");
+  Handle<JSFunction> f = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+  // There should be one IC slot.
+  Handle<TypeFeedbackVector> feedback_vector =
+      Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
+  CHECK_EQ(1, feedback_vector->ICSlots());
+  FeedbackVectorICSlot slot(0);
+  LoadICNexus nexus(feedback_vector, slot);
+  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
+}
+
+
 TEST(VectorLoadICOnSmi) {
   if (i::FLAG_always_opt || !i::FLAG_vector_ics) return;
   CcTest::InitializeVM();
index 24f9c73..ae8e77d 100644 (file)
@@ -81,11 +81,9 @@ static void CheckFunctionName(v8::Handle<v8::Script> script,
 
   // Obtain SharedFunctionInfo for the function.
   isolate->debug()->PrepareForBreakPoints();
-  Object* shared_func_info_ptr =
-      isolate->debug()->FindSharedFunctionInfoInScript(i_script, func_pos);
-  CHECK(shared_func_info_ptr != CcTest::heap()->undefined_value());
-  Handle<SharedFunctionInfo> shared_func_info(
-      SharedFunctionInfo::cast(shared_func_info_ptr));
+  Handle<SharedFunctionInfo> shared_func_info =
+      Handle<SharedFunctionInfo>::cast(
+          isolate->debug()->FindSharedFunctionInfoInScript(i_script, func_pos));
 
   // Verify inferred function name.
   SmartArrayPointer<char> inferred_name =
index 5c9d2e6..d00532f 100644 (file)
@@ -36,7 +36,6 @@
 #include "src/debug.h"
 #include "src/hashmap.h"
 #include "src/heap-profiler.h"
-#include "src/snapshot.h"
 #include "src/utils-inl.h"
 #include "test/cctest/cctest.h"
 
@@ -183,8 +182,7 @@ TEST(HeapSnapshot) {
       "var a2 = new A2();\n"
       "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n"
       "var c2 = new C2(a2);");
-  const v8::HeapSnapshot* snapshot_env2 =
-      heap_profiler->TakeHeapSnapshot(v8_str("env2"));
+  const v8::HeapSnapshot* snapshot_env2 = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot_env2));
   const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);
 
@@ -217,8 +215,7 @@ TEST(HeapSnapshotObjectSizes) {
       "x = new X(new X(), new X());\n"
       "dummy = new X();\n"
       "(function() { x.a.a = x.b; })();");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("sizes"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* x =
@@ -246,8 +243,7 @@ TEST(BoundFunctionInSnapshot) {
       "function myFunction(a, b) { this.a = a; this.b = b; }\n"
       "function AAAAA() {}\n"
       "boundFunction = myFunction.bind(new AAAAA(), 20, new Number(12)); \n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("sizes"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* f =
@@ -286,8 +282,7 @@ TEST(HeapSnapshotEntryChildren) {
   CompileRun(
       "function A() { }\n"
       "a = new A;");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("children"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   for (int i = 0, count = global->GetChildrenCount(); i < count; ++i) {
@@ -314,8 +309,7 @@ TEST(HeapSnapshotCodeObjects) {
       "function compiled(x) { return x + 1; }\n"
       "var anonymous = (function() { return function() { return 0; } })();\n"
       "compiled(1)");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("code"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
 
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
@@ -387,8 +381,7 @@ TEST(HeapSnapshotHeapNumbers) {
   CompileRun(
       "a = 1;    // a is Smi\n"
       "b = 2.5;  // b is HeapNumber");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("numbers"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   CHECK(!GetProperty(global, v8::HeapGraphEdge::kProperty, "a"));
@@ -413,8 +406,7 @@ TEST(HeapSnapshotSlicedString) {
       "123456789.123456789.123456789.123456789.123456789."
       "123456789.123456789.123456789.123456789.123456789.\";"
       "child_string = parent_string.slice(100);");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("strings"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* parent_string =
@@ -451,8 +443,7 @@ TEST(HeapSnapshotConsString) {
   global->SetInternalField(0, v8::ToApiHandle<v8::String>(cons_string));
 
   v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("cons_strings"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
 
@@ -479,8 +470,7 @@ TEST(HeapSnapshotSymbol) {
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
 
   CompileRun("a = Symbol('mySymbol');\n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("Symbol"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* a =
@@ -504,8 +494,7 @@ TEST(HeapSnapshotWeakCollection) {
       "k = {}; v = {}; s = 'str';\n"
       "ws = new WeakSet(); ws.add(k); ws.add(v); ws[s] = s;\n"
       "wm = new WeakMap(); wm.set(k, v); wm[s] = s;\n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("WeakCollections"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* k =
@@ -578,8 +567,7 @@ TEST(HeapSnapshotCollection) {
       "k = {}; v = {}; s = 'str';\n"
       "set = new Set(); set.add(k); set.add(v); set[s] = s;\n"
       "map = new Map(); map.set(k, v); map[s] = s;\n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("Collections"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* k =
@@ -656,8 +644,7 @@ TEST(HeapSnapshotInternalReferences) {
   global->SetInternalField(0, v8_num(17));
   global->SetInternalField(1, obj);
   v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("internals"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
   // The first reference will not present, because it's a Smi.
@@ -677,8 +664,7 @@ TEST(HeapSnapshotAddressReuse) {
       "var a = [];\n"
       "for (var i = 0; i < 10000; ++i)\n"
       "  a[i] = new A();\n");
-  const v8::HeapSnapshot* snapshot1 =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot1"));
+  const v8::HeapSnapshot* snapshot1 = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot1));
   v8::SnapshotObjectId maxId1 = snapshot1->GetMaxSnapshotJSObjectId();
 
@@ -687,8 +673,7 @@ TEST(HeapSnapshotAddressReuse) {
       "  a[i] = new A();\n");
   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
 
-  const v8::HeapSnapshot* snapshot2 =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot2"));
+  const v8::HeapSnapshot* snapshot2 = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot2));
   const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
 
@@ -721,8 +706,7 @@ TEST(HeapEntryIdsAndArrayShift) {
       "var a = new Array();\n"
       "for (var i = 0; i < 10; ++i)\n"
       "  a.push(new AnObject());\n");
-  const v8::HeapSnapshot* snapshot1 =
-      heap_profiler->TakeHeapSnapshot(v8_str("s1"));
+  const v8::HeapSnapshot* snapshot1 = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot1));
 
   CompileRun(
@@ -731,8 +715,7 @@ TEST(HeapEntryIdsAndArrayShift) {
 
   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
 
-  const v8::HeapSnapshot* snapshot2 =
-      heap_profiler->TakeHeapSnapshot(v8_str("s2"));
+  const v8::HeapSnapshot* snapshot2 = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot2));
 
   const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
@@ -768,16 +751,12 @@ TEST(HeapEntryIdsAndGC) {
       "function B(x) { this.x = x; }\n"
       "var a = new A();\n"
       "var b = new B(a);");
-  v8::Local<v8::String> s1_str = v8_str("s1");
-  v8::Local<v8::String> s2_str = v8_str("s2");
-  const v8::HeapSnapshot* snapshot1 =
-      heap_profiler->TakeHeapSnapshot(s1_str);
+  const v8::HeapSnapshot* snapshot1 = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot1));
 
   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
 
-  const v8::HeapSnapshot* snapshot2 =
-      heap_profiler->TakeHeapSnapshot(s2_str);
+  const v8::HeapSnapshot* snapshot2 = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot2));
 
   CHECK_GT(snapshot1->GetMaxSnapshotJSObjectId(), 7000u);
@@ -827,8 +806,7 @@ TEST(HeapSnapshotRootPreservedAfterSorting) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("s"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* root1 = snapshot->GetRoot();
   const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>(
@@ -896,8 +874,7 @@ TEST(HeapSnapshotJSONSerialization) {
       "function B(x) { this.x = x; }\n"
       "var a = new A(" STRING_LITERAL_FOR_TEST ");\n"
       "var b = new B(a);");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("json"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
 
   TestJSONStream stream;
@@ -996,8 +973,7 @@ TEST(HeapSnapshotJSONSerializationAborting) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("abort"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   TestJSONStream stream(5);
   snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
@@ -1067,9 +1043,12 @@ static TestStatsStream GetHeapStatsUpdate(
     v8::HeapProfiler* heap_profiler,
     v8::SnapshotObjectId* object_id = NULL) {
   TestStatsStream stream;
-  v8::SnapshotObjectId last_seen_id = heap_profiler->GetHeapStats(&stream);
+  int64_t timestamp = -1;
+  v8::SnapshotObjectId last_seen_id =
+      heap_profiler->GetHeapStats(&stream, &timestamp);
   if (object_id)
     *object_id = last_seen_id;
+  CHECK_NE(-1, timestamp);
   CHECK_EQ(1, stream.eos_signaled());
   return stream;
 }
@@ -1279,8 +1258,7 @@ TEST(HeapSnapshotGetNodeById) {
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
 
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("id"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* root = snapshot->GetRoot();
   CheckChildrenIds(snapshot, root, 0, 3);
@@ -1294,8 +1272,7 @@ TEST(HeapSnapshotGetSnapshotObjectId) {
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
   CompileRun("globalObject = {};\n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("get_snapshot_object_id"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* global_object =
@@ -1318,8 +1295,7 @@ TEST(HeapSnapshotUnknownSnapshotObjectId) {
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
   CompileRun("globalObject = {};\n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("unknown_object_id"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* node =
       snapshot->GetNodeById(v8::HeapProfiler::kUnknownObjectId);
@@ -1357,16 +1333,13 @@ TEST(TakeHeapSnapshotAborting) {
   const int snapshots_count = heap_profiler->GetSnapshotCount();
   TestActivityControl aborting_control(1);
   const v8::HeapSnapshot* no_snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("abort"),
-                                     &aborting_control);
+      heap_profiler->TakeHeapSnapshot(&aborting_control);
   CHECK(!no_snapshot);
   CHECK_EQ(snapshots_count, heap_profiler->GetSnapshotCount());
   CHECK_GT(aborting_control.total(), aborting_control.done());
 
   TestActivityControl control(-1);  // Don't abort.
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("full"),
-                                     &control);
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(&control);
   CHECK(ValidateSnapshot(snapshot));
 
   CHECK(snapshot);
@@ -1477,8 +1450,7 @@ TEST(HeapSnapshotRetainedObjectInfo) {
   v8::Persistent<v8::String> p_CCC(isolate, v8_str("CCC"));
   p_CCC.SetWrapperClassId(2);
   CHECK_EQ(0, TestRetainedObjectInfo::instances.length());
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("retained"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
 
   CHECK_EQ(3, TestRetainedObjectInfo::instances.length());
@@ -1570,8 +1542,7 @@ TEST(HeapSnapshotImplicitReferences) {
   GraphWithImplicitRefs graph(&env);
   v8::V8::AddGCPrologueCallback(&GraphWithImplicitRefs::gcPrologue);
 
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("implicit_refs"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
 
   const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot);
@@ -1604,28 +1575,25 @@ TEST(DeleteAllHeapSnapshots) {
   CHECK_EQ(0, heap_profiler->GetSnapshotCount());
   heap_profiler->DeleteAllHeapSnapshots();
   CHECK_EQ(0, heap_profiler->GetSnapshotCount());
-  CHECK(heap_profiler->TakeHeapSnapshot(v8_str("1")));
+  CHECK(heap_profiler->TakeHeapSnapshot());
   CHECK_EQ(1, heap_profiler->GetSnapshotCount());
   heap_profiler->DeleteAllHeapSnapshots();
   CHECK_EQ(0, heap_profiler->GetSnapshotCount());
-  CHECK(heap_profiler->TakeHeapSnapshot(v8_str("1")));
-  CHECK(heap_profiler->TakeHeapSnapshot(v8_str("2")));
+  CHECK(heap_profiler->TakeHeapSnapshot());
+  CHECK(heap_profiler->TakeHeapSnapshot());
   CHECK_EQ(2, heap_profiler->GetSnapshotCount());
   heap_profiler->DeleteAllHeapSnapshots();
   CHECK_EQ(0, heap_profiler->GetSnapshotCount());
 }
 
 
-static const v8::HeapSnapshot* FindHeapSnapshot(v8::HeapProfiler* profiler,
-                                                unsigned uid) {
+static bool FindHeapSnapshot(v8::HeapProfiler* profiler,
+                             const v8::HeapSnapshot* snapshot) {
   int length = profiler->GetSnapshotCount();
   for (int i = 0; i < length; i++) {
-    const v8::HeapSnapshot* snapshot = profiler->GetHeapSnapshot(i);
-    if (snapshot->GetUid() == uid) {
-      return snapshot;
-    }
+    if (snapshot == profiler->GetHeapSnapshot(i)) return true;
   }
-  return NULL;
+  return false;
 }
 
 
@@ -1635,38 +1603,31 @@ TEST(DeleteHeapSnapshot) {
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
 
   CHECK_EQ(0, heap_profiler->GetSnapshotCount());
-  const v8::HeapSnapshot* s1 =
-      heap_profiler->TakeHeapSnapshot(v8_str("1"));
+  const v8::HeapSnapshot* s1 = heap_profiler->TakeHeapSnapshot();
 
   CHECK(s1);
   CHECK_EQ(1, heap_profiler->GetSnapshotCount());
-  unsigned uid1 = s1->GetUid();
-  CHECK_EQ(s1, FindHeapSnapshot(heap_profiler, uid1));
+  CHECK(FindHeapSnapshot(heap_profiler, s1));
   const_cast<v8::HeapSnapshot*>(s1)->Delete();
   CHECK_EQ(0, heap_profiler->GetSnapshotCount());
-  CHECK(!FindHeapSnapshot(heap_profiler, uid1));
+  CHECK(!FindHeapSnapshot(heap_profiler, s1));
 
-  const v8::HeapSnapshot* s2 =
-      heap_profiler->TakeHeapSnapshot(v8_str("2"));
+  const v8::HeapSnapshot* s2 = heap_profiler->TakeHeapSnapshot();
   CHECK(s2);
   CHECK_EQ(1, heap_profiler->GetSnapshotCount());
-  unsigned uid2 = s2->GetUid();
-  CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
-  CHECK_EQ(s2, FindHeapSnapshot(heap_profiler, uid2));
-  const v8::HeapSnapshot* s3 =
-      heap_profiler->TakeHeapSnapshot(v8_str("3"));
+  CHECK(FindHeapSnapshot(heap_profiler, s2));
+  const v8::HeapSnapshot* s3 = heap_profiler->TakeHeapSnapshot();
   CHECK(s3);
   CHECK_EQ(2, heap_profiler->GetSnapshotCount());
-  unsigned uid3 = s3->GetUid();
-  CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
-  CHECK_EQ(s3, FindHeapSnapshot(heap_profiler, uid3));
+  CHECK_NE(s2, s3);
+  CHECK(FindHeapSnapshot(heap_profiler, s3));
   const_cast<v8::HeapSnapshot*>(s2)->Delete();
   CHECK_EQ(1, heap_profiler->GetSnapshotCount());
-  CHECK(!FindHeapSnapshot(heap_profiler, uid2));
-  CHECK_EQ(s3, FindHeapSnapshot(heap_profiler, uid3));
+  CHECK(!FindHeapSnapshot(heap_profiler, s2));
+  CHECK(FindHeapSnapshot(heap_profiler, s3));
   const_cast<v8::HeapSnapshot*>(s3)->Delete();
   CHECK_EQ(0, heap_profiler->GetSnapshotCount());
-  CHECK(!FindHeapSnapshot(heap_profiler, uid3));
+  CHECK(!FindHeapSnapshot(heap_profiler, s3));
 }
 
 
@@ -1687,9 +1648,7 @@ TEST(GlobalObjectName) {
 
   NameResolver name_resolver;
   const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("document"),
-      NULL,
-      &name_resolver);
+      heap_profiler->TakeHeapSnapshot(NULL, &name_resolver);
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   CHECK(global);
@@ -1705,8 +1664,7 @@ TEST(GlobalObjectFields) {
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
   CompileRun("obj = {};");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* builtins =
@@ -1728,10 +1686,9 @@ TEST(NoHandleLeaks) {
 
   CompileRun("document = { URL:\"abcdefgh\" };");
 
-  v8::Handle<v8::String> name(v8_str("leakz"));
   i::Isolate* isolate = CcTest::i_isolate();
   int count_before = i::HandleScope::NumberOfHandles(isolate);
-  heap_profiler->TakeHeapSnapshot(name);
+  heap_profiler->TakeHeapSnapshot();
   int count_after = i::HandleScope::NumberOfHandles(isolate);
   CHECK_EQ(count_before, count_after);
 }
@@ -1741,8 +1698,7 @@ TEST(NodesIteration) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("iteration"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   CHECK(global);
@@ -1763,8 +1719,7 @@ TEST(GetHeapValueForNode) {
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
 
   CompileRun("a = { s_prop: \'value\', n_prop: \'value2\' };");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("value"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   CHECK(heap_profiler->FindObjectById(global->GetId())->IsObject());
@@ -1798,8 +1753,7 @@ TEST(GetHeapValueForDeletedObject) {
   // property of the "a" object. Also, the "p" object can't be an empty one
   // because the empty object is static and isn't actually deleted.
   CompileRun("a = { p: { r: {} } };");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* obj = GetProperty(
@@ -1889,8 +1843,7 @@ TEST(FastCaseAccessors) {
              "obj1.__defineSetter__('propWithSetter', function Z(value) {\n"
              "  return this.value_ = value;\n"
              "});\n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("fastCaseAccessors"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
 
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
@@ -1935,8 +1888,7 @@ TEST(FastCaseRedefinedAccessors) {
       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"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   CHECK(global);
@@ -1964,8 +1916,7 @@ TEST(SlowCaseAccessors) {
              "obj1.__defineSetter__('propWithSetter', function Z(value) {\n"
              "  return this.value_ = value;\n"
              "});\n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("slowCaseAccessors"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
 
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
@@ -1994,8 +1945,7 @@ TEST(HiddenPropertiesFastCase) {
   CompileRun(
       "function C(x) { this.a = this; this.b = x; }\n"
       "c = new C(2012);\n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("HiddenPropertiesFastCase1"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* c =
@@ -2010,8 +1960,7 @@ TEST(HiddenPropertiesFastCase) {
   CHECK(!cHandle.IsEmpty() && cHandle->IsObject());
   cHandle->ToObject(isolate)->SetHiddenValue(v8_str("key"), v8_str("val"));
 
-  snapshot = heap_profiler->TakeHeapSnapshot(
-      v8_str("HiddenPropertiesFastCase2"));
+  snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   global = GetGlobalObject(snapshot);
   c = GetProperty(global, v8::HeapGraphEdge::kProperty, "c");
@@ -2028,8 +1977,7 @@ TEST(AccessorInfo) {
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
 
   CompileRun("function foo(x) { }\n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("AccessorInfoTest"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* foo =
@@ -2074,8 +2022,7 @@ bool HasWeakEdge(const v8::HeapGraphNode* node) {
 bool HasWeakGlobalHandle() {
   v8::Isolate* isolate = CcTest::isolate();
   v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("weaks"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* gc_roots = GetNode(
       snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "(GC roots)");
@@ -2115,8 +2062,7 @@ TEST(SfiAndJsFunctionWeakRefs) {
 
   CompileRun(
       "fun = (function (x) { return function () { return x + 1; } })(1);");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("fun"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   CHECK(global);
@@ -2136,8 +2082,7 @@ TEST(NoDebugObjectInSnapshot) {
 
   CHECK(CcTest::i_isolate()->debug()->Load());
   CompileRun("foo = {};");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* root = snapshot->GetRoot();
   int globals_count = 0;
@@ -2161,8 +2106,7 @@ TEST(AllStrongGcRootsHaveNames) {
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
 
   CompileRun("foo = {};");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* gc_roots = GetNode(
       snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "(GC roots)");
@@ -2184,8 +2128,7 @@ TEST(NoRefsToNonEssentialEntries) {
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
   CompileRun("global_object = {};\n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* global_object =
@@ -2205,8 +2148,7 @@ TEST(MapHasDescriptorsAndTransitions) {
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
   CompileRun("obj = { a: 10 };\n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* global_object =
@@ -2244,8 +2186,7 @@ TEST(ManyLocalsInSharedContext) {
       "result.push('return f_' + (n - 1) + ';');"
       "result.push('})()');"
       "var ok = eval(result.join('\\n'));");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
 
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
@@ -2279,8 +2220,7 @@ TEST(AllocationSitesAreVisible) {
   CompileRun(
       "fun = function () { var a = [3, 2, 1]; return a; }\n"
       "fun();");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
 
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
@@ -2292,11 +2232,11 @@ TEST(AllocationSitesAreVisible) {
       GetProperty(fun_code, v8::HeapGraphEdge::kInternal, "literals");
   CHECK(literals);
   CHECK_EQ(v8::HeapGraphNode::kArray, literals->GetType());
-  CHECK_EQ(2, literals->GetChildrenCount());
+  CHECK_EQ(1, literals->GetChildrenCount());
 
-  // The second value in the literals array should be the boilerplate,
+  // The first value in the literals array should be the boilerplate,
   // after an AllocationSite.
-  const v8::HeapGraphEdge* prop = literals->GetChild(1);
+  const v8::HeapGraphEdge* prop = literals->GetChild(0);
   const v8::HeapGraphNode* allocation_site = prop->GetToNode();
   v8::String::Utf8Value name(allocation_site->GetName());
   CHECK_EQ(0, strcmp("system / AllocationSite", *name));
@@ -2333,8 +2273,7 @@ TEST(JSFunctionHasCodeLink) {
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
   CompileRun("function foo(x, y) { return x + y; }\n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* foo_func =
@@ -2375,8 +2314,7 @@ TEST(CheckCodeNames) {
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
   CompileRun("var a = 1.1;");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("CheckCodeNames"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
 
   const char* stub_path[] = {
@@ -2634,8 +2572,7 @@ TEST(ArrayBufferAndArrayBufferView) {
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
   CompileRun("arr1 = new Uint32Array(100);\n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* arr1_obj =
@@ -2693,8 +2630,7 @@ TEST(ArrayBufferSharedBackingStore) {
   v8::Handle<v8::Value> result = CompileRun("ab2.byteLength");
   CHECK_EQ(1024, result->Int32Value());
 
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* ab1_node =
@@ -2728,8 +2664,7 @@ TEST(BoxObject) {
   global->Set(0, v8::ToApiHandle<v8::Object>(box));
 
   v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* box_node =
@@ -2756,8 +2691,7 @@ TEST(WeakContainers) {
       "foo(obj);\n"
       "%OptimizeFunctionOnNextCall(foo);\n"
       "foo(obj);\n");
-  const v8::HeapSnapshot* snapshot =
-      heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
+  const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
   CHECK(ValidateSnapshot(snapshot));
   const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
   const v8::HeapGraphNode* obj =
index ae3c1d3..9867f93 100644 (file)
 #include "src/global-handles.h"
 #include "src/ic/ic.h"
 #include "src/macro-assembler.h"
-#include "src/snapshot.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
+using v8::Just;
 
 static void CheckMap(Map* map, int type, int instance_size) {
   CHECK(map->IsHeapObject());
@@ -191,9 +191,7 @@ TEST(HeapObjects) {
 
   Handle<String> object_string = Handle<String>::cast(factory->Object_string());
   Handle<GlobalObject> global(CcTest::i_isolate()->context()->global_object());
-  v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(global, object_string);
-  CHECK(maybe.has_value);
-  CHECK(maybe.value);
+  CHECK(Just(true) == JSReceiver::HasOwnProperty(global, object_string));
 
   // Check ToString for oddballs
   CheckOddball(isolate, heap->true_value(), "true");
@@ -260,9 +258,7 @@ TEST(GarbageCollection) {
   heap->CollectGarbage(NEW_SPACE);
 
   // Function should be alive.
-  v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(global, name);
-  CHECK(maybe.has_value);
-  CHECK(maybe.value);
+  CHECK(Just(true) == JSReceiver::HasOwnProperty(global, name));
   // Check function is retained.
   Handle<Object> func_value =
       Object::GetProperty(global, name).ToHandleChecked();
@@ -280,9 +276,7 @@ TEST(GarbageCollection) {
   // After gc, it should survive.
   heap->CollectGarbage(NEW_SPACE);
 
-  maybe = JSReceiver::HasOwnProperty(global, obj_name);
-  CHECK(maybe.has_value);
-  CHECK(maybe.value);
+  CHECK(Just(true) == JSReceiver::HasOwnProperty(global, obj_name));
   Handle<Object> obj =
       Object::GetProperty(global, obj_name).ToHandleChecked();
   CHECK(obj->IsJSObject());
@@ -639,85 +633,55 @@ TEST(ObjectProperties) {
   Handle<Smi> two(Smi::FromInt(2), isolate);
 
   // check for empty
-  v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(obj, first);
-  CHECK(maybe.has_value);
-  CHECK(!maybe.value);
+  CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, first));
 
   // add first
   JSReceiver::SetProperty(obj, first, one, SLOPPY).Check();
-  maybe = JSReceiver::HasOwnProperty(obj, first);
-  CHECK(maybe.has_value);
-  CHECK(maybe.value);
+  CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, first));
 
   // delete first
   JSReceiver::DeleteProperty(obj, first, SLOPPY).Check();
-  maybe = JSReceiver::HasOwnProperty(obj, first);
-  CHECK(maybe.has_value);
-  CHECK(!maybe.value);
+  CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, first));
 
   // add first and then second
   JSReceiver::SetProperty(obj, first, one, SLOPPY).Check();
   JSReceiver::SetProperty(obj, second, two, SLOPPY).Check();
-  maybe = JSReceiver::HasOwnProperty(obj, first);
-  CHECK(maybe.has_value);
-  CHECK(maybe.value);
-  maybe = JSReceiver::HasOwnProperty(obj, second);
-  CHECK(maybe.has_value);
-  CHECK(maybe.value);
+  CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, first));
+  CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, second));
 
   // delete first and then second
   JSReceiver::DeleteProperty(obj, first, SLOPPY).Check();
-  maybe = JSReceiver::HasOwnProperty(obj, second);
-  CHECK(maybe.has_value);
-  CHECK(maybe.value);
+  CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, second));
   JSReceiver::DeleteProperty(obj, second, SLOPPY).Check();
-  maybe = JSReceiver::HasOwnProperty(obj, first);
-  CHECK(maybe.has_value);
-  CHECK(!maybe.value);
-  maybe = JSReceiver::HasOwnProperty(obj, second);
-  CHECK(maybe.has_value);
-  CHECK(!maybe.value);
+  CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, first));
+  CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, second));
 
   // add first and then second
   JSReceiver::SetProperty(obj, first, one, SLOPPY).Check();
   JSReceiver::SetProperty(obj, second, two, SLOPPY).Check();
-  maybe = JSReceiver::HasOwnProperty(obj, first);
-  CHECK(maybe.has_value);
-  CHECK(maybe.value);
-  maybe = JSReceiver::HasOwnProperty(obj, second);
-  CHECK(maybe.has_value);
-  CHECK(maybe.value);
+  CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, first));
+  CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, second));
 
   // delete second and then first
   JSReceiver::DeleteProperty(obj, second, SLOPPY).Check();
-  maybe = JSReceiver::HasOwnProperty(obj, first);
-  CHECK(maybe.has_value);
-  CHECK(maybe.value);
+  CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, first));
   JSReceiver::DeleteProperty(obj, first, SLOPPY).Check();
-  maybe = JSReceiver::HasOwnProperty(obj, first);
-  CHECK(maybe.has_value);
-  CHECK(!maybe.value);
-  maybe = JSReceiver::HasOwnProperty(obj, second);
-  CHECK(maybe.has_value);
-  CHECK(!maybe.value);
+  CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, first));
+  CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, second));
 
   // check string and internalized string match
   const char* string1 = "fisk";
   Handle<String> s1 = factory->NewStringFromAsciiChecked(string1);
   JSReceiver::SetProperty(obj, s1, one, SLOPPY).Check();
   Handle<String> s1_string = factory->InternalizeUtf8String(string1);
-  maybe = JSReceiver::HasOwnProperty(obj, s1_string);
-  CHECK(maybe.has_value);
-  CHECK(maybe.value);
+  CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, s1_string));
 
   // check internalized string and string match
   const char* string2 = "fugl";
   Handle<String> s2_string = factory->InternalizeUtf8String(string2);
   JSReceiver::SetProperty(obj, s2_string, one, SLOPPY).Check();
   Handle<String> s2 = factory->NewStringFromAsciiChecked(string2);
-  maybe = JSReceiver::HasOwnProperty(obj, s2);
-  CHECK(maybe.has_value);
-  CHECK(maybe.value);
+  CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, s2));
 }
 
 
@@ -1502,6 +1466,7 @@ TEST(TestInternalWeakLists) {
   // Some flags turn Scavenge collections into Mark-sweep collections
   // and hence are incompatible with this test case.
   if (FLAG_gc_global || FLAG_stress_compaction) return;
+  FLAG_retain_maps_for_n_gc = 0;
 
   static const int kNumTestContexts = 10;
 
@@ -2176,6 +2141,12 @@ TEST(InstanceOfStubWriteBarrier) {
 }
 
 
+static int NumberOfProtoTransitions(Map* map) {
+  return TransitionArray::NumberOfPrototypeTransitions(
+      TransitionArray::GetPrototypeTransitions(map));
+}
+
+
 TEST(PrototypeTransitionClearing) {
   if (FLAG_never_compact) return;
   CcTest::InitializeVM();
@@ -2188,7 +2159,7 @@ TEST(PrototypeTransitionClearing) {
       v8::Utils::OpenHandle(
           *v8::Handle<v8::Object>::Cast(
               CcTest::global()->Get(v8_str("base"))));
-  int initialTransitions = baseObject->map()->NumberOfProtoTransitions();
+  int initialTransitions = NumberOfProtoTransitions(baseObject->map());
 
   CompileRun(
       "var live = [];"
@@ -2201,16 +2172,17 @@ TEST(PrototypeTransitionClearing) {
 
   // Verify that only dead prototype transitions are cleared.
   CHECK_EQ(initialTransitions + 10,
-      baseObject->map()->NumberOfProtoTransitions());
+           NumberOfProtoTransitions(baseObject->map()));
   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   const int transitions = 10 - 3;
   CHECK_EQ(initialTransitions + transitions,
-      baseObject->map()->NumberOfProtoTransitions());
+           NumberOfProtoTransitions(baseObject->map()));
 
   // Verify that prototype transitions array was compacted.
-  FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
+  FixedArray* trans =
+      TransitionArray::GetPrototypeTransitions(baseObject->map());
   for (int i = initialTransitions; i < initialTransitions + transitions; i++) {
-    int j = Map::kProtoTransitionHeaderSize + i;
+    int j = TransitionArray::kProtoTransitionHeaderSize + i;
     CHECK(trans->get(j)->IsMap());
   }
 
@@ -2228,7 +2200,7 @@ TEST(PrototypeTransitionClearing) {
   i::FLAG_always_compact = true;
   Handle<Map> map(baseObject->map());
   CHECK(!space->LastPage()->Contains(
-      map->GetPrototypeTransitions()->address()));
+      TransitionArray::GetPrototypeTransitions(*map)->address()));
   CHECK(space->LastPage()->Contains(prototype->address()));
 }
 
@@ -2267,9 +2239,12 @@ TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
   marking->Start();
 
   // The following two calls will increment CcTest::heap()->global_ic_age().
-  const int kLongIdlePauseInMs = 1000;
+  const double kLongIdlePauseInSeconds = 1.0;
   CcTest::isolate()->ContextDisposedNotification();
-  CcTest::isolate()->IdleNotification(kLongIdlePauseInMs);
+  CcTest::isolate()->IdleNotificationDeadline(
+      (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
+       static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
+      kLongIdlePauseInSeconds);
 
   while (!marking->IsStopped() && !marking->IsComplete()) {
     marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
@@ -2323,9 +2298,12 @@ TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
 
   // The following two calls will increment CcTest::heap()->global_ic_age().
   // Since incremental marking is off, IdleNotification will do full GC.
-  const int kLongIdlePauseInMs = 1000;
+  const double kLongIdlePauseInSeconds = 1.0;
   CcTest::isolate()->ContextDisposedNotification();
-  CcTest::isolate()->IdleNotification(kLongIdlePauseInMs);
+  CcTest::isolate()->IdleNotificationDeadline(
+      (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
+       static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
+      kLongIdlePauseInSeconds);
 
   CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age());
   CHECK_EQ(0, f->shared()->opt_count());
@@ -2368,9 +2346,14 @@ TEST(IdleNotificationFinishMarking) {
     CHECK(!marking->IsIdleMarkingDelayCounterLimitReached());
   }
 
+  marking->SetWeakClosureWasOverApproximatedForTesting(true);
+
   // The next idle notification has to finish incremental marking.
-  const int kLongIdleTime = 1000000;
-  CcTest::isolate()->IdleNotification(kLongIdleTime);
+  const double kLongIdleTime = 1000.0;
+  CcTest::isolate()->IdleNotificationDeadline(
+      (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
+       static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
+      kLongIdleTime);
   CHECK_EQ(CcTest::heap()->gc_count(), 1);
 }
 
@@ -2550,8 +2533,8 @@ TEST(OptimizedPretenuringMixedInObjectProperties) {
   } else {
     CHECK_EQ(2.2, inner_object->RawFastDoublePropertyAt(idx1));
   }
-  CHECK(CcTest::heap()->InOldPointerSpace(
-      inner_object->RawFastPropertyAt(idx2)));
+  CHECK(
+      CcTest::heap()->InOldPointerSpace(inner_object->RawFastPropertyAt(idx2)));
 }
 
 
@@ -2911,7 +2894,7 @@ TEST(OptimizedAllocationArrayLiterals) {
 
 
 static int CountMapTransitions(Map* map) {
-  return map->transitions()->number_of_transitions();
+  return TransitionArray::NumberOfTransitions(map->raw_transitions());
 }
 
 
@@ -2921,6 +2904,7 @@ TEST(Regress1465) {
   i::FLAG_stress_compaction = false;
   i::FLAG_allow_natives_syntax = true;
   i::FLAG_trace_incremental_marking = true;
+  i::FLAG_retain_maps_for_n_gc = 0;
   CcTest::InitializeVM();
   v8::HandleScope scope(CcTest::isolate());
   static const int transitions_count = 256;
@@ -2983,6 +2967,7 @@ static void AddPropertyTo(
   Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
   i::FLAG_gc_interval = gc_count;
   i::FLAG_gc_global = true;
+  i::FLAG_retain_maps_for_n_gc = 0;
   CcTest::heap()->set_allocation_timeout(gc_count);
   JSReceiver::SetProperty(object, prop_name, twenty_three, SLOPPY).Check();
 }
@@ -3090,7 +3075,7 @@ TEST(TransitionArraySimpleToFull) {
   CompileRun("o = new F;"
              "root = new F");
   root = GetByName("root");
-  DCHECK(root->map()->transitions()->IsSimpleTransition());
+  DCHECK(TransitionArray::IsSimpleTransition(root->map()->raw_transitions()));
   AddPropertyTo(2, root, "happy");
 
   // Count number of live transitions after marking.  Note that one transition
@@ -4090,7 +4075,8 @@ TEST(IncrementalMarkingStepMakesBigProgressWithLargeObjects) {
   if (marking->IsStopped()) marking->Start();
   // This big step should be sufficient to mark the whole array.
   marking->Step(100 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
-  DCHECK(marking->IsComplete());
+  DCHECK(marking->IsComplete() ||
+         marking->IsReadyToOverApproximateWeakClosure());
 }
 
 
@@ -4181,7 +4167,7 @@ TEST(EnsureAllocationSiteDependentCodesProcessed) {
   // Now make sure that a gc should get rid of the function, even though we
   // still have the allocation site alive.
   for (int i = 0; i < 4; i++) {
-    heap->CollectAllGarbage(Heap::kNoGCFlags);
+    heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   }
 
   // The site still exists because of our global handle, but the code is no
@@ -4283,6 +4269,7 @@ TEST(NoWeakHashTableLeakWithIncrementalMarking) {
   i::FLAG_weak_embedded_objects_in_optimized_code = true;
   i::FLAG_allow_natives_syntax = true;
   i::FLAG_compilation_cache = false;
+  i::FLAG_retain_maps_for_n_gc = 0;
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   v8::internal::Heap* heap = CcTest::heap();
@@ -4608,17 +4595,33 @@ Handle<JSFunction> GetFunctionByName(Isolate* isolate, const char* name) {
 }
 
 
-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);
+void CheckIC(Code* code, Code::Kind kind, SharedFunctionInfo* shared,
+             int ic_slot, InlineCacheState state) {
+  if (FLAG_vector_ics &&
+      (kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC ||
+       kind == Code::CALL_IC)) {
+    TypeFeedbackVector* vector = shared->feedback_vector();
+    FeedbackVectorICSlot slot(ic_slot);
+    if (kind == Code::LOAD_IC) {
+      LoadICNexus nexus(vector, slot);
+      CHECK_EQ(nexus.StateFromFeedback(), state);
+    } else if (kind == Code::KEYED_LOAD_IC) {
+      KeyedLoadICNexus nexus(vector, slot);
+      CHECK_EQ(nexus.StateFromFeedback(), state);
+    } else if (kind == Code::CALL_IC) {
+      CallICNexus nexus(vector, slot);
+      CHECK_EQ(nexus.StateFromFeedback(), state);
+    }
+  } else {
+    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();
@@ -4641,19 +4644,17 @@ TEST(MonomorphicStaysMonomorphicAfterGC) {
     CompileRun("(testIC())");
   }
   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
-  CheckIC(loadIC->code(), Code::LOAD_IC, MONOMORPHIC);
+  CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 0, MONOMORPHIC);
   {
     v8::HandleScope scope(CcTest::isolate());
     CompileRun("(testIC())");
   }
-  CheckIC(loadIC->code(), Code::LOAD_IC, MONOMORPHIC);
+  CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 0, 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();
@@ -4679,12 +4680,12 @@ TEST(PolymorphicStaysPolymorphicAfterGC) {
     CompileRun("(testIC())");
   }
   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
-  CheckIC(loadIC->code(), Code::LOAD_IC, POLYMORPHIC);
+  CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 0, POLYMORPHIC);
   {
     v8::HandleScope scope(CcTest::isolate());
     CompileRun("(testIC())");
   }
-  CheckIC(loadIC->code(), Code::LOAD_IC, POLYMORPHIC);
+  CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 0, POLYMORPHIC);
 }
 
 
@@ -4878,7 +4879,7 @@ TEST(ArrayShiftSweeping) {
 
 UNINITIALIZED_TEST(PromotionQueue) {
   i::FLAG_expose_gc = true;
-  i::FLAG_max_semi_space_size = 2;
+  i::FLAG_max_semi_space_size = 2 * (Page::kPageSize / MB);
   v8::Isolate* isolate = v8::Isolate::New();
   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   {
@@ -5073,16 +5074,109 @@ TEST(Regress442710) {
 
 
 TEST(NumberStringCacheSize) {
-  if (!Snapshot::HaveASnapshotToStartFrom()) return;
   // Test that the number-string cache has not been resized in the snapshot.
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
+  if (!isolate->snapshot_available()) return;
   Heap* heap = isolate->heap();
   CHECK_EQ(TestHeap::kInitialNumberStringCacheSize * 2,
            heap->number_string_cache()->length());
 }
 
 
+TEST(Regress3877) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  Factory* factory = isolate->factory();
+  HandleScope scope(isolate);
+  CompileRun("function cls() { this.x = 10; }");
+  Handle<WeakCell> weak_prototype;
+  {
+    HandleScope inner_scope(isolate);
+    v8::Local<v8::Value> result = CompileRun("cls.prototype");
+    Handle<JSObject> proto =
+        v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(result));
+    weak_prototype = inner_scope.CloseAndEscape(factory->NewWeakCell(proto));
+  }
+  CHECK(!weak_prototype->cleared());
+  CompileRun(
+      "var a = { };"
+      "a.x = new cls();"
+      "cls.prototype = null;");
+  for (int i = 0; i < 4; i++) {
+    heap->CollectAllGarbage(Heap::kNoGCFlags);
+  }
+  // The map of a.x keeps prototype alive
+  CHECK(!weak_prototype->cleared());
+  // Change the map of a.x and make the previous map garbage collectable.
+  CompileRun("a.x.__proto__ = {};");
+  for (int i = 0; i < 4; i++) {
+    heap->CollectAllGarbage(Heap::kNoGCFlags);
+  }
+  CHECK(weak_prototype->cleared());
+}
+
+
+Handle<WeakCell> AddRetainedMap(Isolate* isolate, Heap* heap) {
+    HandleScope inner_scope(isolate);
+    Handle<Map> map = Map::Create(isolate, 1);
+    v8::Local<v8::Value> result =
+        CompileRun("(function () { return {x : 10}; })();");
+    Handle<JSObject> proto =
+        v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(result));
+    map->set_prototype(*proto);
+    heap->AddRetainedMap(map);
+    return inner_scope.CloseAndEscape(Map::WeakCellForMap(map));
+}
+
+
+void CheckMapRetainingFor(int n) {
+  FLAG_retain_maps_for_n_gc = n;
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  Handle<WeakCell> weak_cell = AddRetainedMap(isolate, heap);
+  CHECK(!weak_cell->cleared());
+  for (int i = 0; i < n; i++) {
+    heap->CollectGarbage(OLD_POINTER_SPACE);
+  }
+  CHECK(!weak_cell->cleared());
+  heap->CollectGarbage(OLD_POINTER_SPACE);
+  CHECK(weak_cell->cleared());
+}
+
+
+TEST(MapRetaining) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  CheckMapRetainingFor(FLAG_retain_maps_for_n_gc);
+  CheckMapRetainingFor(0);
+  CheckMapRetainingFor(1);
+  CheckMapRetainingFor(7);
+}
+
+
+TEST(RegressArrayListGC) {
+  FLAG_retain_maps_for_n_gc = 1;
+  FLAG_incremental_marking = 0;
+  FLAG_gc_global = true;
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  AddRetainedMap(isolate, heap);
+  Handle<Map> map = Map::Create(isolate, 1);
+  heap->CollectGarbage(OLD_POINTER_SPACE);
+  // Force GC in old space on next addition of retained map.
+  Map::WeakCellForMap(map);
+  SimulateFullSpace(CcTest::heap()->new_space());
+  for (int i = 0; i < 10; i++) {
+    heap->AddRetainedMap(map);
+  }
+  heap->CollectGarbage(OLD_POINTER_SPACE);
+}
+
+
 #ifdef DEBUG
 TEST(PathTracer) {
   CcTest::InitializeVM();
@@ -5095,23 +5189,63 @@ TEST(PathTracer) {
 #endif  // DEBUG
 
 
-TEST(FirstPageFitsStartup) {
-  // Test that the first page sizes provided by the default snapshot are large
-  // enough to fit everything right after startup and creating one context.
-  // If this test fails, we are allocating too much aside from deserialization.
-  if (!Snapshot::HaveASnapshotToStartFrom()) return;
-  if (Snapshot::EmbedsScript()) return;
-  CcTest::InitializeVM();
-  LocalContext env;
-  PagedSpaces spaces(CcTest::heap());
-  for (PagedSpace* s = spaces.next(); s != NULL; s = spaces.next()) {
-    uint32_t default_size = s->AreaSize();
-    uint32_t reduced_size = Snapshot::SizeOfFirstPage(s->identity());
-    if (reduced_size == default_size) continue;
-    int counter = 0;
-    Page* page = NULL;
-    for (PageIterator it(s); it.has_next(); page = it.next()) counter++;
-    CHECK_LE(counter, 1);
-    CHECK(static_cast<uint32_t>(page->area_size()) == reduced_size);
+TEST(WritableVsImmortalRoots) {
+  for (int i = 0; i < Heap::kStrongRootListLength; ++i) {
+    Heap::RootListIndex root_index = static_cast<Heap::RootListIndex>(i);
+    bool writable = Heap::RootCanBeWrittenAfterInitialization(root_index);
+    bool immortal = Heap::RootIsImmortalImmovable(root_index);
+    // A root value can be writable, immortal, or neither, but not both.
+    CHECK(!immortal || !writable);
   }
 }
+
+
+static void TestRightTrimFixedTypedArray(v8::ExternalArrayType type,
+                                         int initial_length,
+                                         int elements_to_trim) {
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  Heap* heap = isolate->heap();
+
+  Handle<FixedTypedArrayBase> array =
+      factory->NewFixedTypedArray(initial_length, type);
+  int old_size = array->size();
+  heap->RightTrimFixedArray<Heap::FROM_MUTATOR>(*array, elements_to_trim);
+
+  // Check that free space filler is at the right place and did not smash the
+  // array header.
+  CHECK(array->IsFixedArrayBase());
+  CHECK_EQ(initial_length - elements_to_trim, array->length());
+  int new_size = array->size();
+  if (new_size != old_size) {
+    // Free space filler should be created in this case.
+    Address next_obj_address = array->address() + array->size();
+    CHECK(HeapObject::FromAddress(next_obj_address)->IsFiller());
+  }
+  heap->CollectAllAvailableGarbage();
+}
+
+
+TEST(Regress472513) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  // The combination of type/initial_length/elements_to_trim triggered
+  // typed array header smashing with free space filler (crbug/472513).
+
+  // 64-bit cases.
+  TestRightTrimFixedTypedArray(v8::kExternalUint8Array, 32, 6);
+  TestRightTrimFixedTypedArray(v8::kExternalUint8Array, 32 - 7, 6);
+  TestRightTrimFixedTypedArray(v8::kExternalUint16Array, 16, 6);
+  TestRightTrimFixedTypedArray(v8::kExternalUint16Array, 16 - 3, 6);
+  TestRightTrimFixedTypedArray(v8::kExternalUint32Array, 8, 6);
+  TestRightTrimFixedTypedArray(v8::kExternalUint32Array, 8 - 1, 6);
+
+  // 32-bit cases.
+  TestRightTrimFixedTypedArray(v8::kExternalUint8Array, 16, 3);
+  TestRightTrimFixedTypedArray(v8::kExternalUint8Array, 16 - 3, 3);
+  TestRightTrimFixedTypedArray(v8::kExternalUint16Array, 8, 3);
+  TestRightTrimFixedTypedArray(v8::kExternalUint16Array, 8 - 1, 3);
+  TestRightTrimFixedTypedArray(v8::kExternalUint32Array, 4, 3);
+}
index 5e45034..cbbbf3c 100644 (file)
@@ -35,7 +35,6 @@
 #include "src/execution.h"
 #include "src/isolate.h"
 #include "src/parser.h"
-#include "src/snapshot.h"
 #include "src/unicode-inl.h"
 #include "src/utils.h"
 #include "test/cctest/cctest.h"
index 7f27710..98d3365 100644 (file)
@@ -37,7 +37,6 @@
 #include "src/execution.h"
 #include "src/isolate.h"
 #include "src/parser.h"
-#include "src/snapshot.h"
 #include "src/unicode-inl.h"
 #include "src/utils.h"
 #include "test/cctest/cctest.h"
index c909a02..b571564 100644 (file)
@@ -36,7 +36,6 @@
 #include "src/isolate.h"
 #include "src/parser.h"
 #include "src/smart-pointers.h"
-#include "src/snapshot.h"
 #include "src/unicode-inl.h"
 #include "src/utils.h"
 #include "test/cctest/cctest.h"
index 4b676d2..2386cec 100644 (file)
@@ -39,7 +39,7 @@
 #include "src/cpu-profiler.h"
 #include "src/log.h"
 #include "src/log-utils.h"
-#include "src/natives.h"
+#include "src/snapshot/natives.h"
 #include "src/utils.h"
 #include "src/v8threads.h"
 #include "src/version.h"
index b2b8c94..3834b18 100644 (file)
@@ -33,7 +33,6 @@
 #include "src/base/platform/platform.h"
 #include "src/factory.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
 
 using namespace v8::internal;
 
index 7f20a8d..4ff8cba 100644 (file)
@@ -32,7 +32,6 @@
 #include "src/base/platform/platform.h"
 #include "src/factory.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
 #include "test/cctest/cctest.h"
 
 namespace i = v8::internal;
@@ -98,21 +97,13 @@ typedef int (*F0)();
 
 static void EntryCode(MacroAssembler* masm) {
   // Smi constant register is callee save.
-  __ pushq(i::kSmiConstantRegister);
   __ pushq(i::kRootRegister);
-  __ InitializeSmiConstantRegister();
   __ InitializeRootRegister();
 }
 
 
 static void ExitCode(MacroAssembler* masm) {
-  // Return -1 if kSmiConstantRegister was clobbered during the test.
-  __ Move(rdx, Smi::FromInt(1));
-  __ cmpq(rdx, i::kSmiConstantRegister);
-  __ movq(rdx, Immediate(-1));
-  __ cmovq(not_equal, rax, rdx);
   __ popq(i::kRootRegister);
-  __ popq(i::kSmiConstantRegister);
 }
 
 
@@ -556,32 +547,6 @@ TEST(SmiCheck) {
   cond = masm->CheckNonNegativeSmi(rcx);  // "Positive" non-smi.
   __ j(cond, &exit);
 
-  // CheckIsMinSmi
-
-  __ incq(rax);
-  __ movq(rcx, Immediate(Smi::kMaxValue));
-  __ Integer32ToSmi(rcx, rcx);
-  cond = masm->CheckIsMinSmi(rcx);
-  __ j(cond, &exit);
-
-  __ incq(rax);
-  __ movq(rcx, Immediate(0));
-  __ Integer32ToSmi(rcx, rcx);
-  cond = masm->CheckIsMinSmi(rcx);
-  __ j(cond, &exit);
-
-  __ incq(rax);
-  __ movq(rcx, Immediate(Smi::kMinValue));
-  __ Integer32ToSmi(rcx, rcx);
-  cond = masm->CheckIsMinSmi(rcx);
-  __ j(NegateCondition(cond), &exit);
-
-  __ incq(rax);
-  __ movq(rcx, Immediate(Smi::kMinValue + 1));
-  __ Integer32ToSmi(rcx, rcx);
-  cond = masm->CheckIsMinSmi(rcx);
-  __ j(cond, &exit);
-
   // CheckBothSmi
 
   __ incq(rax);
index 0b057d8..3cee27a 100644 (file)
@@ -33,7 +33,6 @@
 #include "src/base/platform/platform.h"
 #include "src/factory.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
 
 using namespace v8::internal;
 
index 64d995d..cfc9717 100644 (file)
 
 #include "src/full-codegen.h"
 #include "src/global-handles.h"
-#include "src/snapshot.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
+using v8::Just;
 
 
 TEST(MarkingDeque) {
@@ -127,6 +127,7 @@ TEST(NoPromotion) {
 
 TEST(MarkCompactCollector) {
   FLAG_incremental_marking = false;
+  FLAG_retain_maps_for_n_gc = 0;
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   TestHeap* heap = CcTest::test_heap();
@@ -167,9 +168,7 @@ TEST(MarkCompactCollector) {
 
   { HandleScope scope(isolate);
     Handle<String> func_name = factory->InternalizeUtf8String("theFunction");
-    v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(global, func_name);
-    CHECK(maybe.has_value);
-    CHECK(maybe.value);
+    CHECK(Just(true) == JSReceiver::HasOwnProperty(global, func_name));
     Handle<Object> func_value =
         Object::GetProperty(global, func_name).ToHandleChecked();
     CHECK(func_value->IsJSFunction());
@@ -187,9 +186,7 @@ TEST(MarkCompactCollector) {
 
   { HandleScope scope(isolate);
     Handle<String> obj_name = factory->InternalizeUtf8String("theObject");
-    v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(global, obj_name);
-    CHECK(maybe.has_value);
-    CHECK(maybe.value);
+    CHECK(Just(true) == JSReceiver::HasOwnProperty(global, obj_name));
     Handle<Object> object =
         Object::GetProperty(global, obj_name).ToHandleChecked();
     CHECK(object->IsJSObject());
index 4c85151..391c934 100644 (file)
@@ -58,9 +58,26 @@ TEST(Regress340063) {
   if (!i::FLAG_allocation_site_pretenuring) return;
   v8::HandleScope scope(CcTest::isolate());
 
+  SetUpNewSpaceWithPoisonedMementoAtTop();
+
+  // Call GC to see if we can handle a poisonous memento right after the
+  // current new space top pointer.
+  CcTest::i_isolate()->heap()->CollectAllGarbage(
+      Heap::kAbortIncrementalMarkingMask);
+}
+
+
+TEST(Regress470390) {
+  CcTest::InitializeVM();
+  if (!i::FLAG_allocation_site_pretenuring) return;
+  v8::HandleScope scope(CcTest::isolate());
 
   SetUpNewSpaceWithPoisonedMementoAtTop();
 
+  // Set the new space limit to be equal to the top.
+  Address top = CcTest::i_isolate()->heap()->new_space()->top();
+  *(CcTest::i_isolate()->heap()->new_space()->allocation_limit_address()) = top;
+
   // Call GC to see if we can handle a poisonous memento right after the
   // current new space top pointer.
   CcTest::i_isolate()->heap()->CollectAllGarbage(
index 2f7ff87..3be1734 100644 (file)
@@ -145,6 +145,7 @@ class Expectations {
       os << ": " << representations_[i].Mnemonic();
       os << ", attrs: " << attributes_[i] << ")\n";
     }
+    os << "\n";
   }
 
   Handle<HeapType> GetFieldType(int index) {
@@ -232,12 +233,14 @@ class Expectations {
                       representations_[descriptor])) {
       return false;
     }
-    Object* expected_value = *values_[descriptor];
     Object* value = descriptors->GetValue(descriptor);
+    Object* expected_value = *values_[descriptor];
     switch (type) {
       case DATA:
-      case ACCESSOR:
-        return HeapType::cast(expected_value)->Equals(HeapType::cast(value));
+      case ACCESSOR: {
+        HeapType* type = descriptors->GetFieldType(descriptor);
+        return HeapType::cast(expected_value)->Equals(type);
+      }
 
       case DATA_CONSTANT:
         return value == expected_value;
@@ -263,6 +266,9 @@ class Expectations {
     for (int i = 0; i < expected_nof; i++) {
       if (!Check(descriptors, i)) {
         Print();
+#ifdef OBJECT_PRINT
+        descriptors->Print();
+#endif
         Check(descriptors, i);
         return false;
       }
@@ -336,9 +342,10 @@ class Expectations {
     SetDataField(property_index, attributes, representation, heap_type);
 
     Handle<String> name = MakeName("prop", property_index);
-    int t = map->SearchTransition(kData, *name, attributes);
-    CHECK_NE(TransitionArray::kNotFound, t);
-    return handle(map->GetTransition(t));
+    Map* target =
+        TransitionArray::SearchTransition(*map, kData, *name, attributes);
+    CHECK(target != NULL);
+    return handle(target);
   }
 
   Handle<Map> AddAccessorConstant(Handle<Map> map,
@@ -517,21 +524,51 @@ TEST(ReconfigureAccessorToNonExistingDataFieldHeavy) {
 // A set of tests for representation generalization case.
 //
 
-static void TestGeneralizeRepresentation(Representation from_representation,
-                                         Handle<HeapType> from_type,
-                                         Representation to_representation,
-                                         Handle<HeapType> to_type,
-                                         Representation expected_representation,
-                                         Handle<HeapType> expected_type) {
+// This test ensures that representation/field type generalization at
+// |property_index| is done correctly independently of the fact that the |map|
+// is detached from transition tree or not.
+//
+//  {} - p0 - p1 - p2: |detach_point_map|
+//                  |
+//                  X - detached at |detach_property_at_index|
+//                  |
+//                  + - p3 - p4: |map|
+//
+// Detaching does not happen if |detach_property_at_index| is -1.
+//
+static void TestGeneralizeRepresentation(
+    int detach_property_at_index, int property_index,
+    Representation from_representation, Handle<HeapType> from_type,
+    Representation to_representation, Handle<HeapType> to_type,
+    Representation expected_representation, Handle<HeapType> expected_type,
+    bool expected_deprecation, bool expected_field_type_dependency) {
   Isolate* isolate = CcTest::i_isolate();
+  Handle<HeapType> any_type = HeapType::Any(isolate);
+
+  CHECK(detach_property_at_index >= -1 &&
+        detach_property_at_index < kPropCount);
+  CHECK(property_index < kPropCount);
+  CHECK_NE(detach_property_at_index, property_index);
+
+  const bool is_detached_map = detach_property_at_index >= 0;
 
   Expectations expectations(isolate);
 
   // Create a map, add required properties to it and initialize expectations.
   Handle<Map> initial_map = Map::Create(isolate, 0);
   Handle<Map> map = initial_map;
+  Handle<Map> detach_point_map;
   for (int i = 0; i < kPropCount; i++) {
-    map = expectations.AddDataField(map, NONE, from_representation, from_type);
+    if (i == property_index) {
+      map =
+          expectations.AddDataField(map, NONE, from_representation, from_type);
+    } else {
+      map =
+          expectations.AddDataField(map, NONE, Representation::Smi(), any_type);
+      if (i == detach_property_at_index) {
+        detach_point_map = map;
+      }
+    }
   }
   CHECK(!map->is_deprecated());
   CHECK(map->is_stable());
@@ -540,97 +577,121 @@ static void TestGeneralizeRepresentation(Representation from_representation,
   Zone zone;
   FakeStubForTesting stub(isolate);
 
+  if (is_detached_map) {
+    detach_point_map = Map::ReconfigureProperty(
+        detach_point_map, detach_property_at_index, kData, NONE,
+        Representation::Tagged(), any_type, FORCE_FIELD);
+    expectations.SetDataField(detach_property_at_index,
+                              Representation::Tagged(), any_type);
+    CHECK(map->is_deprecated());
+    CHECK(expectations.Check(*detach_point_map,
+                             detach_point_map->NumberOfOwnDescriptors()));
+  }
+
   // Create new maps by generalizing representation of propX field.
-  Handle<Map> maps[kPropCount];
-  for (int i = 0; i < kPropCount; i++) {
-    Handle<Map> field_owner(map->FindFieldOwner(i), isolate);
-    CompilationInfo info(&stub, isolate, &zone);
-    CHECK(!info.HasAbortedDueToDependencyChange());
+  Handle<Map> field_owner(map->FindFieldOwner(property_index), isolate);
+  CompilationInfo info(&stub, isolate, &zone);
+  CHECK(!info.HasAbortedDueToDependencyChange());
+
+  Map::AddDependentCompilationInfo(field_owner, DependentCode::kFieldTypeGroup,
+                                   &info);
 
-    Map::AddDependentCompilationInfo(field_owner,
-                                     DependentCode::kFieldTypeGroup, &info);
+  Handle<Map> new_map =
+      Map::ReconfigureProperty(map, property_index, kData, NONE,
+                               to_representation, to_type, FORCE_FIELD);
 
-    Handle<Map> new_map = Map::ReconfigureProperty(
-        map, i, kData, NONE, to_representation, to_type, FORCE_FIELD);
-    maps[i] = new_map;
+  expectations.SetDataField(property_index, expected_representation,
+                            expected_type);
 
-    expectations.SetDataField(i, expected_representation, expected_type);
+  CHECK(!new_map->is_deprecated());
+  CHECK(expectations.Check(*new_map));
 
+  if (is_detached_map) {
     CHECK(map->is_deprecated());
-    CHECK(!info.HasAbortedDueToDependencyChange());
-    info.RollbackDependencies();  // Properly cleanup compilation info.
+    CHECK_NE(*map, *new_map);
+    CHECK_EQ(expected_field_type_dependency && !field_owner->is_deprecated(),
+             info.HasAbortedDueToDependencyChange());
 
+  } else if (expected_deprecation) {
+    CHECK(map->is_deprecated());
+    CHECK(field_owner->is_deprecated());
     CHECK_NE(*map, *new_map);
-    CHECK(i == 0 || maps[i - 1]->is_deprecated());
+    CHECK(!info.HasAbortedDueToDependencyChange());
 
-    CHECK(!new_map->is_deprecated());
-    CHECK(!new_map->is_dictionary_map());
-    CHECK(expectations.Check(*new_map));
+  } else {
+    CHECK(!field_owner->is_deprecated());
+    CHECK_EQ(*map, *new_map);
+
+    CHECK_EQ(expected_field_type_dependency,
+             info.HasAbortedDueToDependencyChange());
   }
 
-  Handle<Map> active_map = maps[kPropCount - 1];
-  CHECK(!active_map->is_deprecated());
+  info.RollbackDependencies();  // Properly cleanup compilation info.
 
   // Update all deprecated maps and check that they are now the same.
   Handle<Map> updated_map = Map::Update(map);
-  CHECK_EQ(*active_map, *updated_map);
-  for (int i = 0; i < kPropCount; i++) {
-    updated_map = Map::Update(maps[i]);
-    CHECK_EQ(*active_map, *updated_map);
-  }
+  CHECK_EQ(*new_map, *updated_map);
 }
 
 
-static void TestGeneralizeRepresentationTrivial(
+static void TestGeneralizeRepresentation(
     Representation from_representation, Handle<HeapType> from_type,
     Representation to_representation, Handle<HeapType> to_type,
     Representation expected_representation, Handle<HeapType> expected_type,
-    bool expected_field_type_dependency = true) {
-  Isolate* isolate = CcTest::i_isolate();
-
-  Expectations expectations(isolate);
-
-  // Create a map, add required properties to it and initialize expectations.
-  Handle<Map> initial_map = Map::Create(isolate, 0);
-  Handle<Map> map = initial_map;
-  for (int i = 0; i < kPropCount; i++) {
-    map = expectations.AddDataField(map, NONE, from_representation, from_type);
+    bool expected_deprecation, bool expected_field_type_dependency) {
+  // Check the cases when the map being reconfigured is a part of the
+  // transition tree.
+  STATIC_ASSERT(kPropCount > 4);
+  int indices[] = {0, 2, kPropCount - 1};
+  for (int i = 0; i < static_cast<int>(arraysize(indices)); i++) {
+    TestGeneralizeRepresentation(
+        -1, indices[i], from_representation, from_type, to_representation,
+        to_type, expected_representation, expected_type, expected_deprecation,
+        expected_field_type_dependency);
+  }
+
+  if (!from_representation.IsNone()) {
+    // Check the cases when the map being reconfigured is NOT a part of the
+    // transition tree. "None -> anything" representation changes make sense
+    // only for "attached" maps.
+    int indices[] = {0, kPropCount - 1};
+    for (int i = 0; i < static_cast<int>(arraysize(indices)); i++) {
+      TestGeneralizeRepresentation(
+          indices[i], 2, from_representation, from_type, to_representation,
+          to_type, expected_representation, expected_type, expected_deprecation,
+          expected_field_type_dependency);
+    }
   }
-  CHECK(!map->is_deprecated());
-  CHECK(map->is_stable());
-  CHECK(expectations.Check(*map));
-
-  Zone zone;
-  FakeStubForTesting stub(isolate);
-
-  // Create new maps by generalizing representation of propX field.
-  for (int i = 0; i < kPropCount; i++) {
-    Handle<Map> field_owner(map->FindFieldOwner(i), isolate);
-    CompilationInfo info(&stub, isolate, &zone);
-    CHECK(!info.HasAbortedDueToDependencyChange());
-
-    Map::AddDependentCompilationInfo(field_owner,
-                                     DependentCode::kFieldTypeGroup, &info);
+}
 
-    Handle<Map> new_map = Map::ReconfigureProperty(
-        map, i, kData, NONE, to_representation, to_type, FORCE_FIELD);
 
-    expectations.SetDataField(i, expected_representation, expected_type);
+static void TestGeneralizeRepresentation(Representation from_representation,
+                                         Handle<HeapType> from_type,
+                                         Representation to_representation,
+                                         Handle<HeapType> to_type,
+                                         Representation expected_representation,
+                                         Handle<HeapType> expected_type) {
+  const bool expected_deprecation = true;
+  const bool expected_field_type_dependency = false;
 
-    CHECK_EQ(*map, *new_map);
-    CHECK_EQ(expected_field_type_dependency,
-             info.HasAbortedDueToDependencyChange());
+  TestGeneralizeRepresentation(
+      from_representation, from_type, to_representation, to_type,
+      expected_representation, expected_type, expected_deprecation,
+      expected_field_type_dependency);
+}
 
-    info.RollbackDependencies();  // Properly cleanup compilation info.
 
-    CHECK_EQ(*map, *new_map);
-    CHECK(!new_map->is_deprecated());
-    CHECK(!new_map->is_dictionary_map());
-    CHECK(expectations.Check(*new_map));
-  }
+static void TestGeneralizeRepresentationTrivial(
+    Representation from_representation, Handle<HeapType> from_type,
+    Representation to_representation, Handle<HeapType> to_type,
+    Representation expected_representation, Handle<HeapType> expected_type,
+    bool expected_field_type_dependency = true) {
+  const bool expected_deprecation = false;
 
-  Handle<Map> updated_map = Map::Update(map);
-  CHECK_EQ(*map, *updated_map);
+  TestGeneralizeRepresentation(
+      from_representation, from_type, to_representation, to_type,
+      expected_representation, expected_type, expected_deprecation,
+      expected_field_type_dependency);
 }
 
 
@@ -828,7 +889,6 @@ TEST(GeneralizeRepresentationWithAccessorProperties) {
     CHECK(i == 0 || maps[i - 1]->is_deprecated());
 
     CHECK(!new_map->is_deprecated());
-    CHECK(!new_map->is_dictionary_map());
     CHECK(expectations.Check(*new_map));
   }
 
@@ -925,7 +985,6 @@ static void TestReconfigureDataFieldAttribute_GeneralizeRepresentation(
   CHECK_NE(*map, *new_map);
 
   CHECK(!new_map->is_deprecated());
-  CHECK(!new_map->is_dictionary_map());
   CHECK(expectations.Check(*new_map));
 
   // Update deprecated |map|, it should become |new_map|.
@@ -1016,7 +1075,6 @@ static void TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial(
   info.RollbackDependencies();  // Properly cleanup compilation info.
 
   CHECK(!new_map->is_deprecated());
-  CHECK(!new_map->is_dictionary_map());
   CHECK(expectations.Check(*new_map));
 
   Handle<Map> updated_map = Map::Update(map);
@@ -1121,7 +1179,6 @@ struct CheckDeprecated {
     CHECK_NE(*map, *new_map);
 
     CHECK(!new_map->is_deprecated());
-    CHECK(!new_map->is_dictionary_map());
     CHECK(expectations.Check(*new_map));
 
     // Update deprecated |map|, it should become |new_map|.
@@ -1140,7 +1197,6 @@ struct CheckSameMap {
     CHECK_EQ(*map, *new_map);
 
     CHECK(!new_map->is_deprecated());
-    CHECK(!new_map->is_dictionary_map());
     CHECK(expectations.Check(*new_map));
 
     // Update deprecated |map|, it should become |new_map|.
@@ -1163,7 +1219,6 @@ struct CheckCopyGeneralizeAllRepresentations {
     }
 
     CHECK(!new_map->is_deprecated());
-    CHECK(!new_map->is_dictionary_map());
     CHECK(expectations.Check(*new_map));
   }
 };
@@ -1423,9 +1478,10 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
       }
 
       Handle<String> name = MakeName("prop", i);
-      int t = map2->SearchTransition(kData, *name, NONE);
-      CHECK_NE(TransitionArray::kNotFound, t);
-      map2 = handle(map2->GetTransition(t));
+      Map* target =
+          TransitionArray::SearchTransition(*map2, kData, *name, NONE);
+      CHECK(target != NULL);
+      map2 = handle(target);
     }
 
     map2 = Map::ReconfigureProperty(map2, kSplitProp, kData, NONE,
@@ -1445,12 +1501,12 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
 
   // Fill in transition tree of |map2| so that it can't have more transitions.
   for (int i = 0; i < TransitionArray::kMaxNumberOfTransitions; i++) {
-    CHECK(map2->CanHaveMoreTransitions());
+    CHECK(TransitionArray::CanHaveMoreTransitions(map2));
     Handle<String> name = MakeName("foo", i);
     Map::CopyWithField(map2, name, any_type, NONE, Representation::Smi(),
                        INSERT_TRANSITION).ToHandleChecked();
   }
-  CHECK(!map2->CanHaveMoreTransitions());
+  CHECK(!TransitionArray::CanHaveMoreTransitions(map2));
 
   // Try to update |map|, since there is no place for propX transition at |map2|
   // |map| should become "copy-generalized".
index 1a17475..5b19746 100644 (file)
@@ -72,7 +72,6 @@ TEST(ScanKeywords) {
       i::Utf8ToUtf16CharacterStream stream(keyword, length);
       i::Scanner scanner(&unicode_cache);
       // The scanner should parse Harmony keywords for this test.
-      scanner.SetHarmonyScoping(true);
       scanner.SetHarmonyModules(true);
       scanner.SetHarmonyClasses(true);
       scanner.Initialize(&stream);
@@ -1045,15 +1044,14 @@ TEST(ScopeUsesArgumentsSuperThis) {
           factory->NewStringFromUtf8(i::CStrVector(program.start()))
               .ToHandleChecked();
       i::Handle<i::Script> script = factory->NewScript(source);
-      i::CompilationInfoWithZone info(script);
-      i::Parser parser(&info, isolate->stack_guard()->real_climit(),
-                       isolate->heap()->HashSeed(), isolate->unicode_cache());
+      i::Zone zone;
+      i::ParseInfo info(&zone, script);
+      i::Parser parser(&info);
       parser.set_allow_harmony_arrow_functions(true);
       parser.set_allow_harmony_classes(true);
       parser.set_allow_harmony_object_literals(true);
-      parser.set_allow_harmony_scoping(true);
       parser.set_allow_harmony_sloppy(true);
-      info.MarkAsGlobal();
+      info.set_global();
       CHECK(parser.Parse(&info));
       CHECK(i::Rewriter::Rewrite(&info));
       CHECK(i::Scope::Analyze(&info));
@@ -1086,8 +1084,6 @@ TEST(ScopeUsesArgumentsSuperThis) {
 
 
 TEST(ScopePositions) {
-  v8::internal::FLAG_harmony_scoping = true;
-
   // Test the parser for correctly setting the start and end positions
   // of a scope. We check the scope positions of exactly one scope
   // nested in the global scope of a program. 'inner source' is the
@@ -1297,14 +1293,13 @@ TEST(ScopePositions) {
         i::CStrVector(program.start())).ToHandleChecked();
     CHECK_EQ(source->length(), kProgramSize);
     i::Handle<i::Script> script = factory->NewScript(source);
-    i::CompilationInfoWithZone info(script);
-    i::Parser parser(&info, isolate->stack_guard()->real_climit(),
-                     isolate->heap()->HashSeed(), isolate->unicode_cache());
+    i::Zone zone;
+    i::ParseInfo info(&zone, script);
+    i::Parser parser(&info);
     parser.set_allow_lazy(true);
-    parser.set_allow_harmony_scoping(true);
     parser.set_allow_harmony_arrow_functions(true);
-    info.MarkAsGlobal();
-    info.SetLanguageMode(source_data[i].language_mode);
+    info.set_global();
+    info.set_language_mode(source_data[i].language_mode);
     parser.Parse(&info);
     CHECK(info.function() != NULL);
 
@@ -1377,14 +1372,12 @@ i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) {
 enum ParserFlag {
   kAllowLazy,
   kAllowNatives,
-  kAllowHarmonyScoping,
   kAllowHarmonyModules,
   kAllowHarmonyNumericLiterals,
   kAllowHarmonyArrowFunctions,
   kAllowHarmonyClasses,
   kAllowHarmonyObjectLiterals,
   kAllowHarmonyRestParameters,
-  kAllowHarmonyTemplates,
   kAllowHarmonySloppy,
   kAllowHarmonyUnicode,
   kAllowHarmonyComputedPropertyNames,
@@ -1403,7 +1396,6 @@ void SetParserFlags(i::ParserBase<Traits>* parser,
                     i::EnumSet<ParserFlag> flags) {
   parser->set_allow_lazy(flags.Contains(kAllowLazy));
   parser->set_allow_natives(flags.Contains(kAllowNatives));
-  parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping));
   parser->set_allow_harmony_modules(flags.Contains(kAllowHarmonyModules));
   parser->set_allow_harmony_numeric_literals(
       flags.Contains(kAllowHarmonyNumericLiterals));
@@ -1412,7 +1404,6 @@ void SetParserFlags(i::ParserBase<Traits>* parser,
   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_rest_params(
       flags.Contains(kAllowHarmonyRestParameters));
   parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy));
@@ -1456,11 +1447,11 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
   i::FunctionLiteral* function;
   {
     i::Handle<i::Script> script = factory->NewScript(source);
-    i::CompilationInfoWithZone info(script);
-    i::Parser parser(&info, isolate->stack_guard()->real_climit(),
-                     isolate->heap()->HashSeed(), isolate->unicode_cache());
+    i::Zone zone;
+    i::ParseInfo info(&zone, script);
+    i::Parser parser(&info);
     SetParserFlags(&parser, flags);
-    info.MarkAsGlobal();
+    info.set_global();
     parser.Parse(&info);
     function = info.function();
     if (function) {
@@ -1973,8 +1964,8 @@ TEST(NoErrorsFutureStrictReservedWords) {
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 
-  static const ParserFlag classes_flags[] = {
-      kAllowHarmonyArrowFunctions, kAllowHarmonyClasses, kAllowHarmonyScoping};
+  static const ParserFlag classes_flags[] = {kAllowHarmonyArrowFunctions,
+                                             kAllowHarmonyClasses};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     classes_flags, arraysize(classes_flags));
 }
@@ -2544,10 +2535,13 @@ TEST(DontRegressPreParserDataSizes) {
     i::Handle<i::String> source =
         factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked();
     i::Handle<i::Script> script = factory->NewScript(source);
-    i::CompilationInfoWithZone info(script);
+    i::Zone zone;
+    i::ParseInfo info(&zone, script);
     i::ScriptData* sd = NULL;
-    info.SetCachedData(&sd, v8::ScriptCompiler::kProduceParserCache);
-    i::Parser::ParseStatic(&info, true);
+    info.set_cached_data(&sd);
+    info.set_compile_options(v8::ScriptCompiler::kProduceParserCache);
+    info.set_allow_lazy_parsing();
+    i::Parser::ParseStatic(&info);
     i::ParseData* pd = i::ParseData::FromCachedData(sd);
 
     if (pd->FunctionCount() != test_cases[i].functions) {
@@ -2961,6 +2955,36 @@ TEST(StrictDelete) {
 }
 
 
+TEST(NoErrorsDeclsInCase) {
+  const char* context_data[][2] = {
+    {"'use strict'; switch(x) { case 1:", "}"},
+    {"function foo() {'use strict'; switch(x) { case 1:", "}}"},
+    {"'use strict'; switch(x) { case 1: case 2:", "}"},
+    {"function foo() {'use strict'; switch(x) { case 1: case 2:", "}}"},
+    {"'use strict'; switch(x) { default:", "}"},
+    {"function foo() {'use strict'; switch(x) { default:", "}}"},
+    {"'use strict'; switch(x) { case 1: default:", "}"},
+    {"function foo() {'use strict'; switch(x) { case 1: default:", "}}"},
+    { nullptr, nullptr }
+  };
+
+  const char* statement_data[] = {
+    "function f() { }",
+    "class C { }",
+    "class C extends Q {}",
+    "function f() { } class C {}",
+    "function f() { }; class C {}",
+    "class C {}; function f() {}",
+    nullptr
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
+
+  RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
 TEST(InvalidLeftHandSide) {
   const char* assignment_context_data[][2] = {
     {"", " = 1;"},
@@ -3246,70 +3270,6 @@ TEST(IfArgumentsArrayAccessedThenParametersMaybeAssigned) {
 }
 
 
-TEST(ExportsMaybeAssigned) {
-  i::FLAG_use_strict = true;
-  i::FLAG_harmony_scoping = true;
-  i::FLAG_harmony_modules = true;
-
-  i::Isolate* isolate = CcTest::i_isolate();
-  i::Factory* factory = isolate->factory();
-  i::HandleScope scope(isolate);
-  LocalContext env;
-
-  const char* src =
-      "module A {"
-      "  export var x = 1;"
-      "  export function f() { return x };"
-      "  export const y = 2;"
-      "  module B {}"
-      "  export module C {}"
-      "};"
-      "A.f";
-
-  i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
-  i::SNPrintF(program, "%s", src);
-  i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
-  source->PrintOn(stdout);
-  printf("\n");
-  i::Zone zone;
-  v8::Local<v8::Value> v = CompileRun(src);
-  i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
-  i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
-  i::Context* context = f->context();
-  i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
-  avf.Internalize(isolate);
-
-  i::Scope* script_scope =
-      new (&zone) i::Scope(&zone, NULL, i::SCRIPT_SCOPE, &avf);
-  script_scope->Initialize();
-  i::Scope* s =
-      i::Scope::DeserializeScopeChain(isolate, &zone, context, script_scope);
-  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");
-  const i::AstRawString* name_B = avf.GetOneByteString("B");
-  const i::AstRawString* name_C = avf.GetOneByteString("C");
-
-  // Get result from h's function context (that is f's context)
-  i::Variable* var_x = s->Lookup(name_x);
-  CHECK(var_x != NULL);
-  CHECK(var_x->maybe_assigned() == i::kMaybeAssigned);
-  i::Variable* var_f = s->Lookup(name_f);
-  CHECK(var_f != NULL);
-  CHECK(var_f->maybe_assigned() == i::kMaybeAssigned);
-  i::Variable* var_y = s->Lookup(name_y);
-  CHECK(var_y != NULL);
-  CHECK(var_y->maybe_assigned() == i::kNotAssigned);
-  i::Variable* var_B = s->Lookup(name_B);
-  CHECK(var_B != NULL);
-  CHECK(var_B->maybe_assigned() == i::kNotAssigned);
-  i::Variable* var_C = s->Lookup(name_C);
-  CHECK(var_C != NULL);
-  CHECK(var_C->maybe_assigned() == i::kNotAssigned);
-}
-
-
 TEST(InnerAssignment) {
   i::Isolate* isolate = CcTest::i_isolate();
   i::Factory* factory = isolate->factory();
@@ -3431,11 +3391,9 @@ TEST(InnerAssignment) {
           printf("\n");
 
           i::Handle<i::Script> script = factory->NewScript(source);
-          i::CompilationInfoWithZone info(script);
-          i::Parser parser(&info, isolate->stack_guard()->real_climit(),
-                           isolate->heap()->HashSeed(),
-                           isolate->unicode_cache());
-          parser.set_allow_harmony_scoping(true);
+          i::Zone zone;
+          i::ParseInfo info(&zone, script);
+          i::Parser parser(&info);
           CHECK(parser.Parse(&info));
           CHECK(i::Compiler::Analyze(&info));
           CHECK(info.function() != NULL);
@@ -3583,7 +3541,7 @@ TEST(ErrorsArrowFunctions) {
   };
 
   // The test is quite slow, so run it with a reduced set of flags.
-  static const ParserFlag flags[] = {kAllowLazy, kAllowHarmonyScoping};
+  static const ParserFlag flags[] = {kAllowLazy};
   static const ParserFlag always_flags[] = { kAllowHarmonyArrowFunctions };
   RunParserSyncTest(context_data, statement_data, kError, flags,
                     arraysize(flags), always_flags, arraysize(always_flags));
@@ -4111,8 +4069,7 @@ TEST(ClassDeclarationNoErrors) {
     "class name extends class base {} {}",
     NULL};
 
-  static const ParserFlag always_flags[] = {
-      kAllowHarmonyClasses, kAllowHarmonyScoping};
+  static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -4631,9 +4588,7 @@ TEST(ConstParsingInForIn) {
       "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));
+  RunParserSyncTest(context_data, data, kSuccess, nullptr, 0, nullptr, 0);
 }
 
 
@@ -4653,9 +4608,7 @@ TEST(ConstParsingInForInError) {
       "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));
+  RunParserSyncTest(context_data, data, kError, nullptr, 0, nullptr, 0);
 }
 
 
@@ -4749,9 +4702,7 @@ TEST(ScanTemplateLiterals) {
       "`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));
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, NULL, 0);
 }
 
 
@@ -4786,9 +4737,7 @@ TEST(ScanTaggedTemplateLiterals) {
       "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));
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, NULL, 0);
 }
 
 
@@ -4815,9 +4764,7 @@ TEST(TemplateMaterializedLiterals) {
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
-  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
-                    arraysize(always_flags));
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, NULL, 0);
 }
 
 
@@ -4851,9 +4798,7 @@ TEST(ScanUnterminatedTemplateLiterals) {
       "`foo${fn(}`",
       "`foo${1 if}`",
       NULL};
-  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
-  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
-                    arraysize(always_flags));
+  RunParserSyncTest(context_data, data, kError, NULL, 0, NULL, 0);
 }
 
 
@@ -4873,9 +4818,7 @@ TEST(TemplateLiteralsIllegalTokens) {
       "`hello${1}\\x\n${2}`",
       NULL};
 
-  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
-  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
-                    arraysize(always_flags));
+  RunParserSyncTest(context_data, data, kError, NULL, 0, NULL, 0);
 }
 
 
@@ -5010,8 +4953,7 @@ TEST(LexicalScopingSloppyMode) {
     "(class C {})",
     "(class C extends D {})",
     NULL};
-  static const ParserFlag always_true_flags[] = {
-      kAllowHarmonyScoping, kAllowHarmonyClasses};
+  static const ParserFlag always_true_flags[] = {kAllowHarmonyClasses};
   static const ParserFlag always_false_flags[] = {kAllowHarmonySloppy};
   RunParserSyncTest(context_data, bad_data, kError, NULL, 0,
                     always_true_flags, arraysize(always_true_flags),
@@ -5108,6 +5050,7 @@ TEST(BasicImportExportParsing) {
       "export { yield } from 'm.js'",
       "export { static } from 'm.js'",
       "export { let } from 'm.js'",
+      "var a; export { a as b, a as c };",
 
       "import 'somemodule.js';",
       "import { } from 'm.js';",
@@ -5135,23 +5078,18 @@ TEST(BasicImportExportParsing) {
                                         128 * 1024);
 
   for (unsigned i = 0; i < arraysize(kSources); ++i) {
-    int kProgramByteSize = i::StrLength(kSources[i]);
-    i::ScopedVector<char> program(kProgramByteSize + 1);
-    i::SNPrintF(program, "%s", kSources[i]);
     i::Handle<i::String> source =
-        factory->NewStringFromUtf8(i::CStrVector(program.start()))
-            .ToHandleChecked();
+        factory->NewStringFromAsciiChecked(kSources[i]);
 
     // Show that parsing as a module works
     {
       i::Handle<i::Script> script = factory->NewScript(source);
-      i::CompilationInfoWithZone info(script);
-      i::Parser parser(&info, isolate->stack_guard()->real_climit(),
-                       isolate->heap()->HashSeed(), isolate->unicode_cache());
+      i::Zone zone;
+      i::ParseInfo info(&zone, script);
+      i::Parser parser(&info);
       parser.set_allow_harmony_classes(true);
       parser.set_allow_harmony_modules(true);
-      parser.set_allow_harmony_scoping(true);
-      info.MarkAsModule();
+      info.set_module();
       if (!parser.Parse(&info)) {
         i::Handle<i::JSObject> exception_handle(
             i::JSObject::cast(isolate->pending_exception()));
@@ -5173,13 +5111,12 @@ TEST(BasicImportExportParsing) {
     // And that parsing a script does not.
     {
       i::Handle<i::Script> script = factory->NewScript(source);
-      i::CompilationInfoWithZone info(script);
-      i::Parser parser(&info, isolate->stack_guard()->real_climit(),
-                       isolate->heap()->HashSeed(), isolate->unicode_cache());
+      i::Zone zone;
+      i::ParseInfo info(&zone, script);
+      i::Parser parser(&info);
       parser.set_allow_harmony_classes(true);
       parser.set_allow_harmony_modules(true);
-      parser.set_allow_harmony_scoping(true);
-      info.MarkAsGlobal();
+      info.set_global();
       CHECK(!parser.Parse(&info));
     }
   }
@@ -5211,6 +5148,10 @@ TEST(ImportExportParsingErrors) {
       "export { arguments }",
       "export { arguments as foo }",
       "var a; export { a, a };",
+      "var a, b; export { a as b, b };",
+      "var a, b; export { a as c, b as c };",
+      "export default function f(){}; export default class C {};",
+      "export default function f(){}; var a; export { a as default };",
 
       "import from;",
       "import from 'm.js';",
@@ -5256,26 +5197,81 @@ TEST(ImportExportParsingErrors) {
                                         128 * 1024);
 
   for (unsigned i = 0; i < arraysize(kErrorSources); ++i) {
-    int kProgramByteSize = i::StrLength(kErrorSources[i]);
-    i::ScopedVector<char> program(kProgramByteSize + 1);
-    i::SNPrintF(program, "%s", kErrorSources[i]);
     i::Handle<i::String> source =
-        factory->NewStringFromUtf8(i::CStrVector(program.start()))
-            .ToHandleChecked();
+        factory->NewStringFromAsciiChecked(kErrorSources[i]);
 
     i::Handle<i::Script> script = factory->NewScript(source);
-    i::CompilationInfoWithZone info(script);
-    i::Parser parser(&info, isolate->stack_guard()->real_climit(),
-                     isolate->heap()->HashSeed(), isolate->unicode_cache());
+    i::Zone zone;
+    i::ParseInfo info(&zone, script);
+    i::Parser parser(&info);
     parser.set_allow_harmony_classes(true);
     parser.set_allow_harmony_modules(true);
-    parser.set_allow_harmony_scoping(true);
-    info.MarkAsModule();
+    info.set_module();
     CHECK(!parser.Parse(&info));
   }
 }
 
 
+TEST(ModuleParsingInternals) {
+  i::FLAG_harmony_modules = true;
+
+  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);
+
+  static const char kSource[] =
+      "let x = 5;"
+      "export { x as y };"
+      "import { q as z } from 'm.js';"
+      "import n from 'n.js'";
+  i::Handle<i::String> source = factory->NewStringFromAsciiChecked(kSource);
+  i::Handle<i::Script> script = factory->NewScript(source);
+  i::Zone zone;
+  i::ParseInfo info(&zone, script);
+  i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
+  i::Parser parser(&info);
+  parser.set_allow_harmony_modules(true);
+  info.set_module();
+  CHECK(parser.Parse(&info));
+  CHECK(i::Compiler::Analyze(&info));
+
+  i::FunctionLiteral* func = info.function();
+  i::Scope* module_scope = func->scope();
+  i::Scope* outer_scope = module_scope->outer_scope();
+  CHECK(outer_scope->is_script_scope());
+  CHECK_NULL(outer_scope->outer_scope());
+  CHECK_EQ(1, outer_scope->num_modules());
+  CHECK(module_scope->is_module_scope());
+  CHECK_NOT_NULL(module_scope->module_var());
+  CHECK_EQ(i::INTERNAL, module_scope->module_var()->mode());
+
+  i::ModuleDescriptor* descriptor = module_scope->module();
+  CHECK_NOT_NULL(descriptor);
+  CHECK_EQ(1, descriptor->Length());
+  const i::AstRawString* export_name = avf.GetOneByteString("y");
+  const i::AstRawString* local_name =
+      descriptor->LookupLocalExport(export_name, &zone);
+  CHECK_NOT_NULL(local_name);
+  CHECK(local_name->IsOneByteEqualTo("x"));
+  i::ZoneList<i::Declaration*>* declarations = module_scope->declarations();
+  CHECK_EQ(3, declarations->length());
+  CHECK(declarations->at(0)->proxy()->raw_name()->IsOneByteEqualTo("x"));
+  i::ImportDeclaration* import_decl =
+      declarations->at(1)->AsImportDeclaration();
+  CHECK(import_decl->import_name()->IsOneByteEqualTo("q"));
+  CHECK(import_decl->proxy()->raw_name()->IsOneByteEqualTo("z"));
+  CHECK(import_decl->module_specifier()->IsOneByteEqualTo("m.js"));
+  import_decl = declarations->at(2)->AsImportDeclaration();
+  CHECK(import_decl->import_name()->IsOneByteEqualTo("default"));
+  CHECK(import_decl->proxy()->raw_name()->IsOneByteEqualTo("n"));
+  CHECK(import_decl->module_specifier()->IsOneByteEqualTo("n.js"));
+}
+
+
 TEST(DuplicateProtoError) {
   const char* context_data[][2] = {
     {"({", "});"},
@@ -5339,8 +5335,8 @@ TEST(DeclarationsError) {
     "class C {}",
     NULL};
 
-  static const ParserFlag always_flags[] = {
-      kAllowHarmonyClasses, kAllowHarmonyScoping, kAllowStrongMode};
+  static const ParserFlag always_flags[] = {kAllowHarmonyClasses,
+                                            kAllowStrongMode};
   RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -5358,11 +5354,11 @@ void TestLanguageMode(const char* source,
 
   i::Handle<i::Script> script =
       factory->NewScript(factory->NewStringFromAsciiChecked(source));
-  i::CompilationInfoWithZone info(script);
-  i::Parser parser(&info, isolate->stack_guard()->real_climit(),
-                   isolate->heap()->HashSeed(), isolate->unicode_cache());
+  i::Zone zone;
+  i::ParseInfo info(&zone, script);
+  i::Parser parser(&info);
   parser.set_allow_strong_mode(true);
-  info.MarkAsGlobal();
+  info.set_global();
   parser.Parse(&info);
   CHECK(info.function() != NULL);
   CHECK_EQ(expected_language_mode, info.function()->language_mode());
@@ -5425,8 +5421,7 @@ TEST(PropertyNameEvalArguments) {
       NULL};
 
   static const ParserFlag always_flags[] = {
-      kAllowHarmonyClasses, kAllowHarmonyObjectLiterals, kAllowHarmonyScoping,
-      kAllowStrongMode};
+      kAllowHarmonyClasses, kAllowHarmonyObjectLiterals, kAllowStrongMode};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -5498,8 +5493,7 @@ TEST(VarForbiddenInStrongMode) {
     "const x = 0;",
     NULL};
 
-  static const ParserFlag always_flags[] = {kAllowStrongMode,
-                                            kAllowHarmonyScoping};
+  static const ParserFlag always_flags[] = {kAllowStrongMode};
   RunParserSyncTest(strong_context_data, var_declarations, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
   RunParserSyncTest(strong_context_data, let_declarations, kSuccess, NULL, 0,
@@ -5539,7 +5533,7 @@ TEST(StrongEmptySubStatements) {
       NULL};
 
   static const ParserFlag always_flags[] = {
-      kAllowStrongMode, kAllowHarmonyScoping
+      kAllowStrongMode,
   };
   RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
                     arraysize(always_flags));
@@ -5561,7 +5555,7 @@ TEST(StrongForIn) {
       NULL};
 
   static const ParserFlag always_flags[] = {
-      kAllowStrongMode, kAllowHarmonyScoping
+      kAllowStrongMode,
   };
   RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
                     arraysize(always_flags));
@@ -5570,3 +5564,227 @@ TEST(StrongForIn) {
   RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
                     arraysize(always_flags));
 }
+
+
+TEST(StrongSuperCalls) {
+  const char* sloppy_context_data[][2] = {{"", ""}, {NULL}};
+  const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
+  const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
+
+  const char* data[] = {
+      "class C extends Object { constructor() {} }",
+      "class C extends Object { constructor() { (super()); } }",
+      "class C extends Object { constructor() { (() => super())(); } }",
+      "class C extends Object { constructor() { { super(); } } }",
+      "class C extends Object { constructor() { if (1) super(); } }",
+      "class C extends Object { constructor() { super(), super(); } }",
+      "class C extends Object { constructor() { super(); super(); } }",
+      "class C extends Object { constructor() { super(); (super()); } }",
+      "class C extends Object { constructor() { super(); { super() } } }",
+      NULL};
+
+  static const ParserFlag always_flags[] = {
+      kAllowStrongMode, kAllowHarmonyClasses, kAllowHarmonyObjectLiterals,
+      kAllowHarmonyArrowFunctions
+  };
+  RunParserSyncTest(sloppy_context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+  RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+  RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(StrongConstructorReturns) {
+  const char* sloppy_context_data[][2] = {{"", ""}, {NULL}};
+  const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
+  const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
+
+  const char* data[] = {
+      "class C extends Object { constructor() { super(); return {}; } }",
+      "class C extends Object { constructor() { super(); { return {}; } } }",
+      "class C extends Object { constructor() { super(); if (1) return {}; } }",
+      "class C extends Object { constructor() { return; super(); } }",
+      "class C extends Object { constructor() { { return; } super(); } }",
+      "class C extends Object { constructor() { if (0) return; super(); } }",
+      NULL};
+
+  static const ParserFlag always_flags[] = {
+      kAllowStrongMode, kAllowHarmonyClasses, kAllowHarmonyObjectLiterals
+  };
+  RunParserSyncTest(sloppy_context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+  RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+  RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(ArrowFunctionASIErrors) {
+  const char* context_data[][2] = {{"'use strict';", ""}, {"", ""},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "(a\n=> a)(1)",
+      "(a/*\n*/=> a)(1)",
+      "((a)\n=> a)(1)",
+      "((a)/*\n*/=> a)(1)",
+      "((a, b)\n=> a + b)(1, 2)",
+      "((a, b)/*\n*/=> a + b)(1, 2)",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(StrongModeFreeVariablesDeclaredByPreviousScript) {
+  i::FLAG_strong_mode = true;
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate()));
+  v8::TryCatch try_catch;
+
+  // Introduce a bunch of variables, in all language modes.
+  const char* script1 =
+      "var my_var1 = 0;        \n"
+      "function my_func1() { } \n"
+      "const my_const1 = 0;    \n";
+  CompileRun(v8_str(script1));
+  CHECK(!try_catch.HasCaught());
+
+  const char* script2 =
+      "\"use strict\";         \n"
+      "let my_var2 = 0;        \n"
+      "function my_func2() { } \n"
+      "const my_const2 = 0     \n";
+  CompileRun(v8_str(script2));
+  CHECK(!try_catch.HasCaught());
+
+  const char* script3 =
+      "\"use strong\";         \n"
+      "let my_var3 = 0;        \n"
+      "function my_func3() { } \n"
+      "const my_const3 = 0;    \n";
+  CompileRun(v8_str(script3));
+  CHECK(!try_catch.HasCaught());
+
+  // Sloppy eval introduces variables in the surrounding scope.
+  const char* script4 =
+      "eval('var my_var4 = 0;')        \n"
+      "eval('function my_func4() { }') \n"
+      "eval('const my_const4 = 0;')    \n";
+  CompileRun(v8_str(script4));
+  CHECK(!try_catch.HasCaught());
+
+  // Test that referencing these variables work.
+  const char* script5 =
+      "\"use strong\";         \n"
+      "my_var1;                \n"
+      "my_func1;               \n"
+      "my_const1;              \n"
+      "my_var2;                \n"
+      "my_func2;               \n"
+      "my_const2;              \n"
+      "my_var3;                \n"
+      "my_func3;               \n"
+      "my_const3;              \n"
+      "my_var4;                \n"
+      "my_func4;               \n"
+      "my_const4;              \n";
+  CompileRun(v8_str(script5));
+  CHECK(!try_catch.HasCaught());
+}
+
+
+TEST(StrongModeFreeVariablesDeclaredByLanguage) {
+  i::FLAG_strong_mode = true;
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate()));
+  v8::TryCatch try_catch;
+
+  const char* script1 =
+      "\"use strong\";         \n"
+      "Math;                   \n"
+      "RegExp;                 \n";
+  CompileRun(v8_str(script1));
+  CHECK(!try_catch.HasCaught());
+}
+
+
+TEST(StrongModeFreeVariablesDeclaredInGlobalPrototype) {
+  i::FLAG_strong_mode = true;
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate()));
+  v8::TryCatch try_catch;
+
+  const char* script1 = "this.__proto__.my_var = 0;\n";
+  CompileRun(v8_str(script1));
+  CHECK(!try_catch.HasCaught());
+
+  const char* script2 =
+      "\"use strong\";         \n"
+      "my_var;                 \n";
+  CompileRun(v8_str(script2));
+  CHECK(!try_catch.HasCaught());
+}
+
+
+TEST(StrongModeFreeVariablesNotDeclared) {
+  i::FLAG_strong_mode = true;
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate()));
+  v8::TryCatch try_catch;
+
+  // Test that referencing unintroduced variables in sloppy mode is ok.
+  const char* script1 =
+      "if (false) {            \n"
+      "  not_there1;           \n"
+      "}                       \n";
+  CompileRun(v8_str(script1));
+  CHECK(!try_catch.HasCaught());
+
+  // But not in strong mode.
+  {
+    const char* script2 =
+        "\"use strong\";         \n"
+        "if (false) {            \n"
+        "  not_there2;           \n"
+        "}                       \n";
+    v8::TryCatch try_catch2;
+    v8::Script::Compile(v8_str(script2));
+    CHECK(try_catch2.HasCaught());
+    v8::String::Utf8Value exception(try_catch2.Exception());
+    CHECK_EQ(0,
+             strcmp(
+                 "ReferenceError: In strong mode, using an undeclared global "
+                 "variable 'not_there2' is not allowed",
+                 *exception));
+  }
+
+  // Check that the variable reference is detected inside a strong function too,
+  // even if the script scope is not strong.
+  {
+    const char* script3 =
+        "(function not_lazy() {  \n"
+        "  \"use strong\";       \n"
+        "  if (false) {          \n"
+        "    not_there3;         \n"
+        "  }                     \n"
+        "})();                   \n";
+    v8::TryCatch try_catch2;
+    v8::Script::Compile(v8_str(script3));
+    CHECK(try_catch2.HasCaught());
+    v8::String::Utf8Value exception(try_catch2.Exception());
+    CHECK_EQ(0,
+             strcmp(
+                 "ReferenceError: In strong mode, using an undeclared global "
+                 "variable 'not_there3' is not allowed",
+                 *exception));
+  }
+}
index 55eac60..80aa77b 100644 (file)
 #include "src/compilation-cache.h"
 #include "src/debug.h"
 #include "src/heap/spaces.h"
-#include "src/natives.h"
 #include "src/objects.h"
+#include "src/parser.h"
 #include "src/runtime/runtime.h"
 #include "src/scopeinfo.h"
-#include "src/serialize.h"
-#include "src/snapshot.h"
+#include "src/snapshot/natives.h"
+#include "src/snapshot/serialize.h"
+#include "src/snapshot/snapshot.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
 
 
-template <class T>
-static Address AddressOf(T id) {
-  return ExternalReference(id, CcTest::i_isolate()).address();
+bool DefaultSnapshotAvailable() {
+  return i::Snapshot::DefaultSnapshotBlob() != NULL;
 }
 
 
-template <class T>
-static uint32_t Encode(const ExternalReferenceEncoder& encoder, T id) {
-  return encoder.Encode(AddressOf(id));
+void DisableTurbofan() {
+  const char* flag = "--turbo-filter=\"\"";
+  FlagList::SetFlagsFromString(flag, StrLength(flag));
 }
 
 
-static uint32_t make_code(TypeCode type, int id) {
-  return static_cast<uint32_t>(type) << kReferenceTypeShift | id;
-}
-
-
-TEST(ExternalReferenceEncoder) {
-  Isolate* isolate = CcTest::i_isolate();
-  v8::V8::Initialize();
-
-  ExternalReferenceEncoder encoder(isolate);
-  CHECK_EQ(make_code(BUILTIN, Builtins::kArrayCode),
-           Encode(encoder, Builtins::kArrayCode));
-  CHECK_EQ(make_code(v8::internal::RUNTIME_FUNCTION, Runtime::kAbort),
-           Encode(encoder, Runtime::kAbort));
-  ExternalReference stack_limit_address =
-      ExternalReference::address_of_stack_limit(isolate);
-  CHECK_EQ(make_code(UNCLASSIFIED, 2),
-           encoder.Encode(stack_limit_address.address()));
-  ExternalReference real_stack_limit_address =
-      ExternalReference::address_of_real_stack_limit(isolate);
-  CHECK_EQ(make_code(UNCLASSIFIED, 3),
-           encoder.Encode(real_stack_limit_address.address()));
-  CHECK_EQ(make_code(UNCLASSIFIED, 8),
-           encoder.Encode(ExternalReference::debug_break(isolate).address()));
-  CHECK_EQ(
-      make_code(UNCLASSIFIED, 4),
-      encoder.Encode(ExternalReference::new_space_start(isolate).address()));
-  CHECK_EQ(
-      make_code(UNCLASSIFIED, 1),
-      encoder.Encode(ExternalReference::roots_array_start(isolate).address()));
-  CHECK_EQ(make_code(UNCLASSIFIED, 33),
-           encoder.Encode(ExternalReference::cpu_features().address()));
-}
-
-
-TEST(ExternalReferenceDecoder) {
-  Isolate* isolate = CcTest::i_isolate();
-  v8::V8::Initialize();
-
-  ExternalReferenceDecoder decoder(isolate);
-  CHECK_EQ(AddressOf(Builtins::kArrayCode),
-           decoder.Decode(make_code(BUILTIN, Builtins::kArrayCode)));
-  CHECK_EQ(AddressOf(Runtime::kAbort),
-           decoder.Decode(make_code(v8::internal::RUNTIME_FUNCTION,
-                                    Runtime::kAbort)));
-  CHECK_EQ(ExternalReference::address_of_stack_limit(isolate).address(),
-           decoder.Decode(make_code(UNCLASSIFIED, 2)));
-  CHECK_EQ(ExternalReference::address_of_real_stack_limit(isolate).address(),
-           decoder.Decode(make_code(UNCLASSIFIED, 3)));
-  CHECK_EQ(ExternalReference::debug_break(isolate).address(),
-           decoder.Decode(make_code(UNCLASSIFIED, 8)));
-  CHECK_EQ(ExternalReference::new_space_start(isolate).address(),
-           decoder.Decode(make_code(UNCLASSIFIED, 4)));
-}
+// TestIsolate is used for testing isolate serialization.
+class TestIsolate : public Isolate {
+ public:
+  static v8::Isolate* NewInitialized(bool enable_serializer) {
+    i::Isolate* isolate = new TestIsolate(enable_serializer);
+    v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
+    v8::Isolate::Scope isolate_scope(v8_isolate);
+    isolate->Init(NULL);
+    return v8_isolate;
+  }
+  explicit TestIsolate(bool enable_serializer) : Isolate(enable_serializer) {}
+};
 
 
 void WritePayload(const Vector<const byte>& payload, const char* file_name) {
@@ -175,24 +133,20 @@ Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head,
 
 // Test that the whole heap can be serialized.
 UNINITIALIZED_TEST(Serialize) {
-  if (!Snapshot::HaveASnapshotToStartFrom()) {
-    v8::Isolate::CreateParams params;
-    params.enable_serializer = true;
-    v8::Isolate* isolate = v8::Isolate::New(params);
-    Serialize(isolate);
-  }
+  DisableTurbofan();
+  if (DefaultSnapshotAvailable()) return;
+  v8::Isolate* isolate = TestIsolate::NewInitialized(true);
+  Serialize(isolate);
 }
 
 
 // Test that heap serialization is non-destructive.
 UNINITIALIZED_TEST(SerializeTwice) {
-  if (!Snapshot::HaveASnapshotToStartFrom()) {
-    v8::Isolate::CreateParams params;
-    params.enable_serializer = true;
-    v8::Isolate* isolate = v8::Isolate::New(params);
-    Serialize(isolate);
-    Serialize(isolate);
-  }
+  DisableTurbofan();
+  if (DefaultSnapshotAvailable()) return;
+  v8::Isolate* isolate = TestIsolate::NewInitialized(true);
+  Serialize(isolate);
+  Serialize(isolate);
 }
 
 
@@ -207,7 +161,7 @@ v8::Isolate* InitializeFromFile(const char* snapshot_file) {
   {
     SnapshotData snapshot_data(Vector<const byte>(str, len));
     Deserializer deserializer(&snapshot_data);
-    Isolate* isolate = Isolate::NewForTesting();
+    Isolate* isolate = new TestIsolate(false);
     v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     v8::Isolate::Scope isolate_scope(v8_isolate);
     isolate->Init(&deserializer);
@@ -241,466 +195,538 @@ UNINITIALIZED_DEPENDENT_TEST(Deserialize, Serialize) {
   // The serialize-deserialize tests only work if the VM is built without
   // serialization.  That doesn't matter.  We don't need to be able to
   // serialize a snapshot in a VM that is booted from a snapshot.
-  if (!Snapshot::HaveASnapshotToStartFrom()) {
-    v8::Isolate* isolate = Deserialize();
-    {
-      v8::HandleScope handle_scope(isolate);
-      v8::Isolate::Scope isolate_scope(isolate);
+  DisableTurbofan();
+  if (DefaultSnapshotAvailable()) return;
+  v8::Isolate* isolate = Deserialize();
+  {
+    v8::HandleScope handle_scope(isolate);
+    v8::Isolate::Scope isolate_scope(isolate);
 
-      v8::Local<v8::Context> env = v8::Context::New(isolate);
-      env->Enter();
+    v8::Local<v8::Context> env = v8::Context::New(isolate);
+    env->Enter();
 
-      SanityCheck(isolate);
-    }
-    isolate->Dispose();
+    SanityCheck(isolate);
   }
+  isolate->Dispose();
 }
 
 
 UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerialization,
                              SerializeTwice) {
-  if (!Snapshot::HaveASnapshotToStartFrom()) {
-    v8::Isolate* isolate = Deserialize();
-    {
-      v8::Isolate::Scope isolate_scope(isolate);
-      v8::HandleScope handle_scope(isolate);
+  DisableTurbofan();
+  if (DefaultSnapshotAvailable()) return;
+  v8::Isolate* isolate = Deserialize();
+  {
+    v8::Isolate::Scope isolate_scope(isolate);
+    v8::HandleScope handle_scope(isolate);
 
-      v8::Local<v8::Context> env = v8::Context::New(isolate);
-      env->Enter();
+    v8::Local<v8::Context> env = v8::Context::New(isolate);
+    env->Enter();
 
-      SanityCheck(isolate);
-    }
-    isolate->Dispose();
+    SanityCheck(isolate);
   }
+  isolate->Dispose();
 }
 
 
 UNINITIALIZED_DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
-  if (!Snapshot::HaveASnapshotToStartFrom()) {
-    v8::Isolate* isolate = Deserialize();
-    {
-      v8::Isolate::Scope isolate_scope(isolate);
-      v8::HandleScope handle_scope(isolate);
+  DisableTurbofan();
+  if (DefaultSnapshotAvailable()) return;
+  v8::Isolate* isolate = Deserialize();
+  {
+    v8::Isolate::Scope isolate_scope(isolate);
+    v8::HandleScope handle_scope(isolate);
 
 
-      v8::Local<v8::Context> env = v8::Context::New(isolate);
-      env->Enter();
+    v8::Local<v8::Context> env = v8::Context::New(isolate);
+    env->Enter();
 
-      const char* c_source = "\"1234\".length";
-      v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
-      v8::Local<v8::Script> script = v8::Script::Compile(source);
-      CHECK_EQ(4, script->Run()->Int32Value());
-    }
-    isolate->Dispose();
+    const char* c_source = "\"1234\".length";
+    v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
+    v8::Local<v8::Script> script = v8::Script::Compile(source);
+    CHECK_EQ(4, script->Run()->Int32Value());
   }
+  isolate->Dispose();
 }
 
 
 UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
                              SerializeTwice) {
-  if (!Snapshot::HaveASnapshotToStartFrom()) {
-    v8::Isolate* isolate = Deserialize();
-    {
-      v8::Isolate::Scope isolate_scope(isolate);
-      v8::HandleScope handle_scope(isolate);
+  DisableTurbofan();
+  if (DefaultSnapshotAvailable()) return;
+  v8::Isolate* isolate = Deserialize();
+  {
+    v8::Isolate::Scope isolate_scope(isolate);
+    v8::HandleScope handle_scope(isolate);
 
-      v8::Local<v8::Context> env = v8::Context::New(isolate);
-      env->Enter();
+    v8::Local<v8::Context> env = v8::Context::New(isolate);
+    env->Enter();
 
-      const char* c_source = "\"1234\".length";
-      v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
-      v8::Local<v8::Script> script = v8::Script::Compile(source);
-      CHECK_EQ(4, script->Run()->Int32Value());
-    }
-    isolate->Dispose();
+    const char* c_source = "\"1234\".length";
+    v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source);
+    v8::Local<v8::Script> script = v8::Script::Compile(source);
+    CHECK_EQ(4, script->Run()->Int32Value());
   }
+  isolate->Dispose();
 }
 
 
 UNINITIALIZED_TEST(PartialSerialization) {
-  if (!Snapshot::HaveASnapshotToStartFrom()) {
-    v8::Isolate::CreateParams params;
-    params.enable_serializer = true;
-    v8::Isolate* v8_isolate = v8::Isolate::New(params);
-    Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
-    v8_isolate->Enter();
-    {
-      Heap* heap = isolate->heap();
+  DisableTurbofan();
+  if (DefaultSnapshotAvailable()) return;
+  v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true);
+  Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
+  v8_isolate->Enter();
+  {
+    Heap* heap = isolate->heap();
 
-      v8::Persistent<v8::Context> env;
-      {
-        HandleScope scope(isolate);
-        env.Reset(v8_isolate, v8::Context::New(v8_isolate));
-      }
-      DCHECK(!env.IsEmpty());
-      {
-        v8::HandleScope handle_scope(v8_isolate);
-        v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
-      }
-      // Make sure all builtin scripts are cached.
-      {
-        HandleScope scope(isolate);
-        for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
-          isolate->bootstrapper()->NativesSourceLookup(i);
-        }
-      }
-      heap->CollectAllGarbage(Heap::kNoGCFlags);
-      heap->CollectAllGarbage(Heap::kNoGCFlags);
-
-      Object* raw_foo;
-      {
-        v8::HandleScope handle_scope(v8_isolate);
-        v8::Local<v8::String> foo = v8::String::NewFromUtf8(v8_isolate, "foo");
-        DCHECK(!foo.IsEmpty());
-        raw_foo = *(v8::Utils::OpenHandle(*foo));
+    v8::Persistent<v8::Context> env;
+    {
+      HandleScope scope(isolate);
+      env.Reset(v8_isolate, v8::Context::New(v8_isolate));
+    }
+    DCHECK(!env.IsEmpty());
+    {
+      v8::HandleScope handle_scope(v8_isolate);
+      v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
+    }
+    // Make sure all builtin scripts are cached.
+    {
+      HandleScope scope(isolate);
+      for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
+        isolate->bootstrapper()->NativesSourceLookup(i);
       }
+    }
+    heap->CollectAllGarbage(Heap::kNoGCFlags);
+    heap->CollectAllGarbage(Heap::kNoGCFlags);
 
-      int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
-      Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
-      SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+    Object* raw_foo;
+    {
+      v8::HandleScope handle_scope(v8_isolate);
+      v8::Local<v8::String> foo = v8::String::NewFromUtf8(v8_isolate, "foo");
+      DCHECK(!foo.IsEmpty());
+      raw_foo = *(v8::Utils::OpenHandle(*foo));
+    }
 
-      {
-        v8::HandleScope handle_scope(v8_isolate);
-        v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
-      }
-      env.Reset();
+    int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
+    Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
+    SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
 
-      SnapshotByteSink startup_sink;
-      StartupSerializer startup_serializer(isolate, &startup_sink);
-      startup_serializer.SerializeStrongReferences();
+    {
+      v8::HandleScope handle_scope(v8_isolate);
+      v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
+    }
+    env.Reset();
 
-      SnapshotByteSink partial_sink;
-      PartialSerializer partial_serializer(isolate, &startup_serializer,
-                                           &partial_sink);
-      partial_serializer.Serialize(&raw_foo);
+    SnapshotByteSink startup_sink;
+    StartupSerializer startup_serializer(isolate, &startup_sink);
+    startup_serializer.SerializeStrongReferences();
 
-      startup_serializer.SerializeWeakReferences();
+    SnapshotByteSink partial_sink;
+    PartialSerializer partial_serializer(isolate, &startup_serializer,
+                                         &partial_sink);
+    partial_serializer.Serialize(&raw_foo);
 
-      SnapshotData startup_snapshot(startup_serializer);
-      SnapshotData partial_snapshot(partial_serializer);
+    startup_serializer.SerializeWeakReferences();
 
-      WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
-      WritePayload(startup_snapshot.RawData(), startup_name.start());
+    SnapshotData startup_snapshot(startup_serializer);
+    SnapshotData partial_snapshot(partial_serializer);
 
-      startup_name.Dispose();
-    }
-    v8_isolate->Exit();
-    v8_isolate->Dispose();
+    WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
+    WritePayload(startup_snapshot.RawData(), startup_name.start());
+
+    startup_name.Dispose();
   }
+  v8_isolate->Exit();
+  v8_isolate->Dispose();
 }
 
 
 UNINITIALIZED_DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
-  if (!Snapshot::HaveASnapshotToStartFrom()) {
-    int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
-    Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
-    SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+  DisableTurbofan();
+  if (DefaultSnapshotAvailable()) return;
+  int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
+  Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
+  SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+
+  v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
+  CHECK(v8_isolate);
+  startup_name.Dispose();
+  {
+    v8::Isolate::Scope isolate_scope(v8_isolate);
 
-    v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
-    CHECK(v8_isolate);
-    startup_name.Dispose();
+    const char* file_name = FLAG_testing_serialization_file;
+
+    int snapshot_size = 0;
+    byte* snapshot = ReadBytes(file_name, &snapshot_size);
+
+    Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
+    HandleScope handle_scope(isolate);
+    Handle<Object> root;
+    Handle<FixedArray> outdated_contexts;
+    // Intentionally empty handle. The deserializer should not come across
+    // any references to the global proxy in this test.
+    Handle<JSGlobalProxy> global_proxy = Handle<JSGlobalProxy>::null();
     {
-      v8::Isolate::Scope isolate_scope(v8_isolate);
-
-      const char* file_name = FLAG_testing_serialization_file;
-
-      int snapshot_size = 0;
-      byte* snapshot = ReadBytes(file_name, &snapshot_size);
-
-      Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
-      HandleScope handle_scope(isolate);
-      Handle<Object> root;
-      Handle<FixedArray> outdated_contexts;
-      // Intentionally empty handle. The deserializer should not come across
-      // any references to the global proxy in this test.
-      Handle<JSGlobalProxy> global_proxy = Handle<JSGlobalProxy>::null();
-      {
-        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
-        Deserializer deserializer(&snapshot_data);
-        root = deserializer.DeserializePartial(isolate, global_proxy,
-                                               &outdated_contexts)
-                   .ToHandleChecked();
-        CHECK_EQ(0, outdated_contexts->length());
-        CHECK(root->IsString());
-      }
+      SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+      Deserializer deserializer(&snapshot_data);
+      root =
+          deserializer.DeserializePartial(isolate, global_proxy,
+                                          &outdated_contexts).ToHandleChecked();
+      CHECK_EQ(0, outdated_contexts->length());
+      CHECK(root->IsString());
+    }
 
-      Handle<Object> root2;
-      {
-        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
-        Deserializer deserializer(&snapshot_data);
-        root2 = deserializer.DeserializePartial(isolate, global_proxy,
-                                                &outdated_contexts)
-                    .ToHandleChecked();
-        CHECK(root2->IsString());
-        CHECK(root.is_identical_to(root2));
-      }
+    Handle<Object> root2;
+    {
+      SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+      Deserializer deserializer(&snapshot_data);
+      root2 =
+          deserializer.DeserializePartial(isolate, global_proxy,
+                                          &outdated_contexts).ToHandleChecked();
+      CHECK(root2->IsString());
+      CHECK(root.is_identical_to(root2));
     }
-    v8_isolate->Dispose();
+
+    DeleteArray(snapshot);
   }
+  v8_isolate->Dispose();
 }
 
 
 UNINITIALIZED_TEST(ContextSerialization) {
-  if (!Snapshot::HaveASnapshotToStartFrom()) {
-    v8::Isolate::CreateParams params;
-    params.enable_serializer = true;
-    v8::Isolate* v8_isolate = v8::Isolate::New(params);
-    Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
-    Heap* heap = isolate->heap();
-    {
-      v8::Isolate::Scope isolate_scope(v8_isolate);
+  DisableTurbofan();
+  if (DefaultSnapshotAvailable()) return;
+  v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true);
+  Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
+  Heap* heap = isolate->heap();
+  {
+    v8::Isolate::Scope isolate_scope(v8_isolate);
 
-      v8::Persistent<v8::Context> env;
-      {
-        HandleScope scope(isolate);
-        env.Reset(v8_isolate, v8::Context::New(v8_isolate));
-      }
-      DCHECK(!env.IsEmpty());
-      {
-        v8::HandleScope handle_scope(v8_isolate);
-        v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
-      }
-      // Make sure all builtin scripts are cached.
-      {
-        HandleScope scope(isolate);
-        for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
-          isolate->bootstrapper()->NativesSourceLookup(i);
-        }
+    v8::Persistent<v8::Context> env;
+    {
+      HandleScope scope(isolate);
+      env.Reset(v8_isolate, v8::Context::New(v8_isolate));
+    }
+    DCHECK(!env.IsEmpty());
+    {
+      v8::HandleScope handle_scope(v8_isolate);
+      v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
+    }
+    // Make sure all builtin scripts are cached.
+    {
+      HandleScope scope(isolate);
+      for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
+        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 env.
-      heap->CollectAllGarbage(Heap::kNoGCFlags);
+    }
+    // If we don't do this then we end up with a stray root pointing at the
+    // context even after we have disposed of env.
+    heap->CollectAllGarbage(Heap::kNoGCFlags);
 
-      int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
-      Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
-      SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+    int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
+    Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
+    SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
 
-      {
-        v8::HandleScope handle_scope(v8_isolate);
-        v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
-      }
+    {
+      v8::HandleScope handle_scope(v8_isolate);
+      v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
+    }
 
-      i::Object* raw_context = *v8::Utils::OpenPersistent(env);
+    i::Object* raw_context = *v8::Utils::OpenPersistent(env);
 
-      env.Reset();
+    env.Reset();
 
-      SnapshotByteSink startup_sink;
-      StartupSerializer startup_serializer(isolate, &startup_sink);
-      startup_serializer.SerializeStrongReferences();
+    SnapshotByteSink startup_sink;
+    StartupSerializer startup_serializer(isolate, &startup_sink);
+    startup_serializer.SerializeStrongReferences();
 
-      SnapshotByteSink partial_sink;
-      PartialSerializer partial_serializer(isolate, &startup_serializer,
-                                           &partial_sink);
-      partial_serializer.Serialize(&raw_context);
-      startup_serializer.SerializeWeakReferences();
+    SnapshotByteSink partial_sink;
+    PartialSerializer partial_serializer(isolate, &startup_serializer,
+                                         &partial_sink);
+    partial_serializer.Serialize(&raw_context);
+    startup_serializer.SerializeWeakReferences();
 
-      SnapshotData startup_snapshot(startup_serializer);
-      SnapshotData partial_snapshot(partial_serializer);
+    SnapshotData startup_snapshot(startup_serializer);
+    SnapshotData partial_snapshot(partial_serializer);
 
-      WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
-      WritePayload(startup_snapshot.RawData(), startup_name.start());
+    WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
+    WritePayload(startup_snapshot.RawData(), startup_name.start());
 
-      startup_name.Dispose();
-    }
-    v8_isolate->Dispose();
+    startup_name.Dispose();
   }
+  v8_isolate->Dispose();
 }
 
 
 UNINITIALIZED_DEPENDENT_TEST(ContextDeserialization, ContextSerialization) {
-  if (!Snapshot::HaveASnapshotToStartFrom()) {
-    int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
-    Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
-    SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+  DisableTurbofan();
+  if (DefaultSnapshotAvailable()) return;
+  int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
+  Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
+  SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+
+  v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
+  CHECK(v8_isolate);
+  startup_name.Dispose();
+  {
+    v8::Isolate::Scope isolate_scope(v8_isolate);
 
-    v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
-    CHECK(v8_isolate);
-    startup_name.Dispose();
+    const char* file_name = FLAG_testing_serialization_file;
+
+    int snapshot_size = 0;
+    byte* snapshot = ReadBytes(file_name, &snapshot_size);
+
+    Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
+    HandleScope handle_scope(isolate);
+    Handle<Object> root;
+    Handle<FixedArray> outdated_contexts;
+    Handle<JSGlobalProxy> global_proxy =
+        isolate->factory()->NewUninitializedJSGlobalProxy();
     {
-      v8::Isolate::Scope isolate_scope(v8_isolate);
-
-      const char* file_name = FLAG_testing_serialization_file;
-
-      int snapshot_size = 0;
-      byte* snapshot = ReadBytes(file_name, &snapshot_size);
-
-      Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
-      HandleScope handle_scope(isolate);
-      Handle<Object> root;
-      Handle<FixedArray> outdated_contexts;
-      Handle<JSGlobalProxy> global_proxy =
-          isolate->factory()->NewUninitializedJSGlobalProxy();
-      {
-        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
-        Deserializer deserializer(&snapshot_data);
-        root = deserializer.DeserializePartial(isolate, global_proxy,
-                                               &outdated_contexts)
-                   .ToHandleChecked();
-        CHECK(root->IsContext());
-        CHECK(Handle<Context>::cast(root)->global_proxy() == *global_proxy);
-        CHECK_EQ(1, outdated_contexts->length());
-      }
+      SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+      Deserializer deserializer(&snapshot_data);
+      root =
+          deserializer.DeserializePartial(isolate, global_proxy,
+                                          &outdated_contexts).ToHandleChecked();
+      CHECK(root->IsContext());
+      CHECK(Handle<Context>::cast(root)->global_proxy() == *global_proxy);
+      CHECK_EQ(1, outdated_contexts->length());
+    }
 
-      Handle<Object> root2;
-      {
-        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
-        Deserializer deserializer(&snapshot_data);
-        root2 = deserializer.DeserializePartial(isolate, global_proxy,
-                                                &outdated_contexts)
-                    .ToHandleChecked();
-        CHECK(root2->IsContext());
-        CHECK(!root.is_identical_to(root2));
-      }
+    Handle<Object> root2;
+    {
+      SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+      Deserializer deserializer(&snapshot_data);
+      root2 =
+          deserializer.DeserializePartial(isolate, global_proxy,
+                                          &outdated_contexts).ToHandleChecked();
+      CHECK(root2->IsContext());
+      CHECK(!root.is_identical_to(root2));
     }
-    v8_isolate->Dispose();
+    DeleteArray(snapshot);
   }
+  v8_isolate->Dispose();
 }
 
 
 UNINITIALIZED_TEST(CustomContextSerialization) {
-  if (!Snapshot::HaveASnapshotToStartFrom()) {
-    v8::Isolate::CreateParams params;
-    params.enable_serializer = true;
-    v8::Isolate* v8_isolate = v8::Isolate::New(params);
-    Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
-    {
-      v8::Isolate::Scope isolate_scope(v8_isolate);
+  DisableTurbofan();
+  if (DefaultSnapshotAvailable()) return;
+  v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true);
+  Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
+  {
+    v8::Isolate::Scope isolate_scope(v8_isolate);
 
-      v8::Persistent<v8::Context> env;
-      {
-        HandleScope scope(isolate);
-        env.Reset(v8_isolate, v8::Context::New(v8_isolate));
-      }
-      DCHECK(!env.IsEmpty());
-      {
-        v8::HandleScope handle_scope(v8_isolate);
-        v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
-        // After execution, e's function context refers to the global object.
-        CompileRun(
-            "var e;"
-            "(function() {"
-            "  e = function(s) { return eval (s); }"
-            "})();"
-            "var o = this;"
-            "var r = Math.random() + Math.cos(0);"
-            "var f = (function(a, b) { return a + b; }).bind(1, 2, 3);"
-            "var s = parseInt('12345');");
-
-        Vector<const uint8_t> source = ConstructSource(
-            STATIC_CHAR_VECTOR("function g() { return [,"),
-            STATIC_CHAR_VECTOR("1,"),
-            STATIC_CHAR_VECTOR("];} a = g(); b = g(); b.push(1);"), 100000);
-        v8::Handle<v8::String> source_str = v8::String::NewFromOneByte(
-            v8_isolate, source.start(), v8::String::kNormalString,
-            source.length());
-        CompileRun(source_str);
-        source.Dispose();
-      }
-      // Make sure all builtin scripts are cached.
-      {
-        HandleScope scope(isolate);
-        for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
-          isolate->bootstrapper()->NativesSourceLookup(i);
-        }
+    v8::Persistent<v8::Context> env;
+    {
+      HandleScope scope(isolate);
+      env.Reset(v8_isolate, v8::Context::New(v8_isolate));
+    }
+    DCHECK(!env.IsEmpty());
+    {
+      v8::HandleScope handle_scope(v8_isolate);
+      v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
+      // After execution, e's function context refers to the global object.
+      CompileRun(
+          "var e;"
+          "(function() {"
+          "  e = function(s) { return eval (s); }"
+          "})();"
+          "var o = this;"
+          "var r = Math.random() + Math.cos(0);"
+          "var f = (function(a, b) { return a + b; }).bind(1, 2, 3);"
+          "var s = parseInt('12345');");
+
+      Vector<const uint8_t> source = ConstructSource(
+          STATIC_CHAR_VECTOR("function g() { return [,"),
+          STATIC_CHAR_VECTOR("1,"),
+          STATIC_CHAR_VECTOR("];} a = g(); b = g(); b.push(1);"), 100000);
+      v8::Handle<v8::String> source_str = v8::String::NewFromOneByte(
+          v8_isolate, source.start(), v8::String::kNormalString,
+          source.length());
+      CompileRun(source_str);
+      source.Dispose();
+    }
+    // Make sure all builtin scripts are cached.
+    {
+      HandleScope scope(isolate);
+      for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
+        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 env.
-      isolate->heap()->CollectAllAvailableGarbage("snapshotting");
+    }
+    // If we don't do this then we end up with a stray root pointing at the
+    // context even after we have disposed of env.
+    isolate->heap()->CollectAllAvailableGarbage("snapshotting");
 
-      int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
-      Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
-      SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+    int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
+    Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
+    SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
 
-      {
-        v8::HandleScope handle_scope(v8_isolate);
-        v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
-      }
+    {
+      v8::HandleScope handle_scope(v8_isolate);
+      v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
+    }
 
-      i::Object* raw_context = *v8::Utils::OpenPersistent(env);
+    i::Object* raw_context = *v8::Utils::OpenPersistent(env);
 
-      env.Reset();
+    env.Reset();
 
-      SnapshotByteSink startup_sink;
-      StartupSerializer startup_serializer(isolate, &startup_sink);
-      startup_serializer.SerializeStrongReferences();
+    SnapshotByteSink startup_sink;
+    StartupSerializer startup_serializer(isolate, &startup_sink);
+    startup_serializer.SerializeStrongReferences();
 
-      SnapshotByteSink partial_sink;
-      PartialSerializer partial_serializer(isolate, &startup_serializer,
-                                           &partial_sink);
-      partial_serializer.Serialize(&raw_context);
-      startup_serializer.SerializeWeakReferences();
+    SnapshotByteSink partial_sink;
+    PartialSerializer partial_serializer(isolate, &startup_serializer,
+                                         &partial_sink);
+    partial_serializer.Serialize(&raw_context);
+    startup_serializer.SerializeWeakReferences();
 
-      SnapshotData startup_snapshot(startup_serializer);
-      SnapshotData partial_snapshot(partial_serializer);
+    SnapshotData startup_snapshot(startup_serializer);
+    SnapshotData partial_snapshot(partial_serializer);
 
-      WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
-      WritePayload(startup_snapshot.RawData(), startup_name.start());
+    WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
+    WritePayload(startup_snapshot.RawData(), startup_name.start());
 
-      startup_name.Dispose();
-    }
-    v8_isolate->Dispose();
+    startup_name.Dispose();
   }
+  v8_isolate->Dispose();
 }
 
 
 UNINITIALIZED_DEPENDENT_TEST(CustomContextDeserialization,
                              CustomContextSerialization) {
+  DisableTurbofan();
   FLAG_crankshaft = false;
-  if (!Snapshot::HaveASnapshotToStartFrom()) {
-    int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
-    Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
-    SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+  if (DefaultSnapshotAvailable()) return;
+  int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
+  Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
+  SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
+
+  v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
+  CHECK(v8_isolate);
+  startup_name.Dispose();
+  {
+    v8::Isolate::Scope isolate_scope(v8_isolate);
 
-    v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start());
-    CHECK(v8_isolate);
-    startup_name.Dispose();
+    const char* file_name = FLAG_testing_serialization_file;
+
+    int snapshot_size = 0;
+    byte* snapshot = ReadBytes(file_name, &snapshot_size);
+
+    Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
+    HandleScope handle_scope(isolate);
+    Handle<Object> root;
+    Handle<FixedArray> outdated_contexts;
+    Handle<JSGlobalProxy> global_proxy =
+        isolate->factory()->NewUninitializedJSGlobalProxy();
     {
-      v8::Isolate::Scope isolate_scope(v8_isolate);
-
-      const char* file_name = FLAG_testing_serialization_file;
-
-      int snapshot_size = 0;
-      byte* snapshot = ReadBytes(file_name, &snapshot_size);
-
-      Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
-      HandleScope handle_scope(isolate);
-      Handle<Object> root;
-      Handle<FixedArray> outdated_contexts;
-      Handle<JSGlobalProxy> global_proxy =
-          isolate->factory()->NewUninitializedJSGlobalProxy();
-      {
-        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
-        Deserializer deserializer(&snapshot_data);
-        root = deserializer.DeserializePartial(isolate, global_proxy,
-                                               &outdated_contexts)
-                   .ToHandleChecked();
-        CHECK_EQ(2, outdated_contexts->length());
-        CHECK(root->IsContext());
-        Handle<Context> context = Handle<Context>::cast(root);
-        CHECK(context->global_proxy() == *global_proxy);
-        Handle<String> o = isolate->factory()->NewStringFromAsciiChecked("o");
-        Handle<JSObject> global_object(context->global_object(), isolate);
-        Handle<Object> property = JSObject::GetDataProperty(global_object, o);
-        CHECK(property.is_identical_to(global_proxy));
-
-        v8::Handle<v8::Context> v8_context = v8::Utils::ToLocal(context);
-        v8::Context::Scope context_scope(v8_context);
-        double r = CompileRun("r")->ToNumber(v8_isolate)->Value();
-        CHECK(r >= 1 && r <= 2);
-        int f = CompileRun("f()")->ToNumber(v8_isolate)->Int32Value();
-        CHECK_EQ(5, f);
-        f = CompileRun("e('f()')")->ToNumber(v8_isolate)->Int32Value();
-        CHECK_EQ(5, f);
-        v8::Handle<v8::String> s = CompileRun("s")->ToString(v8_isolate);
-        CHECK(s->Equals(v8_str("12345")));
-        int a = CompileRun("a.length")->ToNumber(v8_isolate)->Int32Value();
-        CHECK_EQ(100001, a);
-        int b = CompileRun("b.length")->ToNumber(v8_isolate)->Int32Value();
-        CHECK_EQ(100002, b);
-      }
+      SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+      Deserializer deserializer(&snapshot_data);
+      root =
+          deserializer.DeserializePartial(isolate, global_proxy,
+                                          &outdated_contexts).ToHandleChecked();
+      CHECK_EQ(2, outdated_contexts->length());
+      CHECK(root->IsContext());
+      Handle<Context> context = Handle<Context>::cast(root);
+      CHECK(context->global_proxy() == *global_proxy);
+      Handle<String> o = isolate->factory()->NewStringFromAsciiChecked("o");
+      Handle<JSObject> global_object(context->global_object(), isolate);
+      Handle<Object> property = JSObject::GetDataProperty(global_object, o);
+      CHECK(property.is_identical_to(global_proxy));
+
+      v8::Handle<v8::Context> v8_context = v8::Utils::ToLocal(context);
+      v8::Context::Scope context_scope(v8_context);
+      double r = CompileRun("r")->ToNumber(v8_isolate)->Value();
+      CHECK(r >= 1 && r <= 2);
+      int f = CompileRun("f()")->ToNumber(v8_isolate)->Int32Value();
+      CHECK_EQ(5, f);
+      f = CompileRun("e('f()')")->ToNumber(v8_isolate)->Int32Value();
+      CHECK_EQ(5, f);
+      v8::Handle<v8::String> s = CompileRun("s")->ToString(v8_isolate);
+      CHECK(s->Equals(v8_str("12345")));
+      int a = CompileRun("a.length")->ToNumber(v8_isolate)->Int32Value();
+      CHECK_EQ(100001, a);
+      int b = CompileRun("b.length")->ToNumber(v8_isolate)->Int32Value();
+      CHECK_EQ(100002, b);
     }
-    v8_isolate->Dispose();
+    DeleteArray(snapshot);
+  }
+  v8_isolate->Dispose();
+}
+
+
+TEST(PerIsolateSnapshotBlobs) {
+  DisableTurbofan();
+  const char* source1 = "function f() { return 42; }";
+  const char* source2 =
+      "function f() { return g() * 2; }"
+      "function g() { return 43; }"
+      "/./.test('a')";
+
+  v8::StartupData data1 = v8::V8::CreateSnapshotDataBlob(source1);
+  v8::StartupData data2 = v8::V8::CreateSnapshotDataBlob(source2);
+
+  v8::Isolate::CreateParams params1;
+  params1.snapshot_blob = &data1;
+  v8::Isolate* isolate1 = v8::Isolate::New(params1);
+  {
+    v8::Isolate::Scope i_scope(isolate1);
+    v8::HandleScope h_scope(isolate1);
+    v8::Local<v8::Context> context = v8::Context::New(isolate1);
+    delete[] data1.data;  // We can dispose of the snapshot blob now.
+    v8::Context::Scope c_scope(context);
+    CHECK_EQ(42, CompileRun("f()")->ToInt32(isolate1)->Int32Value());
+    CHECK(CompileRun("this.g")->IsUndefined());
+  }
+  isolate1->Dispose();
+
+  v8::Isolate::CreateParams params2;
+  params2.snapshot_blob = &data2;
+  v8::Isolate* isolate2 = v8::Isolate::New(params2);
+  {
+    v8::Isolate::Scope i_scope(isolate2);
+    v8::HandleScope h_scope(isolate2);
+    v8::Local<v8::Context> context = v8::Context::New(isolate2);
+    delete[] data2.data;  // We can dispose of the snapshot blob now.
+    v8::Context::Scope c_scope(context);
+    CHECK_EQ(86, CompileRun("f()")->ToInt32(isolate2)->Int32Value());
+    CHECK_EQ(43, CompileRun("g()")->ToInt32(isolate2)->Int32Value());
+  }
+  isolate2->Dispose();
+}
+
+
+TEST(PerIsolateSnapshotBlobsWithLocker) {
+  DisableTurbofan();
+  v8::Isolate* isolate0 = v8::Isolate::New();
+  {
+    v8::Locker locker(isolate0);
+    v8::Isolate::Scope i_scope(isolate0);
+    v8::HandleScope h_scope(isolate0);
+    v8::Local<v8::Context> context = v8::Context::New(isolate0);
+    v8::Context::Scope c_scope(context);
+    CHECK_EQ(1, CompileRun("Math.cos(0)")->ToInt32(isolate0)->Int32Value());
   }
+  isolate0->Dispose();
+
+  const char* source1 = "function f() { return 42; }";
+
+  v8::StartupData data1 = v8::V8::CreateSnapshotDataBlob(source1);
+
+  v8::Isolate::CreateParams params1;
+  params1.snapshot_blob = &data1;
+  v8::Isolate* isolate1 = v8::Isolate::New(params1);
+  {
+    v8::Locker locker(isolate1);
+    v8::Isolate::Scope i_scope(isolate1);
+    v8::HandleScope h_scope(isolate1);
+    v8::Local<v8::Context> context = v8::Context::New(isolate1);
+    delete[] data1.data;  // We can dispose of the snapshot blob now.
+    v8::Context::Scope c_scope(context);
+    CHECK_EQ(42, CompileRun("f()")->ToInt32(isolate1)->Int32Value());
+  }
+  isolate1->Dispose();
 }
 
 
@@ -735,10 +761,10 @@ int CountBuiltins() {
 static Handle<SharedFunctionInfo> CompileScript(
     Isolate* isolate, Handle<String> source, Handle<String> name,
     ScriptData** cached_data, v8::ScriptCompiler::CompileOptions options) {
-  return Compiler::CompileScript(source, name, 0, 0, false, false,
-                                 Handle<Context>(isolate->native_context()),
-                                 NULL, cached_data, options, NOT_NATIVES_CODE,
-                                 false);
+  return Compiler::CompileScript(
+      source, name, 0, 0, false, false, Handle<Object>(),
+      Handle<Context>(isolate->native_context()), NULL, cached_data, options,
+      NOT_NATIVES_CODE, false);
 }
 
 
@@ -1346,7 +1372,9 @@ TEST(SerializeToplevelFlagChange) {
   v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
 
   v8::Isolate* isolate2 = v8::Isolate::New();
+
   FLAG_allow_natives_syntax = true;  // Flag change should trigger cache reject.
+  FlagList::EnforceFlagImplications();
   {
     v8::Isolate::Scope iscope(isolate2);
     v8::HandleScope scope(isolate2);
@@ -1393,7 +1421,6 @@ TEST(SerializeToplevelBitFlip) {
 
 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'";
@@ -1454,3 +1481,71 @@ TEST(SerializeWithHarmonyScoping) {
   }
   isolate2->Dispose();
 }
+
+
+TEST(SerializeInternalReference) {
+#ifdef V8_TARGET_ARCH_ARM64
+  return;
+#endif  // V8_TARGET_ARCH_ARM64
+  // Disable experimental natives that are loaded after deserialization.
+  FLAG_turbo_deoptimization = false;
+  FLAG_context_specialization = false;
+  FLAG_always_opt = true;
+  const char* flag = "--turbo-filter=foo";
+  FlagList::SetFlagsFromString(flag, StrLength(flag));
+
+  const char* source =
+      "var foo = (function(stdlib, foreign, heap) {"
+      "  function foo(i) {"
+      "    i = i|0;"
+      "    var j = 0;"
+      "    switch (i) {"
+      "      case 0:"
+      "      case 1: j = 1; break;"
+      "      case 2:"
+      "      case 3: j = 2; break;"
+      "      case 4:"
+      "      case 5: j = foo(3) + 1; break;"
+      "      default: j = 0; break;"
+      "    }"
+      "    return j + 10;"
+      "  }"
+      "  return { foo: foo };"
+      "})(this, {}, undefined).foo;"
+      "foo(1);";
+
+  v8::StartupData data = v8::V8::CreateSnapshotDataBlob(source);
+  CHECK(data.data);
+
+  v8::Isolate::CreateParams params;
+  params.snapshot_blob = &data;
+  v8::Isolate* isolate = v8::Isolate::New(params);
+  {
+    v8::Isolate::Scope i_scope(isolate);
+    v8::HandleScope h_scope(isolate);
+    v8::Local<v8::Context> context = v8::Context::New(isolate);
+    delete[] data.data;  // We can dispose of the snapshot blob now.
+    v8::Context::Scope c_scope(context);
+    v8::Handle<v8::Function> foo =
+        v8::Handle<v8::Function>::Cast(CompileRun("foo"));
+
+    // There are at least 6 internal references.
+    int mask = RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
+               RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED);
+    RelocIterator it(v8::Utils::OpenHandle(*foo)->code(), mask);
+    for (int i = 0; i < 6; ++i) {
+      CHECK(!it.done());
+      it.next();
+    }
+
+    CHECK(v8::Utils::OpenHandle(*foo)->code()->is_turbofanned());
+    CHECK_EQ(11, CompileRun("foo(0)")->ToInt32(isolate)->Int32Value());
+    CHECK_EQ(11, CompileRun("foo(1)")->ToInt32(isolate)->Int32Value());
+    CHECK_EQ(12, CompileRun("foo(2)")->ToInt32(isolate)->Int32Value());
+    CHECK_EQ(12, CompileRun("foo(3)")->ToInt32(isolate)->Int32Value());
+    CHECK_EQ(23, CompileRun("foo(4)")->ToInt32(isolate)->Int32Value());
+    CHECK_EQ(23, CompileRun("foo(5)")->ToInt32(isolate)->Int32Value());
+    CHECK_EQ(10, CompileRun("foo(6)")->ToInt32(isolate)->Int32Value());
+  }
+  isolate->Dispose();
+}
index 331ea02..92305f9 100644 (file)
@@ -28,7 +28,7 @@
 #include <stdlib.h>
 
 #include "src/base/platform/platform.h"
-#include "src/snapshot.h"
+#include "src/snapshot/snapshot.h"
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
 
@@ -207,12 +207,13 @@ static void VerifyMemoryChunk(Isolate* isolate,
 TEST(Regress3540) {
   Isolate* isolate = CcTest::i_isolate();
   Heap* heap = isolate->heap();
+  const int pageSize = Page::kPageSize;
   MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
   CHECK(
       memory_allocator->SetUp(heap->MaxReserved(), heap->MaxExecutableSize()));
   TestMemoryAllocatorScope test_allocator_scope(isolate, memory_allocator);
   CodeRange* code_range = new CodeRange(isolate);
-  const size_t code_range_size = 4 * MB;
+  const size_t code_range_size = 4 * pageSize;
   if (!code_range->SetUp(
           code_range_size +
           RoundUp(v8::base::OS::CommitPageSize() * kReservedCodeRangePages,
@@ -222,13 +223,13 @@ TEST(Regress3540) {
   }
   Address address;
   size_t size;
-  address = code_range->AllocateRawMemory(code_range_size - 2 * MB,
-                                          code_range_size - 2 * MB, &size);
+  address = code_range->AllocateRawMemory(
+      code_range_size - 2 * pageSize, code_range_size - 2 * pageSize, &size);
   CHECK(address != NULL);
   Address null_address;
   size_t null_size;
   null_address = code_range->AllocateRawMemory(
-      code_range_size - MB, code_range_size - MB, &null_size);
+      code_range_size - pageSize, code_range_size - pageSize, &null_size);
   CHECK(null_address == NULL);
   code_range->FreeRawMemory(address, size);
   delete code_range;
@@ -307,9 +308,7 @@ TEST(MemoryAllocator) {
                                 heap->MaxExecutableSize()));
 
   int total_pages = 0;
-  OldSpace faked_space(heap,
-                       heap->MaxReserved(),
-                       OLD_POINTER_SPACE,
+  OldSpace faked_space(heap, heap->MaxReserved(), OLD_POINTER_SPACE,
                        NOT_EXECUTABLE);
   Page* first_page = memory_allocator->AllocatePage(
       faked_space.AreaSize(), &faked_space, NOT_EXECUTABLE);
@@ -379,10 +378,8 @@ TEST(OldSpace) {
                                 heap->MaxExecutableSize()));
   TestMemoryAllocatorScope test_scope(isolate, memory_allocator);
 
-  OldSpace* s = new OldSpace(heap,
-                             heap->MaxOldGenerationSize(),
-                             OLD_POINTER_SPACE,
-                             NOT_EXECUTABLE);
+  OldSpace* s = new OldSpace(heap, heap->MaxOldGenerationSize(),
+                             OLD_POINTER_SPACE, NOT_EXECUTABLE);
   CHECK(s != NULL);
 
   CHECK(s->SetUp());
@@ -422,7 +419,9 @@ TEST(LargeObjectSpace) {
     { AllocationResult allocation = lo->AllocateRaw(lo_size, NOT_EXECUTABLE);
       if (allocation.IsRetry()) break;
     }
-    CHECK(lo->Available() < available);
+    // The available value is conservative such that it may report
+    // zero prior to heap exhaustion.
+    CHECK(lo->Available() < available || available == 0);
   }
 
   CHECK(!lo->IsEmpty());
@@ -434,9 +433,10 @@ TEST(LargeObjectSpace) {
 TEST(SizeOfFirstPageIsLargeEnough) {
   if (i::FLAG_always_opt) return;
   // Bootstrapping without a snapshot causes more allocations.
-  if (!i::Snapshot::HaveASnapshotToStartFrom()) return;
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
+  if (!isolate->snapshot_available()) return;
+  if (Snapshot::EmbedsScript(isolate)) return;
 
   // Freshly initialized VM gets by with one page per space.
   for (int i = FIRST_PAGED_SPACE; i <= LAST_PAGED_SPACE; i++) {
@@ -460,7 +460,7 @@ TEST(SizeOfFirstPageIsLargeEnough) {
 
 
 UNINITIALIZED_TEST(NewSpaceGrowsToTargetCapacity) {
-  FLAG_target_semi_space_size = 2;
+  FLAG_target_semi_space_size = 2 * (Page::kPageSize / MB);
   if (FLAG_optimize_for_size) return;
 
   v8::Isolate* isolate = v8::Isolate::New();
index 9a4e96f..8d5129c 100644 (file)
@@ -1209,7 +1209,7 @@ UNINITIALIZED_TEST(OneByteArrayJoin) {
   v8::Isolate::CreateParams create_params;
   // Set heap limits.
   create_params.constraints.set_max_semi_space_size(1);
-  create_params.constraints.set_max_old_space_size(5);
+  create_params.constraints.set_max_old_space_size(6);
   v8::Isolate* isolate = v8::Isolate::New(create_params);
   isolate->Enter();
 
index d31b413..0d20e0f 100644 (file)
@@ -192,6 +192,7 @@ TEST(TerminateOnlyV8ThreadFromOtherThread) {
   // Run a loop that will be infinite if thread termination does not work.
   v8::Handle<v8::String> source = v8::String::NewFromUtf8(
       CcTest::isolate(), "try { loop(); fail(); } catch(e) { fail(); }");
+  i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
   v8::Script::Compile(source)->Run();
 
   thread.Join();
@@ -228,6 +229,7 @@ void LoopGetProperty(const v8::FunctionCallbackInfo<v8::Value>& args) {
                               "    }"
                               "    fail();"
                               "  } catch(e) {"
+                              "    (function() {})();"  // trigger stack check.
                               "    fail();"
                               "  }"
                               "}"
@@ -375,6 +377,7 @@ void MicrotaskLoopForever(const v8::FunctionCallbackInfo<v8::Value>& info) {
   // Enqueue another should-not-run task to ensure we clean out the queue
   // when we terminate.
   isolate->EnqueueMicrotask(v8::Function::New(isolate, MicrotaskShouldNotRun));
+  i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
   CompileRun("terminate(); while (true) { }");
   CHECK(v8::V8::IsExecutionTerminating());
 }
@@ -474,3 +477,65 @@ TEST(ErrorObjectAfterTermination) {
   // TODO(yangguo): crbug/403509. Check for empty handle instead.
   CHECK(error->IsUndefined());
 }
+
+
+void InnerTryCallTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
+  CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
+  v8::Handle<v8::Object> global = CcTest::global();
+  v8::Handle<v8::Function> loop =
+      v8::Handle<v8::Function>::Cast(global->Get(v8_str("loop")));
+  i::MaybeHandle<i::Object> result =
+      i::Execution::TryCall(v8::Utils::OpenHandle((*loop)),
+                            v8::Utils::OpenHandle((*global)), 0, NULL, NULL);
+  CHECK(result.is_null());
+  // TryCall ignores terminate execution, but rerequests the interrupt.
+  CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
+  CHECK(CompileRun("1 + 1;").IsEmpty());
+}
+
+
+TEST(TerminationInInnerTryCall) {
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  v8::Handle<v8::ObjectTemplate> global_template = CreateGlobalTemplate(
+      CcTest::isolate(), TerminateCurrentThread, DoLoopNoCall);
+  global_template->Set(
+      v8_str("inner_try_call_terminate"),
+      v8::FunctionTemplate::New(isolate, InnerTryCallTerminate));
+  v8::Handle<v8::Context> context =
+      v8::Context::New(CcTest::isolate(), NULL, global_template);
+  v8::Context::Scope context_scope(context);
+  {
+    v8::TryCatch try_catch;
+    CompileRun("inner_try_call_terminate()");
+    CHECK(try_catch.HasTerminated());
+  }
+  CHECK_EQ(4, CompileRun("2 + 2")->ToInt32()->Int32Value());
+  CHECK(!v8::V8::IsExecutionTerminating());
+}
+
+
+TEST(TerminateAndTryCall) {
+  i::FLAG_allow_natives_syntax = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  v8::Handle<v8::ObjectTemplate> global = CreateGlobalTemplate(
+      isolate, TerminateCurrentThread, DoLoopCancelTerminate);
+  v8::Handle<v8::Context> context = v8::Context::New(isolate, NULL, global);
+  v8::Context::Scope context_scope(context);
+  CHECK(!v8::V8::IsExecutionTerminating(isolate));
+  v8::TryCatch try_catch;
+  CHECK(!v8::V8::IsExecutionTerminating(isolate));
+  // Terminate execution has been triggered inside TryCall, but re-requested
+  // to trigger later.
+  CHECK(CompileRun("terminate(); reference_error();").IsEmpty());
+  CHECK(try_catch.HasCaught());
+  CHECK(!v8::V8::IsExecutionTerminating(isolate));
+  CHECK(CcTest::global()->Get(v8_str("terminate"))->IsFunction());
+  // The first stack check after terminate has been re-requested fails.
+  CHECK(CompileRun("1 + 1").IsEmpty());
+  CHECK(!v8::V8::IsExecutionTerminating(isolate));
+  // V8 then recovers.
+  CHECK_EQ(4, CompileRun("2 + 2")->ToInt32()->Int32Value());
+  CHECK(!v8::V8::IsExecutionTerminating(isolate));
+}
index 59c9f74..800c2a0 100644 (file)
@@ -20,16 +20,6 @@ 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) {
@@ -69,34 +59,32 @@ TEST(TransitionArray_SimpleFieldTransitions) {
                          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(kData, *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(kData, *name1, attributes);
-  CHECK_EQ(*name1, transitions->GetKey(transition));
-  CHECK_EQ(*map1, transitions->GetTarget(transition));
-
-  transition = transitions->Search(kData, *name2, attributes);
-  CHECK_EQ(*name2, transitions->GetKey(transition));
-  CHECK_EQ(*map2, transitions->GetTarget(transition));
-
-  DCHECK(transitions->IsSortedNoDuplicates());
+  CHECK(map0->raw_transitions()->IsSmi());
+
+  TransitionArray::Insert(map0, name1, map1, SIMPLE_PROPERTY_TRANSITION);
+  CHECK(TransitionArray::IsSimpleTransition(map0->raw_transitions()));
+  CHECK_EQ(*map1,
+           TransitionArray::SearchTransition(*map0, kData, *name1, attributes));
+  CHECK_EQ(1, TransitionArray::NumberOfTransitions(map0->raw_transitions()));
+  CHECK_EQ(*name1, TransitionArray::GetKey(map0->raw_transitions(), 0));
+  CHECK_EQ(*map1, TransitionArray::GetTarget(map0->raw_transitions(), 0));
+
+  TransitionArray::Insert(map0, name2, map2, SIMPLE_PROPERTY_TRANSITION);
+  CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions()));
+
+  CHECK_EQ(*map1,
+           TransitionArray::SearchTransition(*map0, kData, *name1, attributes));
+  CHECK_EQ(*map2,
+           TransitionArray::SearchTransition(*map0, kData, *name2, attributes));
+  CHECK_EQ(2, TransitionArray::NumberOfTransitions(map0->raw_transitions()));
+  for (int i = 0; i < 2; i++) {
+    Name* key = TransitionArray::GetKey(map0->raw_transitions(), i);
+    Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i);
+    CHECK((key == *name1 && target == *map1) ||
+          (key == *name2 && target == *map2));
+  }
+
+  DCHECK(TransitionArray::IsSortedNoDuplicates(*map0));
 }
 
 
@@ -120,31 +108,32 @@ TEST(TransitionArray_FullFieldTransitions) {
                          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(kData, *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(kData, *name1, attributes);
-  CHECK_EQ(*name1, transitions->GetKey(transition));
-  CHECK_EQ(*map1, transitions->GetTarget(transition));
-
-  transition = transitions->Search(kData, *name2, attributes);
-  CHECK_EQ(*name2, transitions->GetKey(transition));
-  CHECK_EQ(*map2, transitions->GetTarget(transition));
+  CHECK(map0->raw_transitions()->IsSmi());
+
+  TransitionArray::Insert(map0, name1, map1, PROPERTY_TRANSITION);
+  CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions()));
+  CHECK_EQ(*map1,
+           TransitionArray::SearchTransition(*map0, kData, *name1, attributes));
+  CHECK_EQ(1, TransitionArray::NumberOfTransitions(map0->raw_transitions()));
+  CHECK_EQ(*name1, TransitionArray::GetKey(map0->raw_transitions(), 0));
+  CHECK_EQ(*map1, TransitionArray::GetTarget(map0->raw_transitions(), 0));
+
+  TransitionArray::Insert(map0, name2, map2, PROPERTY_TRANSITION);
+  CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions()));
+
+  CHECK_EQ(*map1,
+           TransitionArray::SearchTransition(*map0, kData, *name1, attributes));
+  CHECK_EQ(*map2,
+           TransitionArray::SearchTransition(*map0, kData, *name2, attributes));
+  CHECK_EQ(2, TransitionArray::NumberOfTransitions(map0->raw_transitions()));
+  for (int i = 0; i < 2; i++) {
+    Name* key = TransitionArray::GetKey(map0->raw_transitions(), i);
+    Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i);
+    CHECK((key == *name1 && target == *map1) ||
+          (key == *name2 && target == *map2));
+  }
 
-  DCHECK(transitions->IsSortedNoDuplicates());
+  DCHECK(TransitionArray::IsSortedNoDuplicates(*map0));
 }
 
 
@@ -160,9 +149,7 @@ TEST(TransitionArray_DifferentFieldNames) {
   PropertyAttributes attributes = NONE;
 
   Handle<Map> map0 = Map::Create(isolate, 0);
-  CHECK(!map0->HasTransitionArray());
-  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
-  CHECK(transitions->IsFullTransitionArray());
+  CHECK(map0->raw_transitions()->IsSmi());
 
   for (int i = 0; i < PROPS_COUNT; i++) {
     EmbeddedVector<char, 64> buffer;
@@ -175,17 +162,25 @@ TEST(TransitionArray_DifferentFieldNames) {
     names[i] = name;
     maps[i] = map;
 
-    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
-    ConnectTransition(map0, transitions, map);
+    TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
   }
 
   for (int i = 0; i < PROPS_COUNT; i++) {
-    int transition = transitions->Search(kData, *names[i], attributes);
-    CHECK_EQ(*names[i], transitions->GetKey(transition));
-    CHECK_EQ(*maps[i], transitions->GetTarget(transition));
+    CHECK_EQ(*maps[i], TransitionArray::SearchTransition(
+                           *map0, kData, *names[i], attributes));
+  }
+  for (int i = 0; i < PROPS_COUNT; i++) {
+    Name* key = TransitionArray::GetKey(map0->raw_transitions(), i);
+    Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i);
+    for (int j = 0; j < PROPS_COUNT; j++) {
+      if (*names[i] == key) {
+        CHECK_EQ(*maps[i], target);
+        break;
+      }
+    }
   }
 
-  DCHECK(transitions->IsSortedNoDuplicates());
+  DCHECK(TransitionArray::IsSortedNoDuplicates(*map0));
 }
 
 
@@ -196,9 +191,7 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) {
   Factory* factory = isolate->factory();
 
   Handle<Map> map0 = Map::Create(isolate, 0);
-  CHECK(!map0->HasTransitionArray());
-  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
-  CHECK(transitions->IsFullTransitionArray());
+  CHECK(map0->raw_transitions()->IsSmi());
 
   const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
   STATIC_ASSERT(ATTRS_COUNT == 8);
@@ -215,20 +208,20 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) {
                            OMIT_TRANSITION).ToHandleChecked();
     attr_maps[i] = map;
 
-    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
-    ConnectTransition(map0, transitions, map);
+    TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
   }
 
   // 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(kData, *name, attributes);
-    CHECK_EQ(*name, transitions->GetKey(transition));
-    CHECK_EQ(*attr_maps[i], transitions->GetTarget(transition));
+    CHECK_EQ(*attr_maps[i], TransitionArray::SearchTransition(
+                                *map0, kData, *name, attributes));
+    // All transitions use the same key, so this check doesn't need to
+    // care about ordering.
+    CHECK_EQ(*name, TransitionArray::GetKey(map0->raw_transitions(), i));
   }
 
-  DCHECK(transitions->IsSortedNoDuplicates());
+  DCHECK(TransitionArray::IsSortedNoDuplicates(*map0));
 }
 
 
@@ -243,9 +236,7 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
   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());
+  CHECK(map0->raw_transitions()->IsSmi());
 
   // Some number of fields.
   for (int i = 0; i < PROPS_COUNT; i++) {
@@ -259,8 +250,7 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
     names[i] = name;
     maps[i] = map;
 
-    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
-    ConnectTransition(map0, transitions, map);
+    TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
   }
 
   const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
@@ -278,25 +268,36 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
                            OMIT_TRANSITION).ToHandleChecked();
     attr_maps[i] = map;
 
-    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
-    ConnectTransition(map0, transitions, map);
+    TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
   }
 
   // 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(kData, *name, attributes);
-    CHECK_EQ(*name, transitions->GetKey(transition));
-    CHECK_EQ(*attr_maps[i], transitions->GetTarget(transition));
+    PropertyAttributes attr = static_cast<PropertyAttributes>(i);
+    CHECK_EQ(*attr_maps[i],
+             TransitionArray::SearchTransition(*map0, kData, *name, attr));
   }
 
   // Ensure that info about the other fields still valid.
-  for (int i = 0; i < PROPS_COUNT; i++) {
-    int transition = transitions->Search(kData, *names[i], NONE);
-    CHECK_EQ(*names[i], transitions->GetKey(transition));
-    CHECK_EQ(*maps[i], transitions->GetTarget(transition));
+  CHECK_EQ(PROPS_COUNT + ATTRS_COUNT,
+           TransitionArray::NumberOfTransitions(map0->raw_transitions()));
+  for (int i = 0; i < PROPS_COUNT + ATTRS_COUNT; i++) {
+    Name* key = TransitionArray::GetKey(map0->raw_transitions(), i);
+    Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i);
+    if (key == *name) {
+      // Attributes transition.
+      PropertyAttributes attributes =
+          target->GetLastDescriptorDetails().attributes();
+      CHECK_EQ(*attr_maps[static_cast<int>(attributes)], target);
+    } else {
+      for (int j = 0; j < PROPS_COUNT; j++) {
+        if (*names[j] == key) {
+          CHECK_EQ(*maps[j], target);
+          break;
+        }
+      }
+    }
   }
 
-  DCHECK(transitions->IsSortedNoDuplicates());
+  DCHECK(TransitionArray::IsSortedNoDuplicates(*map0));
 }
diff --git a/deps/v8/test/cctest/test-typedarrays.cc b/deps/v8/test/cctest/test-typedarrays.cc
new file mode 100644 (file)
index 0000000..d031048
--- /dev/null
@@ -0,0 +1,81 @@
+// 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.
+
+#include <stdlib.h>
+
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/api.h"
+#include "src/heap/heap.h"
+#include "src/objects.h"
+#include "src/v8.h"
+
+using namespace v8::internal;
+
+void TestArrayBufferViewContents(LocalContext& env, bool should_use_buffer) {
+  v8::Local<v8::Object> obj_a =
+      v8::Local<v8::Object>::Cast(env->Global()->Get(v8_str("a")));
+  CHECK(obj_a->IsArrayBufferView());
+  v8::Local<v8::ArrayBufferView> array_buffer_view =
+      v8::Local<v8::ArrayBufferView>::Cast(obj_a);
+  CHECK_EQ(array_buffer_view->HasBuffer(), should_use_buffer);
+  unsigned char contents[4] = {23, 23, 23, 23};
+  CHECK_EQ(sizeof(contents),
+           array_buffer_view->CopyContents(contents, sizeof(contents)));
+  CHECK_EQ(array_buffer_view->HasBuffer(), should_use_buffer);
+  for (size_t i = 0; i < sizeof(contents); ++i) {
+    CHECK_EQ(i, contents[i]);
+  }
+}
+
+
+TEST(CopyContentsTypedArray) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+  CompileRun(
+      "var a = new Uint8Array(4);"
+      "a[0] = 0;"
+      "a[1] = 1;"
+      "a[2] = 2;"
+      "a[3] = 3;");
+  TestArrayBufferViewContents(env, false);
+}
+
+
+TEST(CopyContentsArray) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+  CompileRun("var a = new Uint8Array([0, 1, 2, 3]);");
+  TestArrayBufferViewContents(env, true);
+}
+
+
+TEST(CopyContentsView) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+  CompileRun(
+      "var b = new ArrayBuffer(6);"
+      "var c = new Uint8Array(b);"
+      "c[0] = -1;"
+      "c[1] = -1;"
+      "c[2] = 0;"
+      "c[3] = 1;"
+      "c[4] = 2;"
+      "c[5] = 3;"
+      "var a = new DataView(b, 2);");
+  TestArrayBufferViewContents(env, true);
+}
+
+
+TEST(AllocateNotExternal) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+  void* memory = V8::ArrayBufferAllocator()->Allocate(1024);
+  v8::Local<v8::ArrayBuffer> buffer =
+      v8::ArrayBuffer::New(env->GetIsolate(), memory, 1024,
+                           v8::ArrayBufferCreationMode::kInternalized);
+  CHECK(!buffer->IsExternal());
+  CHECK_EQ(memory, buffer->GetContents().Data());
+}
index fdcac3a..05c13e5 100644 (file)
@@ -18,7 +18,7 @@
 using namespace v8::base;
 using namespace v8::internal;
 
-#if (V8_DOUBLE_FIELDS_UNBOXING)
+#if V8_DOUBLE_FIELDS_UNBOXING
 
 
 //
@@ -30,7 +30,7 @@ static void InitializeVerifiedMapDescriptors(
     Map* map, DescriptorArray* descriptors,
     LayoutDescriptor* layout_descriptor) {
   map->InitializeDescriptors(descriptors, layout_descriptor);
-  CHECK(layout_descriptor->IsConsistentWithMap(map));
+  CHECK(layout_descriptor->IsConsistentWithMap(map, true));
 }
 
 
@@ -48,6 +48,12 @@ static Handle<String> MakeName(const char* str, int suffix) {
 }
 
 
+Handle<JSObject> GetObject(const char* name) {
+  return v8::Utils::OpenHandle(
+      *v8::Handle<v8::Object>::Cast(CcTest::global()->Get(v8_str(name))));
+}
+
+
 static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) {
   if (obj->IsUnboxedDoubleField(field_index)) {
     return obj->RawFastDoublePropertyAt(field_index);
@@ -224,7 +230,7 @@ TEST(LayoutDescriptorBasicSlow) {
     }
     CHECK(layout_desc->IsSlowLayout());
     CHECK(!layout_desc->IsFastPointerLayout());
-    CHECK(layout_descriptor->IsConsistentWithMap(*map));
+    CHECK(layout_descriptor->IsConsistentWithMap(*map, true));
   }
 }
 
@@ -638,7 +644,7 @@ static Handle<LayoutDescriptor> TestLayoutDescriptorAppend(
     map->InitializeDescriptors(*descriptors, *layout_descriptor);
   }
   Handle<LayoutDescriptor> layout_descriptor(map->layout_descriptor(), isolate);
-  CHECK(layout_descriptor->IsConsistentWithMap(*map));
+  CHECK(layout_descriptor->IsConsistentWithMap(*map, true));
   return layout_descriptor;
 }
 
@@ -907,42 +913,126 @@ TEST(Regress436816) {
 }
 
 
+TEST(DescriptorArrayTrimming) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+
+  const int kFieldCount = 128;
+  const int kSplitFieldIndex = 32;
+  const int kTrimmedLayoutDescriptorLength = 64;
+
+  Handle<HeapType> any_type = HeapType::Any(isolate);
+  Handle<Map> map = Map::Create(isolate, kFieldCount);
+  for (int i = 0; i < kSplitFieldIndex; i++) {
+    map = Map::CopyWithField(map, MakeName("prop", i), any_type, NONE,
+                             Representation::Smi(),
+                             INSERT_TRANSITION).ToHandleChecked();
+  }
+  map = Map::CopyWithField(map, MakeName("dbl", kSplitFieldIndex), any_type,
+                           NONE, Representation::Double(),
+                           INSERT_TRANSITION).ToHandleChecked();
+  CHECK(map->layout_descriptor()->IsConsistentWithMap(*map, true));
+  CHECK(map->layout_descriptor()->IsSlowLayout());
+  CHECK(map->owns_descriptors());
+  CHECK_EQ(2, map->layout_descriptor()->length());
+
+  {
+    // Add transitions to double fields.
+    v8::HandleScope scope(CcTest::isolate());
+
+    Handle<Map> tmp_map = map;
+    for (int i = kSplitFieldIndex + 1; i < kFieldCount; i++) {
+      tmp_map = Map::CopyWithField(tmp_map, MakeName("dbl", i), any_type, NONE,
+                                   Representation::Double(),
+                                   INSERT_TRANSITION).ToHandleChecked();
+      CHECK(tmp_map->layout_descriptor()->IsConsistentWithMap(*tmp_map, true));
+    }
+    // Check that descriptors are shared.
+    CHECK(tmp_map->owns_descriptors());
+    CHECK_EQ(map->instance_descriptors(), tmp_map->instance_descriptors());
+    CHECK_EQ(map->layout_descriptor(), tmp_map->layout_descriptor());
+  }
+  CHECK(map->layout_descriptor()->IsSlowLayout());
+  CHECK_EQ(4, map->layout_descriptor()->length());
+
+  // The unused tail of the layout descriptor is now "durty" because of sharing.
+  CHECK(map->layout_descriptor()->IsConsistentWithMap(*map));
+  for (int i = kSplitFieldIndex + 1; i < kTrimmedLayoutDescriptorLength; i++) {
+    CHECK(!map->layout_descriptor()->IsTagged(i));
+  }
+  CHECK_LT(map->NumberOfOwnDescriptors(),
+           map->instance_descriptors()->number_of_descriptors());
+
+  // Call GC that should trim both |map|'s descriptor array and layout
+  // descriptor.
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+
+  // The unused tail of the layout descriptor is now "clean" again.
+  CHECK(map->layout_descriptor()->IsConsistentWithMap(*map, true));
+  CHECK(map->owns_descriptors());
+  CHECK_EQ(map->NumberOfOwnDescriptors(),
+           map->instance_descriptors()->number_of_descriptors());
+  CHECK(map->layout_descriptor()->IsSlowLayout());
+  CHECK_EQ(2, map->layout_descriptor()->length());
+
+  {
+    // Add transitions to tagged fields.
+    v8::HandleScope scope(CcTest::isolate());
+
+    Handle<Map> tmp_map = map;
+    for (int i = kSplitFieldIndex + 1; i < kFieldCount - 1; i++) {
+      tmp_map = Map::CopyWithField(tmp_map, MakeName("tagged", i), any_type,
+                                   NONE, Representation::Tagged(),
+                                   INSERT_TRANSITION).ToHandleChecked();
+      CHECK(tmp_map->layout_descriptor()->IsConsistentWithMap(*tmp_map, true));
+    }
+    tmp_map = Map::CopyWithField(tmp_map, MakeString("dbl"), any_type, NONE,
+                                 Representation::Double(),
+                                 INSERT_TRANSITION).ToHandleChecked();
+    CHECK(tmp_map->layout_descriptor()->IsConsistentWithMap(*tmp_map, true));
+    // Check that descriptors are shared.
+    CHECK(tmp_map->owns_descriptors());
+    CHECK_EQ(map->instance_descriptors(), tmp_map->instance_descriptors());
+  }
+  CHECK(map->layout_descriptor()->IsSlowLayout());
+}
+
+
 TEST(DoScavenge) {
   CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   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();");
+  // The plan: create |obj| with double field in new space, do scanvenge so
+  // that |obj| is moved to old space, construct a double value that looks like
+  // a pointer to "from space" pointer. Do scavenge one more time and ensure
+  // that it didn't crash or corrupt the double value stored in the object.
 
-  Handle<String> obj_name = factory->InternalizeUtf8String("o");
+  Handle<HeapType> any_type = HeapType::Any(isolate);
+  Handle<Map> map = Map::Create(isolate, 10);
+  map = Map::CopyWithField(map, MakeName("prop", 0), any_type, NONE,
+                           Representation::Double(),
+                           INSERT_TRANSITION).ToHandleChecked();
 
-  Handle<Object> obj_value =
-      Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked();
-  CHECK(obj_value->IsJSObject());
-  Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
+  // Create object in new space.
+  Handle<JSObject> obj = factory->NewJSObjectFromMap(map, NOT_TENURED, false);
+
+  Handle<HeapNumber> heap_number = factory->NewHeapNumber(42.5);
+  obj->WriteToField(0, *heap_number);
 
   {
     // 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);
+    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
+  // Do scavenge so that |obj| is moved to survivor space.
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);
 
   // Create temp object in the new space.
   Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED);
@@ -957,9 +1047,9 @@ TEST(DoScavenge) {
   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
+  // Now |obj| 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
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE, "boom");
 
   CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
 
@@ -967,6 +1057,96 @@ TEST(DoScavenge) {
 }
 
 
+TEST(DoScavengeWithIncrementalWriteBarrier) {
+  if (FLAG_never_compact || !FLAG_incremental_marking) return;
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  Heap* heap = CcTest::heap();
+  PagedSpace* old_pointer_space = heap->old_pointer_space();
+
+  // The plan: create |obj_value| in old space and ensure that it is allocated
+  // on evacuation candidate page, create |obj| with double and tagged fields
+  // in new space and write |obj_value| to tagged field of |obj|, do two
+  // scavenges to promote |obj| to old space, a GC in old space and ensure that
+  // the tagged value was properly updated after candidates evacuation.
+
+  Handle<HeapType> any_type = HeapType::Any(isolate);
+  Handle<Map> map = Map::Create(isolate, 10);
+  map = Map::CopyWithField(map, MakeName("prop", 0), any_type, NONE,
+                           Representation::Double(),
+                           INSERT_TRANSITION).ToHandleChecked();
+  map = Map::CopyWithField(map, MakeName("prop", 1), any_type, NONE,
+                           Representation::Tagged(),
+                           INSERT_TRANSITION).ToHandleChecked();
+
+  // Create |obj_value| in old space.
+  Handle<HeapObject> obj_value;
+  Page* ec_page;
+  {
+    AlwaysAllocateScope always_allocate(isolate);
+    // Make sure |obj_value| is placed on an old-space evacuation candidate.
+    SimulateFullSpace(old_pointer_space);
+    obj_value = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
+    ec_page = Page::FromAddress(obj_value->address());
+  }
+
+  // Create object in new space.
+  Handle<JSObject> obj = factory->NewJSObjectFromMap(map, NOT_TENURED, false);
+
+  Handle<HeapNumber> heap_number = factory->NewHeapNumber(42.5);
+  obj->WriteToField(0, *heap_number);
+  obj->WriteToField(1, *obj_value);
+
+  {
+    // Ensure the object is properly set up.
+    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));
+
+    field_index = FieldIndex::ForDescriptor(*map, 1);
+    CHECK(field_index.is_inobject() && !field_index.is_double());
+    CHECK(!map->IsUnboxedDoubleField(field_index));
+  }
+  CHECK(isolate->heap()->new_space()->Contains(*obj));
+
+  // Heap is ready, force |ec_page| to become an evacuation candidate and
+  // simulate incremental marking.
+  FLAG_stress_compaction = true;
+  FLAG_manual_evacuation_candidates_selection = true;
+  ec_page->SetFlag(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING);
+  SimulateIncrementalMarking(heap);
+  // Disable stress compaction mode in order to let GC do scavenge.
+  FLAG_stress_compaction = false;
+
+  // Check that everything is ready for triggering incremental write barrier
+  // during scavenge (i.e. that |obj| is black and incremental marking is
+  // in compacting mode and |obj_value|'s page is an evacuation candidate).
+  IncrementalMarking* marking = heap->incremental_marking();
+  CHECK(marking->IsCompacting());
+  CHECK(Marking::IsBlack(Marking::MarkBitFrom(*obj)));
+  CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
+
+  // Trigger GCs so that |obj| moves to old gen.
+  heap->CollectGarbage(i::NEW_SPACE);  // in survivor space now
+  heap->CollectGarbage(i::NEW_SPACE);  // in old gen now
+
+  CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
+  CHECK(isolate->heap()->old_pointer_space()->Contains(*obj_value));
+  CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
+
+  heap->CollectGarbage(i::OLD_POINTER_SPACE, "boom");
+
+  // |obj_value| must be evacuated.
+  CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
+
+  FieldIndex field_index = FieldIndex::ForDescriptor(*map, 1);
+  CHECK_EQ(*obj_value, obj->RawFastPropertyAt(field_index));
+}
+
+
 static void TestLayoutDescriptorHelper(Isolate* isolate,
                                        int inobject_properties,
                                        Handle<DescriptorArray> descriptors,
@@ -1131,7 +1311,7 @@ TEST(LayoutDescriptorSharing) {
   }
   Handle<LayoutDescriptor> split_layout_descriptor(
       split_map->layout_descriptor(), isolate);
-  CHECK(split_layout_descriptor->IsConsistentWithMap(*split_map));
+  CHECK(split_layout_descriptor->IsConsistentWithMap(*split_map, true));
   CHECK(split_layout_descriptor->IsSlowLayout());
   CHECK(split_map->owns_descriptors());
 
@@ -1144,7 +1324,7 @@ TEST(LayoutDescriptorSharing) {
   // Layout descriptors should be shared with |split_map|.
   CHECK(map1->owns_descriptors());
   CHECK_EQ(*split_layout_descriptor, map1->layout_descriptor());
-  CHECK(map1->layout_descriptor()->IsConsistentWithMap(*map1));
+  CHECK(map1->layout_descriptor()->IsConsistentWithMap(*map1, true));
 
   Handle<Map> map2 = Map::CopyWithField(split_map, MakeString("bar"), any_type,
                                         NONE, Representation::Tagged(),
@@ -1153,7 +1333,7 @@ TEST(LayoutDescriptorSharing) {
   // Layout descriptors should not be shared with |split_map|.
   CHECK(map2->owns_descriptors());
   CHECK_NE(*split_layout_descriptor, map2->layout_descriptor());
-  CHECK(map2->layout_descriptor()->IsConsistentWithMap(*map2));
+  CHECK(map2->layout_descriptor()->IsConsistentWithMap(*map2, true));
 }
 
 
@@ -1163,28 +1343,23 @@ TEST(StoreBufferScanOnScavenge) {
   Factory* factory = isolate->factory();
   v8::HandleScope scope(CcTest::isolate());
 
-  CompileRun(
-      "function A() {"
-      "  this.x = 42.5;"
-      "  this.o = {};"
-      "};"
-      "var o = new A();");
+  Handle<HeapType> any_type = HeapType::Any(isolate);
+  Handle<Map> map = Map::Create(isolate, 10);
+  map = Map::CopyWithField(map, MakeName("prop", 0), any_type, NONE,
+                           Representation::Double(),
+                           INSERT_TRANSITION).ToHandleChecked();
 
-  Handle<String> obj_name = factory->InternalizeUtf8String("o");
+  // Create object in new space.
+  Handle<JSObject> obj = factory->NewJSObjectFromMap(map, NOT_TENURED, false);
 
-  Handle<Object> obj_value =
-      Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked();
-  CHECK(obj_value->IsJSObject());
-  Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
+  Handle<HeapNumber> heap_number = factory->NewHeapNumber(42.5);
+  obj->WriteToField(0, *heap_number);
 
   {
     // 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);
+    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));
@@ -1305,4 +1480,211 @@ TEST(WriteBarriersInCopyJSObject) {
   CHECK_EQ(boom_value, clone->RawFastDoublePropertyAt(index));
 }
 
+
+static void TestWriteBarrier(Handle<Map> map, Handle<Map> new_map,
+                             int tagged_descriptor, int double_descriptor,
+                             bool check_tagged_value = true) {
+  FLAG_stress_compaction = true;
+  FLAG_manual_evacuation_candidates_selection = true;
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  Heap* heap = CcTest::heap();
+  PagedSpace* old_pointer_space = heap->old_pointer_space();
+
+  // The plan: create |obj| by |map| in old space, create |obj_value| in
+  // new space and ensure that write barrier is triggered when |obj_value| is
+  // written to property |tagged_descriptor| of |obj|.
+  // Then migrate object to |new_map| and set proper value for property
+  // |double_descriptor|. Call GC and ensure that it did not crash during
+  // store buffer entries updating.
+
+  Handle<JSObject> obj;
+  Handle<HeapObject> obj_value;
+  {
+    AlwaysAllocateScope always_allocate(isolate);
+    obj = factory->NewJSObjectFromMap(map, TENURED, false);
+    CHECK(old_pointer_space->Contains(*obj));
+
+    obj_value = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS);
+  }
+
+  CHECK(heap->InNewSpace(*obj_value));
+
+  {
+    FieldIndex index = FieldIndex::ForDescriptor(*map, tagged_descriptor);
+    const int n = 153;
+    for (int i = 0; i < n; i++) {
+      obj->FastPropertyAtPut(index, *obj_value);
+    }
+  }
+
+  // Migrate |obj| to |new_map| which should shift fields and put the
+  // |boom_value| to the slot that was earlier recorded by write barrier.
+  JSObject::MigrateToMap(obj, new_map);
+
+  Address fake_object = reinterpret_cast<Address>(*obj_value) + kPointerSize;
+  double boom_value = bit_cast<double>(fake_object);
+
+  FieldIndex double_field_index =
+      FieldIndex::ForDescriptor(*new_map, double_descriptor);
+  CHECK(obj->IsUnboxedDoubleField(double_field_index));
+  obj->RawFastDoublePropertyAtPut(double_field_index, boom_value);
+
+  // Trigger GC to evacuate all candidates.
+  CcTest::heap()->CollectGarbage(NEW_SPACE, "boom");
+
+  if (check_tagged_value) {
+    FieldIndex tagged_field_index =
+        FieldIndex::ForDescriptor(*new_map, tagged_descriptor);
+    CHECK_EQ(*obj_value, obj->RawFastPropertyAt(tagged_field_index));
+  }
+  CHECK_EQ(boom_value, obj->RawFastDoublePropertyAt(double_field_index));
+}
+
+
+static void TestIncrementalWriteBarrier(Handle<Map> map, Handle<Map> new_map,
+                                        int tagged_descriptor,
+                                        int double_descriptor,
+                                        bool check_tagged_value = true) {
+  if (FLAG_never_compact || !FLAG_incremental_marking) return;
+  FLAG_stress_compaction = true;
+  FLAG_manual_evacuation_candidates_selection = true;
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  Heap* heap = CcTest::heap();
+  PagedSpace* old_pointer_space = heap->old_pointer_space();
+
+  // The plan: create |obj| by |map| in old space, create |obj_value| in
+  // old space and ensure it end up in evacuation candidate page. Start
+  // incremental marking and ensure that incremental write barrier is triggered
+  // when |obj_value| is written to property |tagged_descriptor| of |obj|.
+  // Then migrate object to |new_map| and set proper value for property
+  // |double_descriptor|. Call GC and ensure that it did not crash during
+  // slots buffer entries updating.
+
+  Handle<JSObject> obj;
+  Handle<HeapObject> obj_value;
+  Page* ec_page;
+  {
+    AlwaysAllocateScope always_allocate(isolate);
+    obj = factory->NewJSObjectFromMap(map, TENURED, false);
+    CHECK(old_pointer_space->Contains(*obj));
+
+    // Make sure |obj_value| is placed on an old-space evacuation candidate.
+    SimulateFullSpace(old_pointer_space);
+    obj_value = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
+    ec_page = Page::FromAddress(obj_value->address());
+    CHECK_NE(ec_page, Page::FromAddress(obj->address()));
+  }
+
+  // Heap is ready, force |ec_page| to become an evacuation candidate and
+  // simulate incremental marking.
+  ec_page->SetFlag(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING);
+  SimulateIncrementalMarking(heap);
+
+  // Check that everything is ready for triggering incremental write barrier
+  // (i.e. that both |obj| and |obj_value| are black and the marking phase is
+  // still active and |obj_value|'s page is indeed an evacuation candidate).
+  IncrementalMarking* marking = heap->incremental_marking();
+  CHECK(marking->IsMarking());
+  CHECK(Marking::IsBlack(Marking::MarkBitFrom(*obj)));
+  CHECK(Marking::IsBlack(Marking::MarkBitFrom(*obj_value)));
+  CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
+
+  // Trigger incremental write barrier, which should add a slot to |ec_page|'s
+  // slots buffer.
+  {
+    int slots_buffer_len = SlotsBuffer::SizeOfChain(ec_page->slots_buffer());
+    FieldIndex index = FieldIndex::ForDescriptor(*map, tagged_descriptor);
+    const int n = SlotsBuffer::kNumberOfElements + 10;
+    for (int i = 0; i < n; i++) {
+      obj->FastPropertyAtPut(index, *obj_value);
+    }
+    // Ensure that the slot was actually added to the |ec_page|'s slots buffer.
+    CHECK_EQ(slots_buffer_len + n,
+             SlotsBuffer::SizeOfChain(ec_page->slots_buffer()));
+  }
+
+  // Migrate |obj| to |new_map| which should shift fields and put the
+  // |boom_value| to the slot that was earlier recorded by incremental write
+  // barrier.
+  JSObject::MigrateToMap(obj, new_map);
+
+  double boom_value = bit_cast<double>(UINT64_C(0xbaad0176a37c28e1));
+
+  FieldIndex double_field_index =
+      FieldIndex::ForDescriptor(*new_map, double_descriptor);
+  CHECK(obj->IsUnboxedDoubleField(double_field_index));
+  obj->RawFastDoublePropertyAtPut(double_field_index, boom_value);
+
+  // Trigger GC to evacuate all candidates.
+  CcTest::heap()->CollectGarbage(OLD_POINTER_SPACE, "boom");
+
+  // Ensure that the values are still there and correct.
+  CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
+
+  if (check_tagged_value) {
+    FieldIndex tagged_field_index =
+        FieldIndex::ForDescriptor(*new_map, tagged_descriptor);
+    CHECK_EQ(*obj_value, obj->RawFastPropertyAt(tagged_field_index));
+  }
+  CHECK_EQ(boom_value, obj->RawFastDoublePropertyAt(double_field_index));
+}
+
+
+enum WriteBarrierKind { OLD_TO_OLD_WRITE_BARRIER, OLD_TO_NEW_WRITE_BARRIER };
+static void TestWriteBarrierObjectShiftFieldsRight(
+    WriteBarrierKind write_barrier_kind) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<HeapType> any_type = HeapType::Any(isolate);
+
+  CompileRun("function func() { return 1; }");
+
+  Handle<JSObject> func = GetObject("func");
+
+  Handle<Map> map = Map::Create(isolate, 10);
+  map = Map::CopyWithConstant(map, MakeName("prop", 0), func, NONE,
+                              INSERT_TRANSITION).ToHandleChecked();
+  map = Map::CopyWithField(map, MakeName("prop", 1), any_type, NONE,
+                           Representation::Double(),
+                           INSERT_TRANSITION).ToHandleChecked();
+  map = Map::CopyWithField(map, MakeName("prop", 2), any_type, NONE,
+                           Representation::Tagged(),
+                           INSERT_TRANSITION).ToHandleChecked();
+
+  // Shift fields right by turning constant property to a field.
+  Handle<Map> new_map = Map::ReconfigureProperty(
+      map, 0, kData, NONE, Representation::Tagged(), any_type, FORCE_FIELD);
+
+  if (write_barrier_kind == OLD_TO_NEW_WRITE_BARRIER) {
+    TestWriteBarrier(map, new_map, 2, 1);
+  } else {
+    CHECK_EQ(OLD_TO_OLD_WRITE_BARRIER, write_barrier_kind);
+    TestIncrementalWriteBarrier(map, new_map, 2, 1);
+  }
+}
+
+
+// TODO(ishell): enable when this issue is fixed.
+DISABLED_TEST(WriteBarrierObjectShiftFieldsRight) {
+  TestWriteBarrierObjectShiftFieldsRight(OLD_TO_NEW_WRITE_BARRIER);
+}
+
+
+TEST(IncrementalWriteBarrierObjectShiftFieldsRight) {
+  TestWriteBarrierObjectShiftFieldsRight(OLD_TO_OLD_WRITE_BARRIER);
+}
+
+
+// TODO(ishell): add respective tests for property kind reconfiguring from
+// accessor field to double, once accessor fields are supported by
+// Map::ReconfigureProperty().
+
+
+// TODO(ishell): add respective tests for fast property removal case once
+// Map::ReconfigureProperty() supports that.
+
 #endif
index 04f41b9..dfe3f45 100644 (file)
@@ -30,7 +30,6 @@
 #include "src/v8.h"
 
 #include "src/global-handles.h"
-#include "src/snapshot.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
@@ -184,7 +183,8 @@ TEST(Regress2060a) {
 
   // Start second old-space page so that values land on evacuation candidate.
   Page* first_page = heap->old_pointer_space()->anchor()->next_page();
-  factory->NewFixedArray(900 * KB / kPointerSize, TENURED);
+  int dummy_array_size = Page::kMaxRegularHeapObjectSize - 92 * KB;
+  factory->NewFixedArray(dummy_array_size / kPointerSize, TENURED);
 
   // Fill up weak map with values on an evacuation candidate.
   {
@@ -222,7 +222,8 @@ TEST(Regress2060b) {
 
   // Start second old-space page so that keys land on evacuation candidate.
   Page* first_page = heap->old_pointer_space()->anchor()->next_page();
-  factory->NewFixedArray(900 * KB / kPointerSize, TENURED);
+  int dummy_array_size = Page::kMaxRegularHeapObjectSize - 92 * KB;
+  factory->NewFixedArray(dummy_array_size / kPointerSize, TENURED);
 
   // Fill up weak map with keys on an evacuation candidate.
   Handle<JSObject> keys[32];
index f08a99b..1ab9f10 100644 (file)
@@ -30,7 +30,6 @@
 #include "src/v8.h"
 
 #include "src/global-handles.h"
-#include "src/snapshot.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
@@ -184,7 +183,8 @@ TEST(WeakSet_Regress2060a) {
 
   // Start second old-space page so that values land on evacuation candidate.
   Page* first_page = heap->old_pointer_space()->anchor()->next_page();
-  factory->NewFixedArray(900 * KB / kPointerSize, TENURED);
+  int dummy_array_size = Page::kMaxRegularHeapObjectSize - 92 * KB;
+  factory->NewFixedArray(dummy_array_size / kPointerSize, TENURED);
 
   // Fill up weak set with values on an evacuation candidate.
   {
@@ -222,7 +222,8 @@ TEST(WeakSet_Regress2060b) {
 
   // Start second old-space page so that keys land on evacuation candidate.
   Page* first_page = heap->old_pointer_space()->anchor()->next_page();
-  factory->NewFixedArray(900 * KB / kPointerSize, TENURED);
+  int dummy_array_size = Page::kMaxRegularHeapObjectSize - 92 * KB;
+  factory->NewFixedArray(dummy_array_size / kPointerSize, TENURED);
 
   // Fill up weak set with keys on an evacuation candidate.
   Handle<JSObject> keys[32];
index d40b7e9..c1f59de 100644 (file)
@@ -62,7 +62,20 @@ static bool HasArrayBufferInWeakList(Heap* heap, JSArrayBuffer* ab) {
 }
 
 
-static int CountViews(JSArrayBuffer* array_buffer) {
+static int CountViewsInNewSpaceList(Heap* heap, JSArrayBuffer* array_buffer) {
+  int count = 0;
+  for (Object* o = heap->new_array_buffer_views_list(); !o->IsUndefined();) {
+    JSArrayBufferView* view = JSArrayBufferView::cast(o);
+    if (array_buffer == view->buffer()) {
+      count++;
+    }
+    o = view->weak_next();
+  }
+  return count;
+}
+
+
+static int CountViews(Heap* heap, JSArrayBuffer* array_buffer) {
   int count = 0;
   for (Object* o = array_buffer->weak_first_view();
        !o->IsUndefined();
@@ -70,17 +83,27 @@ static int CountViews(JSArrayBuffer* array_buffer) {
     count++;
   }
 
-  return count;
+  return count + CountViewsInNewSpaceList(heap, array_buffer);
 }
 
-static bool HasViewInWeakList(JSArrayBuffer* array_buffer,
+
+static bool HasViewInNewSpaceList(Heap* heap, JSArrayBufferView* ta) {
+  for (Object* o = heap->new_array_buffer_views_list(); !o->IsUndefined();
+       o = JSArrayBufferView::cast(o)->weak_next()) {
+    if (ta == o) return true;
+  }
+  return false;
+}
+
+
+static bool HasViewInWeakList(Heap* heap, JSArrayBuffer* array_buffer,
                               JSArrayBufferView* ta) {
   for (Object* o = array_buffer->weak_first_view();
        !o->IsUndefined();
        o = JSArrayBufferView::cast(o)->weak_next()) {
     if (ta == o) return true;
   }
-  return false;
+  return HasViewInNewSpaceList(heap, ta);
 }
 
 
@@ -200,18 +223,18 @@ void TestViewFromApi() {
 
       Handle<JSArrayBufferView> ita1 = v8::Utils::OpenHandle(*ta1);
       Handle<JSArrayBufferView> ita2 = v8::Utils::OpenHandle(*ta2);
-      CHECK_EQ(2, CountViews(*iab));
-      CHECK(HasViewInWeakList(*iab, *ita1));
-      CHECK(HasViewInWeakList(*iab, *ita2));
+      CHECK_EQ(2, CountViews(isolate->heap(), *iab));
+      CHECK(HasViewInWeakList(isolate->heap(), *iab, *ita1));
+      CHECK(HasViewInWeakList(isolate->heap(), *iab, *ita2));
     }
     isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
-    CHECK_EQ(1, CountViews(*iab));
+    CHECK_EQ(1, CountViews(isolate->heap(), *iab));
     Handle<JSArrayBufferView> ita1 = v8::Utils::OpenHandle(*ta1);
-    CHECK(HasViewInWeakList(*iab, *ita1));
+    CHECK(HasViewInWeakList(isolate->heap(), *iab, *ita1));
   }
   isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
 
-  CHECK_EQ(0, CountViews(*iab));
+  CHECK_EQ(0, CountViews(isolate->heap(), *iab));
 }
 
 
@@ -299,10 +322,13 @@ static void TestTypedArrayFromScript(const char* constructor) {
           v8::Handle<TypedArray>::Cast(CompileRun("ta3"));
       CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
       Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab);
-      CHECK_EQ(3, CountViews(*iab));
-      CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta1)));
-      CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta2)));
-      CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta3)));
+      CHECK_EQ(3, CountViews(isolate->heap(), *iab));
+      CHECK(HasViewInWeakList(isolate->heap(), *iab,
+                              *v8::Utils::OpenHandle(*ta1)));
+      CHECK(HasViewInWeakList(isolate->heap(), *iab,
+                              *v8::Utils::OpenHandle(*ta2)));
+      CHECK(HasViewInWeakList(isolate->heap(), *iab,
+                              *v8::Utils::OpenHandle(*ta3)));
     }
 
     i::SNPrintF(source, "ta%d = null;", i);
@@ -316,13 +342,14 @@ static void TestTypedArrayFromScript(const char* constructor) {
       v8::Handle<v8::ArrayBuffer> ab =
           v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab"));
       Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab);
-      CHECK_EQ(2, CountViews(*iab));
+      CHECK_EQ(2, CountViews(isolate->heap(), *iab));
       for (int j = 1; j <= 3; j++) {
         if (j == i) continue;
         i::SNPrintF(source, "ta%d", j);
         v8::Handle<TypedArray> ta =
             v8::Handle<TypedArray>::Cast(CompileRun(source.start()));
-        CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta)));
+        CHECK(HasViewInWeakList(isolate->heap(), *iab,
+                                *v8::Utils::OpenHandle(*ta)));
       }
     }
 
@@ -336,7 +363,7 @@ static void TestTypedArrayFromScript(const char* constructor) {
       v8::Handle<v8::ArrayBuffer> ab =
           v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab"));
       Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab);
-      CHECK_EQ(0, CountViews(*iab));
+      CHECK_EQ(0, CountViews(isolate->heap(), *iab));
     }
   }
 }
index 0a99ad4..a703642 100644 (file)
@@ -60,7 +60,6 @@
       "path": ["Strings"],
       "main": "run.js",
       "resources": ["harmony-string.js"],
-      "flags": ["--harmony-strings"],
       "results_regexp": "^%s\\-Strings\\(Score\\): (.+)$",
       "tests": [
         {"name": "StringFunctions"}
@@ -71,7 +70,6 @@
       "path": ["Templates"],
       "main": "run.js",
       "resources": ["templates.js"],
-      "flags": ["--harmony-templates"],
       "run_count": 5,
       "units": "score",
       "results_regexp": "^%s\\-Templates\\(Score\\): (.+)$",
@@ -1,7 +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.
+//
+// Flags: --harmony-classes
+'use strict';
 
-// Flags: --noharmony-strings
-
-assertEquals(undefined, String.prototype.includes);
+class C {
+  get constructor() {}
+}
diff --git a/deps/v8/test/message/class-constructor-accessor.out b/deps/v8/test/message/class-constructor-accessor.out
new file mode 100644 (file)
index 0000000..8776f54
--- /dev/null
@@ -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.
+*%(basename)s:9: SyntaxError: Class constructor may not be an accessor
+  get constructor() {}
+      ^^^^^^^^^^^
+SyntaxError: Class constructor may not be an accessor
diff --git a/deps/v8/test/message/class-constructor-generator.js b/deps/v8/test/message/class-constructor-generator.js
new file mode 100644 (file)
index 0000000..5d370f8
--- /dev/null
@@ -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.
+//
+// Flags: --harmony-classes
+'use strict';
+
+class C {
+  *constructor() {}
+}
diff --git a/deps/v8/test/message/class-constructor-generator.out b/deps/v8/test/message/class-constructor-generator.out
new file mode 100644 (file)
index 0000000..5075e51
--- /dev/null
@@ -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.
+*%(basename)s:9: SyntaxError: Class constructor may not be a generator
+  *constructor() {}
+   ^^^^^^^^^^^
+SyntaxError: Class constructor may not be a generator
diff --git a/deps/v8/test/message/export-duplicate-as.js b/deps/v8/test/message/export-duplicate-as.js
new file mode 100644 (file)
index 0000000..49b52d4
--- /dev/null
@@ -0,0 +1,9 @@
+// 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.
+//
+// MODULE
+
+var a, b;
+export { a as c };
+export { a, b as c };
diff --git a/deps/v8/test/message/export-duplicate-as.out b/deps/v8/test/message/export-duplicate-as.out
new file mode 100644 (file)
index 0000000..1726d94
--- /dev/null
@@ -0,0 +1,7 @@
+# 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.
+*%(basename)s:9: SyntaxError: Duplicate export of 'c'
+export { a, b as c };
+                 ^
+SyntaxError: Duplicate export of 'c'
diff --git a/deps/v8/test/message/export-duplicate-default.js b/deps/v8/test/message/export-duplicate-default.js
new file mode 100644 (file)
index 0000000..72a54a4
--- /dev/null
@@ -0,0 +1,8 @@
+// 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.
+//
+// MODULE
+
+export default function f() {};
+export default class C {};
diff --git a/deps/v8/test/message/export-duplicate-default.out b/deps/v8/test/message/export-duplicate-default.out
new file mode 100644 (file)
index 0000000..4c6b97a
--- /dev/null
@@ -0,0 +1,7 @@
+# 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.
+*%(basename)s:8: SyntaxError: Duplicate export of 'default'
+export default class C {};
+       ^^^^^^^
+SyntaxError: Duplicate export of 'default'
diff --git a/deps/v8/test/message/export-duplicate.js b/deps/v8/test/message/export-duplicate.js
new file mode 100644 (file)
index 0000000..f45aefe
--- /dev/null
@@ -0,0 +1,9 @@
+// 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.
+//
+// MODULE
+
+var a, b;
+export { a };
+export { a, b };
diff --git a/deps/v8/test/message/export-duplicate.out b/deps/v8/test/message/export-duplicate.out
new file mode 100644 (file)
index 0000000..e88779f
--- /dev/null
@@ -0,0 +1,7 @@
+# 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.
+*%(basename)s:9: SyntaxError: Duplicate export of 'a'
+export { a, b };
+         ^
+SyntaxError: Duplicate export of 'a'
diff --git a/deps/v8/test/message/import-as-eval.js b/deps/v8/test/message/import-as-eval.js
new file mode 100644 (file)
index 0000000..66adc32
--- /dev/null
@@ -0,0 +1,7 @@
+// 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.
+//
+// MODULE
+
+import { foo as eval } from "mod";
diff --git a/deps/v8/test/message/import-as-eval.out b/deps/v8/test/message/import-as-eval.out
new file mode 100644 (file)
index 0000000..622f7fe
--- /dev/null
@@ -0,0 +1,7 @@
+# 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.
+*%(basename)s:7: SyntaxError: Unexpected eval or arguments in strict mode
+import { foo as eval } from "mod";
+                ^^^^
+SyntaxError: Unexpected eval or arguments in strict mode
diff --git a/deps/v8/test/message/import-as-redeclaration.js b/deps/v8/test/message/import-as-redeclaration.js
new file mode 100644 (file)
index 0000000..43bf278
--- /dev/null
@@ -0,0 +1,8 @@
+// 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.
+//
+// MODULE
+
+let foo = 42;
+import { bar as foo } from "mod";
diff --git a/deps/v8/test/message/import-as-redeclaration.out b/deps/v8/test/message/import-as-redeclaration.out
new file mode 100644 (file)
index 0000000..51c4c03
--- /dev/null
@@ -0,0 +1,7 @@
+# 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.
+*%(basename)s:8: SyntaxError: Identifier 'foo' has already been declared
+import { bar as foo } from "mod";
+                ^^^
+SyntaxError: Identifier 'foo' has already been declared
diff --git a/deps/v8/test/message/import-as-reserved-word.js b/deps/v8/test/message/import-as-reserved-word.js
new file mode 100644 (file)
index 0000000..562699d
--- /dev/null
@@ -0,0 +1,7 @@
+// 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.
+//
+// MODULE
+
+import { foo as import } from "mod";
diff --git a/deps/v8/test/message/import-as-reserved-word.out b/deps/v8/test/message/import-as-reserved-word.out
new file mode 100644 (file)
index 0000000..1ee8d41
--- /dev/null
@@ -0,0 +1,7 @@
+# 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.
+*%(basename)s:7: SyntaxError: Unexpected reserved word
+import { foo as import } from "mod";
+                ^^^^^^
+SyntaxError: Unexpected reserved word
diff --git a/deps/v8/test/message/import-eval.js b/deps/v8/test/message/import-eval.js
new file mode 100644 (file)
index 0000000..8ab35ba
--- /dev/null
@@ -0,0 +1,7 @@
+// 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.
+//
+// MODULE
+
+import { eval } from "mod";
diff --git a/deps/v8/test/message/import-eval.out b/deps/v8/test/message/import-eval.out
new file mode 100644 (file)
index 0000000..148662a
--- /dev/null
@@ -0,0 +1,7 @@
+# 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.
+*%(basename)s:7: SyntaxError: Unexpected eval or arguments in strict mode
+import { eval } from "mod";
+         ^^^^
+SyntaxError: Unexpected eval or arguments in strict mode
diff --git a/deps/v8/test/message/import-redeclaration.js b/deps/v8/test/message/import-redeclaration.js
new file mode 100644 (file)
index 0000000..27b0cdc
--- /dev/null
@@ -0,0 +1,8 @@
+// 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.
+//
+// MODULE
+
+let foo = 42;
+import { foo } from "mod";
diff --git a/deps/v8/test/message/import-redeclaration.out b/deps/v8/test/message/import-redeclaration.out
new file mode 100644 (file)
index 0000000..6419488
--- /dev/null
@@ -0,0 +1,7 @@
+# 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.
+*%(basename)s:8: SyntaxError: Identifier 'foo' has already been declared
+import { foo } from "mod";
+         ^^^
+SyntaxError: Identifier 'foo' has already been declared
diff --git a/deps/v8/test/message/import-reserved-word.js b/deps/v8/test/message/import-reserved-word.js
new file mode 100644 (file)
index 0000000..1fd7ba2
--- /dev/null
@@ -0,0 +1,7 @@
+// 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.
+//
+// MODULE
+
+import { import } from "mod";
diff --git a/deps/v8/test/message/import-reserved-word.out b/deps/v8/test/message/import-reserved-word.out
new file mode 100644 (file)
index 0000000..5b990e9
--- /dev/null
@@ -0,0 +1,7 @@
+# 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.
+*%(basename)s:7: SyntaxError: Unexpected reserved word
+import { import } from "mod";
+         ^^^^^^
+SyntaxError: Unexpected reserved word
index 5d6ab84..cfe22f1 100644 (file)
@@ -36,6 +36,7 @@ from testrunner.objects import testcase
 
 FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
 INVALID_FLAGS = ["--enable-slow-asserts"]
+MODULE_PATTERN = re.compile(r"^// MODULE$", flags=re.MULTILINE)
 
 
 class MessageTestSuite(testsuite.TestSuite):
@@ -63,6 +64,8 @@ class MessageTestSuite(testsuite.TestSuite):
     for match in flags_match:
       result += match.strip().split()
     result += context.mode_flags
+    if MODULE_PATTERN.search(source):
+      result.append("--module")
     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
diff --git a/deps/v8/test/message/unterminated-arg-list.js b/deps/v8/test/message/unterminated-arg-list.js
new file mode 100644 (file)
index 0000000..b0fd1dd
--- /dev/null
@@ -0,0 +1,7 @@
+// 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.
+
+$(document).ready(function() {
+$("html").load( "https://localhost" );
+}
diff --git a/deps/v8/test/message/unterminated-arg-list.out b/deps/v8/test/message/unterminated-arg-list.out
new file mode 100644 (file)
index 0000000..5be2b3d
--- /dev/null
@@ -0,0 +1,8 @@
+# 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.
+
+*%(basename)s:7: SyntaxError: missing ) after argument list
+}
+^
+SyntaxError: missing ) after argument list
diff --git a/deps/v8/test/mjsunit/asm/construct-double.js b/deps/v8/test/mjsunit/asm/construct-double.js
new file mode 100644 (file)
index 0000000..8bb5000
--- /dev/null
@@ -0,0 +1,33 @@
+// 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
+
+var stdlib = this;
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+
+var m = (function(stdlib, foreign, heap) {
+  "use asm";
+  function cd1(i, j) {
+    i = i|0;
+    j = j|0;
+    return +%_ConstructDouble(i, j);
+  }
+  function cd2(i) {
+    i = i|0;
+    return +%_ConstructDouble(0, i);
+  }
+  return { cd1: cd1, cd2: cd2 };
+})(stdlib, foreign, heap);
+
+assertEquals(0.0, m.cd1(0, 0));
+assertEquals(%ConstructDouble(0, 1), m.cd2(1));
+for (var i = -2147483648; i < 2147483648; i += 3999773) {
+  assertEquals(%ConstructDouble(0, i), m.cd2(i));
+  for (var j = -2147483648; j < 2147483648; j += 3999773) {
+    assertEquals(%ConstructDouble(i, j), m.cd1(i, j));
+  }
+}
diff --git a/deps/v8/test/mjsunit/asm/double-hi.js b/deps/v8/test/mjsunit/asm/double-hi.js
new file mode 100644 (file)
index 0000000..5a5f942
--- /dev/null
@@ -0,0 +1,40 @@
+// 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
+
+var stdlib = this;
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+
+var m = (function(stdlib, foreign, heap) {
+  "use asm";
+  function hi1(i) {
+    i = +i;
+    return %_DoubleHi(i)|0;
+  }
+  function hi2(i, j) {
+    i = +i;
+    j = +j;
+    return %_DoubleHi(i)+%_DoubleHi(j)|0;
+  }
+  return { hi1: hi1, hi2: hi2 };
+})(stdlib, foreign, heap);
+
+assertEquals(0, m.hi1(0.0));
+assertEquals(-2147483648, m.hi1(-0.0));
+assertEquals(2146435072, m.hi1(Infinity));
+assertEquals(-1048576, m.hi1(-Infinity));
+assertEquals(0, m.hi2(0.0, 0.0));
+assertEquals(-2147483648, m.hi2(0.0, -0.0));
+assertEquals(-2147483648, m.hi2(-0.0, 0.0));
+assertEquals(0, m.hi2(-0.0, -0.0));
+for (var i = -2147483648; i < 2147483648; i += 3999773) {
+  assertEquals(%_DoubleHi(i), m.hi1(i));
+  assertEquals(i, m.hi1(%ConstructDouble(i, 0)));
+  assertEquals(i, m.hi1(%ConstructDouble(i, i)));
+  assertEquals(i+i|0, m.hi2(%ConstructDouble(i, 0), %ConstructDouble(i, 0)));
+  assertEquals(i+i|0, m.hi2(%ConstructDouble(i, i), %ConstructDouble(i, i)));
+}
diff --git a/deps/v8/test/mjsunit/asm/double-lo.js b/deps/v8/test/mjsunit/asm/double-lo.js
new file mode 100644 (file)
index 0000000..39d5b52
--- /dev/null
@@ -0,0 +1,40 @@
+// 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
+
+var stdlib = this;
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+
+var m = (function(stdlib, foreign, heap) {
+  "use asm";
+  function lo1(i) {
+    i = +i;
+    return %_DoubleLo(i)|0;
+  }
+  function lo2(i, j) {
+    i = +i;
+    j = +j;
+    return %_DoubleLo(i)+%_DoubleLo(j)|0;
+  }
+  return { lo1: lo1, lo2: lo2 };
+})(stdlib, foreign, heap);
+
+assertEquals(0, m.lo1(0.0));
+assertEquals(0, m.lo1(-0.0));
+assertEquals(0, m.lo1(Infinity));
+assertEquals(0, m.lo1(-Infinity));
+assertEquals(0, m.lo2(0.0, 0.0));
+assertEquals(0, m.lo2(0.0, -0.0));
+assertEquals(0, m.lo2(-0.0, 0.0));
+assertEquals(0, m.lo2(-0.0, -0.0));
+for (var i = -2147483648; i < 2147483648; i += 3999773) {
+  assertEquals(%_DoubleLo(i), m.lo1(i));
+  assertEquals(i, m.lo1(%ConstructDouble(0, i)));
+  assertEquals(i, m.lo1(%ConstructDouble(i, i)));
+  assertEquals(i+i|0, m.lo2(%ConstructDouble(0, i), %ConstructDouble(0, i)));
+  assertEquals(i+i|0, m.lo2(%ConstructDouble(i, i), %ConstructDouble(i, i)));
+}
diff --git a/deps/v8/test/mjsunit/asm/if-cloning.js b/deps/v8/test/mjsunit/asm/if-cloning.js
new file mode 100644 (file)
index 0000000..99d4edc
--- /dev/null
@@ -0,0 +1,34 @@
+// 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 if0 = (function Module() {
+  "use asm";
+  function if0(i, j) {
+    i = i|0;
+    j = j|0;
+    if (i == 0 ? j == 0 : 0) return 1;
+    return 0;
+  }
+  return {if0: if0};
+})().if0;
+assertEquals(1, if0(0, 0));
+assertEquals(0, if0(11, 0));
+assertEquals(0, if0(0, -1));
+assertEquals(0, if0(-1024, 1));
+
+
+var if1 = (function Module() {
+  "use asm";
+  function if1(i, j) {
+    i = i|0;
+    j = j|0;
+    if (i == 0 ? j == 0 : 1) return 0;
+    return 1;
+  }
+  return {if1: if1};
+})().if1;
+assertEquals(0, if1(0, 0));
+assertEquals(0, if1(11, 0));
+assertEquals(1, if1(0, -1));
+assertEquals(0, if1(-1024, 9));
diff --git a/deps/v8/test/mjsunit/asm/math-clz32.js b/deps/v8/test/mjsunit/asm/math-clz32.js
new file mode 100644 (file)
index 0000000..004aa65
--- /dev/null
@@ -0,0 +1,31 @@
+// 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
+
+var stdlib = { Math: Math };
+
+var f = (function Module(stdlib) {
+  "use asm";
+
+  var clz32 = stdlib.Math.clz32;
+
+  function f(a) {
+    a = a >>> 0;
+    return clz32(a)|0;
+  }
+
+  return f;
+})(stdlib);
+
+assertEquals(32, f(0));
+assertEquals(32, f(NaN));
+assertEquals(32, f(undefined));
+for (var i = 0; i < 32; ++i) {
+  assertEquals(i, f((-1) >>> i));
+}
+for (var i = -2147483648; i < 2147483648; i += 3999773) {
+  assertEquals(%MathClz32(i), f(i));
+  assertEquals(%_MathClz32(i), f(i));
+}
index 9ef8efb..52c94e7 100644 (file)
@@ -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 --harmony-scoping
+// Flags: --expose-debug-as debug
 // The functions used for testing backtraces. They are at the top to make the
 // testing of source line/column easier.
 
diff --git a/deps/v8/test/mjsunit/compiler/deopt-tonumber-binop.js b/deps/v8/test/mjsunit/compiler/deopt-tonumber-binop.js
new file mode 100644 (file)
index 0000000..c93ef9d
--- /dev/null
@@ -0,0 +1,40 @@
+// 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
+//
+var f = (function() {
+  "use asm";
+  function f(x, y) {
+    return x - y;
+  }
+  return f;
+})();
+
+var counter = 0;
+
+var deopt = { toString : function() {
+  %DeoptimizeFunction(f);
+  counter++;
+  return "2";
+} };
+
+var o = { toString : function() {
+  counter++;
+  return "1";
+} };
+
+counter = 0;
+assertEquals(1, f(deopt, o));
+assertEquals(2, counter);
+
+%OptimizeFunctionOnNextCall(f);
+counter = 0;
+assertEquals(-1, f(o, deopt));
+assertEquals(2, counter);
+
+%OptimizeFunctionOnNextCall(f);
+counter = 0;
+assertEquals(0, f(deopt, deopt));
+assertEquals(2, counter);
diff --git a/deps/v8/test/mjsunit/compiler/eager-deopt-simple.js b/deps/v8/test/mjsunit/compiler/eager-deopt-simple.js
new file mode 100644 (file)
index 0000000..067400c
--- /dev/null
@@ -0,0 +1,18 @@
+// 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(a, b, c) {
+  return a + b + c;
+}
+
+function f() {
+  return g(1, (%_DeoptimizeNow(), 2), 3);
+}
+
+f();
+f();
+%OptimizeFunctionOnNextCall(f);
+assertEquals(6, f());
diff --git a/deps/v8/test/mjsunit/compiler/osr-forin-nested.js b/deps/v8/test/mjsunit/compiler/osr-forin-nested.js
new file mode 100644 (file)
index 0000000..ad55b30
--- /dev/null
@@ -0,0 +1,35 @@
+// 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: --turbo-osr --allow-natives-syntax
+
+function test(e, f, v) {
+  assertEquals(e, f(v));
+  assertEquals(e, f(v));
+  assertEquals(e, f(v));
+}
+
+function foo(t) {
+  for (var x in t) {
+    for (var i = 0; i < 2; i++) {
+      %OptimizeOsr();
+    }
+  }
+  return 5;
+}
+
+test(5, foo, {x:20});
+
+function bar(t) {
+  var sum = 0;
+  for (var x in t) {
+    for (var i = 0; i < 2; i++) {
+      %OptimizeOsr();
+      sum += t[x];
+    }
+  }
+  return sum;
+}
+
+test(62, bar, {x:20,y:11});
diff --git a/deps/v8/test/mjsunit/compiler/osr-infinite.js b/deps/v8/test/mjsunit/compiler/osr-infinite.js
new file mode 100644 (file)
index 0000000..aa74c87
--- /dev/null
@@ -0,0 +1,78 @@
+// 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: --use-osr --allow-natives-syntax --turbo-osr
+
+var global_counter = 0;
+
+function thrower() {
+  var x = global_counter++;
+  if (x == 5)  %OptimizeOsr(thrower.caller);
+  if (x == 10) throw "terminate";
+}
+
+%NeverOptimizeFunction(thrower);  // Don't want to inline the thrower.
+%NeverOptimizeFunction(test);     // Don't want to inline the func into test.
+
+function test(func) {
+  for (var i = 0; i < 3; i++) {
+    global_counter = 0;
+    assertThrows(func);
+  }
+}
+
+function n1() {
+  while (true) thrower();
+}
+
+function n2() {
+  while (true) while (true) thrower();
+}
+
+function n3() {
+  while (true) while (true) while (true) thrower();
+}
+
+function n4() {
+  while (true) while (true) while (true) while (true) thrower();
+}
+
+function b1(a) {
+  while (true) {
+    thrower();
+    if (a) break
+  }
+}
+
+
+function b2(a) {
+  while (true) {
+    while (true) {
+      thrower();
+      if (a) break
+    }
+  }
+}
+
+
+function b3(a) {
+  while (true) {
+    while (true) {
+      while (true) {
+        thrower();
+        if (a) break
+      }
+      if (a) break
+    }
+  }
+}
+
+
+test(n1);
+test(n2);
+test(n3);
+test(n4);
+test(b1);
+test(b2);
+test(b3);
diff --git a/deps/v8/test/mjsunit/compiler/osr-labeled.js b/deps/v8/test/mjsunit/compiler/osr-labeled.js
new file mode 100644 (file)
index 0000000..1a97092
--- /dev/null
@@ -0,0 +1,47 @@
+// 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 --use-osr --turbo-osr
+
+function foo() {
+  var sum = 0;
+  A: for (var i = 0; i < 5; i++) {
+    B: for (var j = 0; j < 5; j++) {
+      C: for (var k = 0; k < 10; k++) {
+        if (k === 5) %OptimizeOsr();
+        if (k === 6) break B;
+        sum++;
+      }
+    }
+  }
+  return sum;
+}
+
+assertEquals(30, foo());
+assertEquals(30, foo());
+
+function bar(a) {
+  var sum = 0;
+  A: for (var i = 0; i < 5; i++) {
+    B: for (var j = 0; j < 5; j++) {
+      C: for (var k = 0; k < 10; k++) {
+        sum++;
+        %OptimizeOsr();
+        if (a === 1) break A;
+        if (a === 2) break B;
+        if (a === 3) break C;
+      }
+    }
+  }
+  return sum;
+}
+
+assertEquals(1, bar(1));
+assertEquals(1, bar(1));
+
+assertEquals(5, bar(2));
+assertEquals(5, bar(2));
+
+assertEquals(25, bar(3));
+assertEquals(25, bar(3));
diff --git a/deps/v8/test/mjsunit/compiler/osr-literals-adapted.js b/deps/v8/test/mjsunit/compiler/osr-literals-adapted.js
new file mode 100644 (file)
index 0000000..950d8b0
--- /dev/null
@@ -0,0 +1,56 @@
+// 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 --use-osr --turbo-osr
+
+function mod() {
+  function f0() {
+    for (var i = 0; i < 3; i = i + 1 | 0) {
+      %OptimizeOsr();
+    }
+    return {blah: i};
+  }
+
+  function f1(a) {
+    for (var i = 0; i < 3; i = i + 1 | 0) {
+      %OptimizeOsr();
+    }
+    return {blah: i};
+  }
+
+  function f2(a,b) {
+    for (var i = 0; i < 3; i = i + 1 | 0) {
+      %OptimizeOsr();
+    }
+    return {blah: i};
+  }
+
+  function f3(a,b,c) {
+    for (var i = 0; i < 3; i = i + 1 | 0) {
+      %OptimizeOsr();
+    }
+    return {blah: i};
+  }
+
+  function f4(a,b,c,d) {
+    for (var i = 0; i < 3; i = i + 1 | 0) {
+      %OptimizeOsr();
+    }
+    return {blah: i};
+  }
+
+  function bar() {
+    assertEquals(3, f0().blah);
+    assertEquals(3, f1().blah);
+    assertEquals(3, f2().blah);
+    assertEquals(3, f3().blah);
+    assertEquals(3, f4().blah);
+  }
+  bar();
+}
+
+
+mod();
+mod();
+mod();
diff --git a/deps/v8/test/mjsunit/compiler/osr-literals.js b/deps/v8/test/mjsunit/compiler/osr-literals.js
new file mode 100644 (file)
index 0000000..d9f68a0
--- /dev/null
@@ -0,0 +1,56 @@
+// 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 --use-osr --turbo-osr
+
+function mod() {
+  function f0() {
+    for (var i = 0; i < 3; i = i + 1 | 0) {
+      %OptimizeOsr();
+    }
+    return {blah: i};
+  }
+
+  function f1(a) {
+    for (var i = 0; i < 3; i = i + 1 | 0) {
+      %OptimizeOsr();
+    }
+    return {blah: i};
+  }
+
+  function f2(a,b) {
+    for (var i = 0; i < 3; i = i + 1 | 0) {
+      %OptimizeOsr();
+    }
+    return {blah: i};
+  }
+
+  function f3(a,b,c) {
+    for (var i = 0; i < 3; i = i + 1 | 0) {
+      %OptimizeOsr();
+    }
+    return {blah: i};
+  }
+
+  function f4(a,b,c,d) {
+    for (var i = 0; i < 3; i = i + 1 | 0) {
+      %OptimizeOsr();
+    }
+    return {blah: i};
+  }
+
+  function bar() {
+    assertEquals(3, f0().blah);
+    assertEquals(3, f1(1).blah);
+    assertEquals(3, f2(1,2).blah);
+    assertEquals(3, f3(1,2,3).blah);
+    assertEquals(3, f4(1,2,3,4).blah);
+  }
+  bar();
+}
+
+
+mod();
+mod();
+mod();
diff --git a/deps/v8/test/mjsunit/compiler/regress-463056.js b/deps/v8/test/mjsunit/compiler/regress-463056.js
new file mode 100644 (file)
index 0000000..fb87161
--- /dev/null
@@ -0,0 +1,9 @@
+// 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 f() {
+ return ((0%0)&1) + (1>>>(0%0));
+}
+
+f();
diff --git a/deps/v8/test/mjsunit/compiler/regress-468727.js b/deps/v8/test/mjsunit/compiler/regress-468727.js
new file mode 100644 (file)
index 0000000..a69efe5
--- /dev/null
@@ -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: --noanalyze-environment-liveness
+
+function f() {
+  var __v_7 = -126 - __v_3;
+  var __v_17 = ((__v_15 & __v_14) != 4) | 16;
+  if (__v_17) {
+    var __v_11 = 1 << __v_7;
+  }
+  __v_12 >>= __v_3;
+}
+
+assertThrows(f);
diff --git a/deps/v8/test/mjsunit/compiler/regress-469089.js b/deps/v8/test/mjsunit/compiler/regress-469089.js
new file mode 100644 (file)
index 0000000..6aff2b7
--- /dev/null
@@ -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: --expose-gc
+
+(function() {
+  var __v_6 = false;
+  function f(val, idx) {
+    if (idx === 1) {
+      gc();
+      __v_6 = (val === 0);
+    }
+  }
+  f(.1, 1);
+})();
diff --git a/deps/v8/test/mjsunit/compiler/truncating-store-deopt.js b/deps/v8/test/mjsunit/compiler/truncating-store-deopt.js
new file mode 100644 (file)
index 0000000..a640caf
--- /dev/null
@@ -0,0 +1,28 @@
+// 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(a, b, c) {
+  return a + b + c;
+}
+
+var asm = (function Module(global, env, buffer) {
+  "use asm";
+
+  var i32 = new global.Int32Array(buffer);
+
+  // This is not valid asm.js, but we should still generate correct code.
+  function store(x) {
+    return g(1, i32[0] = x, 2);
+  }
+
+  return { store: store };
+})({
+  "Int32Array": Int32Array
+}, {}, new ArrayBuffer(64 * 1024));
+
+var o = { toString : function() { %DeoptimizeFunction(asm.store); return "1"; } }
+
+asm.store(o);
diff --git a/deps/v8/test/mjsunit/compiler/try-deopt.js b/deps/v8/test/mjsunit/compiler/try-deopt.js
new file mode 100644 (file)
index 0000000..dc44e73
--- /dev/null
@@ -0,0 +1,56 @@
+// 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.
+
+// TODO(mstarzinger): Add FLAG_turbo_exceptions once we want ClusterFuzz.
+// Flags: --allow-natives-syntax --turbo-deoptimization
+
+function DeoptFromTry(x) {
+  try {
+    %DeoptimizeFunction(DeoptFromTry);
+    throw x;
+  } catch (e) {
+    return e + 1;
+  }
+  return x + 2;
+}
+%OptimizeFunctionOnNextCall(DeoptFromTry);
+assertEquals(24, DeoptFromTry(23));
+
+
+function DeoptFromCatch(x) {
+  try {
+    throw x;
+  } catch (e) {
+    %DeoptimizeFunction(DeoptFromCatch);
+    return e + 1;
+  }
+  return x + 2;
+}
+%OptimizeFunctionOnNextCall(DeoptFromCatch);
+assertEquals(24, DeoptFromCatch(23));
+
+
+function DeoptFromFinally_Return(x) {
+  try {
+    throw x;
+  } finally {
+    %DeoptimizeFunction(DeoptFromFinally_Return);
+    return x + 1;
+  }
+  return x + 2;
+}
+%OptimizeFunctionOnNextCall(DeoptFromFinally_Return);
+assertEquals(24, DeoptFromFinally_Return(23));
+
+
+function DeoptFromFinally_ReThrow(x) {
+  try {
+    throw x;
+  } finally {
+    %DeoptimizeFunction(DeoptFromFinally_ReThrow);
+  }
+  return x + 2;
+}
+%OptimizeFunctionOnNextCall(DeoptFromFinally_ReThrow);
+assertThrows("DeoptFromFinally_ReThrow(new Error)", Error);
index 73cf040..3f82c2f 100644 (file)
@@ -26,7 +26,7 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
-// Flags: --nodead-code-elimination --fold-constants --allow-natives-syntax
+// Flags: --nodead-code-elimination --fold-constants --allow-natives-syntax --nostress-opt
 
 function test(f) {
   f();
diff --git a/deps/v8/test/mjsunit/debug-allscopes-on-debugger.js b/deps/v8/test/mjsunit/debug-allscopes-on-debugger.js
new file mode 100644 (file)
index 0000000..f0613b2
--- /dev/null
@@ -0,0 +1,58 @@
+// 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: --expose-debug-as debug
+
+Debug = debug.Debug
+var exception = null;
+var break_count = 0;
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      assertTrue(exec_state.frameCount() != 0, "FAIL: Empty stack trace");
+      // Count number of expected breakpoints in this source file.
+      if (!break_count) {
+        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 frameMirror = exec_state.frame(0);
+
+      frameMirror.allScopes();
+      var source = frameMirror.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);
+        print("Next step prepared");
+      }
+    }
+  } catch(e) {
+    exception = e;
+    print(e, e.stack);
+  }
+};
+
+Debug.setListener(listener);
+
+var sum = 0;
+(function (){
+  'use strict';
+
+  debugger; // Break 0.
+  var i = 0; // Break 1.
+  i++; // Break 2.
+  i++; // Break 3.
+  return i; // Break 4.
+}()); // Break 5.
+
+assertNull(exception); // Break 6.
+assertEquals(expected_breaks, break_count);
+
+Debug.setListener(null);
index 6948a70..d843ca6 100644 (file)
@@ -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 --allow-natives-syntax
 // Get the Debug object exposed from the debug context global object.
 
 Debug = debug.Debug
@@ -87,13 +87,13 @@ function WrapInCatcher(f, holder) {
 
 function WrapInNativeCall(f) {
   return function() {
-    return Debug.ExecuteInDebugContext(f, true);
+    return %Call(undefined, f);
   };
 }
 
 function WrapInDebuggerCall(f) {
   return function() {
-    return Debug.ExecuteInDebugContext(f, false);
+    return %ExecuteInDebugContext(f);
   };
 }
 
index bb33976..cb9f370 100644 (file)
@@ -26,6 +26,8 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // Flags: --expose-debug-as debug --turbo-deoptimization
+// Flags: --stack-trace-on-illegal
+
 // Get the Debug object exposed from the debug context global object.
 Debug = debug.Debug
 
@@ -98,7 +100,8 @@ function listener(event, exec_state, event_data, data) {
     listenerComplete = true;
   }
   } catch (e) {
-    exception = e
+    exception = e;
+    print(e + "\n" + e.stack);
   };
 };
 
index 7c08120..78a70af 100644 (file)
@@ -1049,6 +1049,30 @@ catch_block_7();
 EndTest();
 
 
+BeginTest("Classes and methods 1");
+
+listener_delegate = function(exec_state) {
+  "use strict"
+  CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Block,
+                   debug.ScopeType.Script,
+                   debug.ScopeType.Global], exec_state);
+  CheckScopeContent({C1: class { m() { debugger; }} }, 1, exec_state);
+};
+
+(function() {
+  "use strict";
+  class C1 {
+    m() {
+      debugger;
+    }
+  }
+  new C1().m();
+})();
+
+EndTest();
+
+
 assertEquals(begin_test_count, break_count,
              'one or more tests did not enter the debugger');
 assertEquals(begin_test_count, end_test_count,
index 4667a71..6543428 100644 (file)
@@ -29,6 +29,7 @@
 
 // Get the Debug object exposed from the debug context global object.
 var Debug = debug.Debug;
+var DebugCommandProcessor = debug.DebugCommandProcessor;
 
 // Accepts a function/closure 'fun' that must have a debugger statement inside.
 // A variable 'variable_name' must be initialized before debugger statement
@@ -291,18 +292,18 @@ RunPauseTest(0, 5, 'p', 2012, 2012, (function Factory() {
 
 // Test value description protocol JSON
 
-assertEquals(true, Debug.TestApi.CommandProcessorResolveValue({value: true}));
+assertEquals(true, DebugCommandProcessor.resolveValue_({value: true}));
 
-assertSame(null, Debug.TestApi.CommandProcessorResolveValue({type: "null"}));
+assertSame(null, DebugCommandProcessor.resolveValue_({type: "null"}));
 assertSame(undefined,
-    Debug.TestApi.CommandProcessorResolveValue({type: "undefined"}));
+    DebugCommandProcessor.resolveValue_({type: "undefined"}));
 
-assertSame("123", Debug.TestApi.CommandProcessorResolveValue(
+assertSame("123", DebugCommandProcessor.resolveValue_(
     {type: "string", stringDescription: "123"}));
-assertSame(123, Debug.TestApi.CommandProcessorResolveValue(
+assertSame(123, DebugCommandProcessor.resolveValue_(
     {type: "number", stringDescription: "123"}));
 
-assertSame(Number, Debug.TestApi.CommandProcessorResolveValue(
+assertSame(Number, DebugCommandProcessor.resolveValue_(
     {handle: Debug.MakeMirror(Number).handle()}));
-assertSame(RunClosureTest, Debug.TestApi.CommandProcessorResolveValue(
+assertSame(RunClosureTest, DebugCommandProcessor.resolveValue_(
     {handle: Debug.MakeMirror(RunClosureTest).handle()}));
index ddf80dc..1dbe1b7 100644 (file)
-// Copyright 2008 the V8 project authors. All rights reserved.\r
-// Redistribution and use in source and binary forms, with or without\r
-// modification, are permitted provided that the following conditions are\r
-// met:\r
-//\r
-//     * Redistributions of source code must retain the above copyright\r
-//       notice, this list of conditions and the following disclaimer.\r
-//     * Redistributions in binary form must reproduce the above\r
-//       copyright notice, this list of conditions and the following\r
-//       disclaimer in the documentation and/or other materials provided\r
-//       with the distribution.\r
-//     * Neither the name of Google Inc. nor the names of its\r
-//       contributors may be used to endorse or promote products derived\r
-//       from this software without specific prior written permission.\r
-//\r
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
-\r
-// Flags: --expose-debug-as debug\r
-// For this test to work this file MUST have CR LF line endings.\r
-function a() { b(); };\r
-function    b() {\r
-  c(true);\r
-};\r
-  function c(x) {\r
-    if (x) {\r
-      return 1;\r
-    } else {\r
-      return 1;\r
-    }\r
-  };\r
-function d(x) {\r
-  x = 1 ;\r
-  x = 2 ;\r
-  x = 3 ;\r
-  x = 4 ;\r
-  x = 5 ;\r
-  x = 6 ;\r
-  x = 7 ;\r
-  x = 8 ;\r
-  x = 9 ;\r
-  x = 10;\r
-  x = 11;\r
-  x = 12;\r
-  x = 13;\r
-  x = 14;\r
-  x = 15;\r
-}\r
-\r
-// Get the Debug object exposed from the debug context global object.\r
-Debug = debug.Debug\r
-\r
-// This is the number of comment lines above the first test function.\r
-var comment_lines = 29;\r
-\r
-// This is the last position in the entire file (note: this equals\r
-// file size of <debug-sourceinfo.js> - 1, since starting at 0).\r
-var last_position = 14312;\r
-// This is the last line of entire file (note: starting at 0).\r
-var last_line = 351;\r
-// This is the last column of last line (note: starting at 0 and +2, due\r
-// to trailing <CR><LF>).\r
-var last_column = 2;\r
-\r
-// This magic number is the length or the first line comment (actually number\r
-// of characters before 'function a(...'.\r
-var comment_line_length = 1726;\r
-var start_a = 10 + comment_line_length;\r
-var start_b = 37 + comment_line_length;\r
-var start_c = 71 + comment_line_length;\r
-var start_d = 163 + comment_line_length;\r
-\r
-// The position of the first line of d(), i.e. "x = 1 ;".\r
-var start_code_d = start_d + 7;\r
-// The line # of the first line of d() (note: starting at 0).\r
-var start_line_d = 41;\r
-var line_length_d = 11;\r
-var num_lines_d = 15;\r
-\r
-assertEquals(start_a, Debug.sourcePosition(a));\r
-assertEquals(start_b, Debug.sourcePosition(b));\r
-assertEquals(start_c, Debug.sourcePosition(c));\r
-assertEquals(start_d, Debug.sourcePosition(d));\r
-\r
-var script = Debug.findScript(a);\r
-assertTrue(script.data === Debug.findScript(b).data);\r
-assertTrue(script.data === Debug.findScript(c).data);\r
-assertTrue(script.data === Debug.findScript(d).data);\r
-assertTrue(script.source === Debug.findScript(b).source);\r
-assertTrue(script.source === Debug.findScript(c).source);\r
-assertTrue(script.source === Debug.findScript(d).source);\r
-\r
-// Test that when running through source positions the position, line and\r
-// column progresses as expected.\r
-var position;\r
-var line;\r
-var column;\r
-for (var p = 0; p < 100; p++) {\r
-  var location = script.locationFromPosition(p);\r
-  if (p > 0) {\r
-    assertEquals(position + 1, location.position);\r
-    if (line == location.line) {\r
-      assertEquals(column + 1, location.column);\r
-    } else {\r
-      assertEquals(line + 1, location.line);\r
-      assertEquals(0, location.column);\r
-    }\r
-  } else {\r
-    assertEquals(0, location.position);\r
-    assertEquals(0, location.line);\r
-    assertEquals(0, location.column);\r
-  }\r
-\r
-  // Remember the location.\r
-  position = location.position;\r
-  line = location.line;\r
-  column = location.column;\r
-}\r
-\r
-// Every line of d() is the same length.  Verify we can loop through all\r
-// positions and find the right line # for each.\r
-var p = start_code_d;\r
-for (line = 0; line < num_lines_d; line++) {\r
-  for (column = 0; column < line_length_d; column++) {\r
-    var location = script.locationFromPosition(p);\r
-    assertEquals(p, location.position);\r
-    assertEquals(start_line_d + line, location.line);\r
-    assertEquals(column, location.column);\r
-    p++;\r
-  }\r
-}\r
-\r
-// Test first position.\r
-assertEquals(0, script.locationFromPosition(0).position);\r
-assertEquals(0, script.locationFromPosition(0).line);\r
-assertEquals(0, script.locationFromPosition(0).column);\r
-\r
-// Test second position.\r
-assertEquals(1, script.locationFromPosition(1).position);\r
-assertEquals(0, script.locationFromPosition(1).line);\r
-assertEquals(1, script.locationFromPosition(1).column);\r
-\r
-// Test first position in function a().\r
-assertEquals(start_a, script.locationFromPosition(start_a).position);\r
-assertEquals(0, script.locationFromPosition(start_a).line - comment_lines);\r
-assertEquals(10, script.locationFromPosition(start_a).column);\r
-\r
-// Test first position in function b().\r
-assertEquals(start_b, script.locationFromPosition(start_b).position);\r
-assertEquals(1, script.locationFromPosition(start_b).line - comment_lines);\r
-assertEquals(13, script.locationFromPosition(start_b).column);\r
-\r
-// Test first position in function c().\r
-assertEquals(start_c, script.locationFromPosition(start_c).position);\r
-assertEquals(4, script.locationFromPosition(start_c).line - comment_lines);\r
-assertEquals(12, script.locationFromPosition(start_c).column);\r
-\r
-// Test first position in function d().\r
-assertEquals(start_d, script.locationFromPosition(start_d).position);\r
-assertEquals(11, script.locationFromPosition(start_d).line - comment_lines);\r
-assertEquals(10, script.locationFromPosition(start_d).column);\r
-\r
-// Test first line.\r
-assertEquals(0, script.locationFromLine().position);\r
-assertEquals(0, script.locationFromLine().line);\r
-assertEquals(0, script.locationFromLine().column);\r
-assertEquals(0, script.locationFromLine(0).position);\r
-assertEquals(0, script.locationFromLine(0).line);\r
-assertEquals(0, script.locationFromLine(0).column);\r
-\r
-// Test first line column 1.\r
-assertEquals(1, script.locationFromLine(0, 1).position);\r
-assertEquals(0, script.locationFromLine(0, 1).line);\r
-assertEquals(1, script.locationFromLine(0, 1).column);\r
-\r
-// Test first line offset 1.\r
-assertEquals(1, script.locationFromLine(0, 0, 1).position);\r
-assertEquals(0, script.locationFromLine(0, 0, 1).line);\r
-assertEquals(1, script.locationFromLine(0, 0, 1).column);\r
-\r
-// Test offset function a().\r
-assertEquals(start_a, script.locationFromLine(void 0, void 0, start_a).position);\r
-assertEquals(0, script.locationFromLine(void 0, void 0, start_a).line - comment_lines);\r
-assertEquals(10, script.locationFromLine(void 0, void 0, start_a).column);\r
-assertEquals(start_a, script.locationFromLine(0, void 0, start_a).position);\r
-assertEquals(0, script.locationFromLine(0, void 0, start_a).line - comment_lines);\r
-assertEquals(10, script.locationFromLine(0, void 0, start_a).column);\r
-assertEquals(start_a, script.locationFromLine(0, 0, start_a).position);\r
-assertEquals(0, script.locationFromLine(0, 0, start_a).line - comment_lines);\r
-assertEquals(10, script.locationFromLine(0, 0, start_a).column);\r
-\r
-// Test second line offset function a().\r
-assertEquals(start_a + 14, script.locationFromLine(1, 0, start_a).position);\r
-assertEquals(1, script.locationFromLine(1, 0, start_a).line - comment_lines);\r
-assertEquals(0, script.locationFromLine(1, 0, start_a).column);\r
-\r
-// Test second line column 2 offset function a().\r
-assertEquals(start_a + 14 + 2, script.locationFromLine(1, 2, start_a).position);\r
-assertEquals(1, script.locationFromLine(1, 2, start_a).line - comment_lines);\r
-assertEquals(2, script.locationFromLine(1, 2, start_a).column);\r
-\r
-// Test offset function b().\r
-assertEquals(start_b, script.locationFromLine(0, 0, start_b).position);\r
-assertEquals(1, script.locationFromLine(0, 0, start_b).line - comment_lines);\r
-assertEquals(13, script.locationFromLine(0, 0, start_b).column);\r
-\r
-// Test second line offset function b().\r
-assertEquals(start_b + 6, script.locationFromLine(1, 0, start_b).position);\r
-assertEquals(2, script.locationFromLine(1, 0, start_b).line - comment_lines);\r
-assertEquals(0, script.locationFromLine(1, 0, start_b).column);\r
-\r
-// Test second line column 11 offset function b().\r
-assertEquals(start_b + 6 + 11, script.locationFromLine(1, 11, start_b).position);\r
-assertEquals(2, script.locationFromLine(1, 11, start_b).line - comment_lines);\r
-assertEquals(11, script.locationFromLine(1, 11, start_b).column);\r
-\r
-// Test second line column 12 offset function b. Second line in b is 11 long\r
-// using column 12 wraps to next line.\r
-assertEquals(start_b + 6 + 12, script.locationFromLine(1, 12, start_b).position);\r
-assertEquals(3, script.locationFromLine(1, 12, start_b).line - comment_lines);\r
-assertEquals(0, script.locationFromLine(1, 12, start_b).column);\r
-\r
-// Test the Debug.findSourcePosition which wraps SourceManager.\r
-assertEquals(0 + start_a, Debug.findFunctionSourceLocation(a, 0, 0).position);\r
-assertEquals(0 + start_b, Debug.findFunctionSourceLocation(b, 0, 0).position);\r
-assertEquals(6 + start_b, Debug.findFunctionSourceLocation(b, 1, 0).position);\r
-assertEquals(8 + start_b, Debug.findFunctionSourceLocation(b, 1, 2).position);\r
-assertEquals(18 + start_b, Debug.findFunctionSourceLocation(b, 2, 0).position);\r
-assertEquals(0 + start_c, Debug.findFunctionSourceLocation(c, 0, 0).position);\r
-assertEquals(7 + start_c, Debug.findFunctionSourceLocation(c, 1, 0).position);\r
-assertEquals(21 + start_c, Debug.findFunctionSourceLocation(c, 2, 0).position);\r
-assertEquals(38 + start_c, Debug.findFunctionSourceLocation(c, 3, 0).position);\r
-assertEquals(52 + start_c, Debug.findFunctionSourceLocation(c, 4, 0).position);\r
-assertEquals(69 + start_c, Debug.findFunctionSourceLocation(c, 5, 0).position);\r
-assertEquals(76 + start_c, Debug.findFunctionSourceLocation(c, 6, 0).position);\r
-assertEquals(0 + start_d, Debug.findFunctionSourceLocation(d, 0, 0).position);\r
-assertEquals(7 + start_d, Debug.findFunctionSourceLocation(d, 1, 0).position);\r
-for (i = 1; i <= num_lines_d; i++) {\r
-  assertEquals(7 + (i * line_length_d) + start_d, Debug.findFunctionSourceLocation(d, (i + 1), 0).position);\r
-}\r
-assertEquals(175 + start_d, Debug.findFunctionSourceLocation(d, 17, 0).position);\r
-\r
-// Make sure invalid inputs work properly.\r
-assertEquals(0, script.locationFromPosition(-1).line);\r
-assertEquals(null, script.locationFromPosition(last_position + 1));\r
-\r
-// Test last position.\r
-assertEquals(last_position, script.locationFromPosition(last_position).position);\r
-assertEquals(last_line, script.locationFromPosition(last_position).line);\r
-assertEquals(last_column, script.locationFromPosition(last_position).column);\r
-\r
-// Test source line and restriction. All the following tests start from line 1\r
-// column 2 in function b, which is the call to c.\r
-//   c(true);\r
-//   ^\r
-\r
-var location;\r
-\r
-location = script.locationFromLine(1, 0, start_b);\r
-assertEquals('  c(true);', location.sourceText());\r
-\r
-result = ['c', ' c', ' c(', '  c(', '  c(t']\r
-for (var i = 1; i <= 5; i++) {\r
-  location = script.locationFromLine(1, 2, start_b);\r
-  location.restrict(i);\r
-  assertEquals(result[i - 1], location.sourceText());\r
-}\r
-\r
-location = script.locationFromLine(1, 2, start_b);\r
-location.restrict(1, 0);\r
-assertEquals('c', location.sourceText());\r
-\r
-location = script.locationFromLine(1, 2, start_b);\r
-location.restrict(2, 0);\r
-assertEquals('c(', location.sourceText());\r
-\r
-location = script.locationFromLine(1, 2, start_b);\r
-location.restrict(2, 1);\r
-assertEquals(' c', location.sourceText());\r
-\r
-location = script.locationFromLine(1, 2, start_b);\r
-location.restrict(2, 2);\r
-assertEquals(' c', location.sourceText());\r
-\r
-location = script.locationFromLine(1, 2, start_b);\r
-location.restrict(2, 3);\r
-assertEquals(' c', location.sourceText());\r
-\r
-location = script.locationFromLine(1, 2, start_b);\r
-location.restrict(3, 1);\r
-assertEquals(' c(', location.sourceText());\r
-\r
-location = script.locationFromLine(1, 2, start_b);\r
-location.restrict(5, 0);\r
-assertEquals('c(tru', location.sourceText());\r
-\r
-location = script.locationFromLine(1, 2, start_b);\r
-location.restrict(5, 2);\r
-assertEquals('  c(t', location.sourceText());\r
-\r
-location = script.locationFromLine(1, 2, start_b);\r
-location.restrict(5, 4);\r
-assertEquals('  c(t', location.sourceText());\r
-\r
-// All the following tests start from line 1 column 10 in function b, which is\r
-// the final character.\r
-//   c(true);\r
-//          ^\r
-\r
-location = script.locationFromLine(1, 10, start_b);\r
-location.restrict(5, 0);\r
-assertEquals('rue);', location.sourceText());\r
-\r
-location = script.locationFromLine(1, 10, start_b);\r
-location.restrict(7, 0);\r
-assertEquals('(true);', location.sourceText());\r
-\r
-// All the following tests start from line 1 column 0 in function b, which is\r
-// the first character.\r
-//   c(true);\r
-//^\r
-\r
-location = script.locationFromLine(1, 0, start_b);\r
-location.restrict(5, 0);\r
-assertEquals('  c(t', location.sourceText());\r
-\r
-location = script.locationFromLine(1, 0, start_b);\r
-location.restrict(5, 4);\r
-assertEquals('  c(t', location.sourceText());\r
-\r
-location = script.locationFromLine(1, 0, start_b);\r
-location.restrict(7, 0);\r
-assertEquals('  c(tru', location.sourceText());\r
-\r
-location = script.locationFromLine(1, 0, start_b);\r
-location.restrict(7, 6);\r
-assertEquals('  c(tru', location.sourceText());\r
-\r
-// Test that script.sourceLine(line) works.\r
-for (line = 0; line < num_lines_d; line++) {\r
-  var line_content_regexp = new RegExp("  x = " + (line + 1));\r
-  assertTrue(line_content_regexp.test(script.sourceLine(start_line_d + line)));\r
-}\r
+// Copyright 2008 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
+function a() { b(); };
+function    b() {
+  c(true);
+};
+  function c(x) {
+    if (x) {
+      return 1;
+    } else {
+      return 1;
+    }
+  };
+function d(x) {
+  x = 1 ;
+  x = 2 ;
+  x = 3 ;
+  x = 4 ;
+  x = 5 ;
+  x = 6 ;
+  x = 7 ;
+  x = 8 ;
+  x = 9 ;
+  x = 10;
+  x = 11;
+  x = 12;
+  x = 13;
+  x = 14;
+  x = 15;
+}
+
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// This is the number of comment lines above the first test function.
+var comment_lines = 28;
+
+// This is the last position in the entire file (note: this equals
+// file size of <debug-sourceinfo.js> - 1, since starting at 0).
+var last_position = 11337;
+// This is the last line of entire file (note: starting at 0).
+var last_line = 265;
+// This is the last column of last line (note: starting at 0 and +1, due
+// to trailing <LF>).
+var last_column = 1;
+
+// This magic number is the length or the first line comment (actually number
+// of characters before 'function a(...'.
+var comment_line_length = 1633;
+var start_a = 9 + comment_line_length;
+var start_b = 35 + comment_line_length;
+var start_c = 66 + comment_line_length;
+var start_d = 151 + comment_line_length;
+
+// The position of the first line of d(), i.e. "x = 1 ;".
+var start_code_d = start_d + 6;
+// The line # of the first line of d() (note: starting at 0).
+var start_line_d = 40;
+var line_length_d = 10;
+var num_lines_d = 15;
+
+assertEquals(start_a, Debug.sourcePosition(a));
+assertEquals(start_b, Debug.sourcePosition(b));
+assertEquals(start_c, Debug.sourcePosition(c));
+assertEquals(start_d, Debug.sourcePosition(d));
+
+var script = Debug.findScript(a);
+assertTrue(script.data === Debug.findScript(b).data);
+assertTrue(script.data === Debug.findScript(c).data);
+assertTrue(script.data === Debug.findScript(d).data);
+assertTrue(script.source === Debug.findScript(b).source);
+assertTrue(script.source === Debug.findScript(c).source);
+assertTrue(script.source === Debug.findScript(d).source);
+
+// Test that when running through source positions the position, line and
+// column progresses as expected.
+var position;
+var line;
+var column;
+for (var p = 0; p < 100; p++) {
+  var location = script.locationFromPosition(p);
+  if (p > 0) {
+    assertEquals(position + 1, location.position);
+    if (line == location.line) {
+      assertEquals(column + 1, location.column);
+    } else {
+      assertEquals(line + 1, location.line);
+      assertEquals(0, location.column);
+    }
+  } else {
+    assertEquals(0, location.position);
+    assertEquals(0, location.line);
+    assertEquals(0, location.column);
+  }
+
+  // Remember the location.
+  position = location.position;
+  line = location.line;
+  column = location.column;
+}
+
+// Every line of d() is the same length.  Verify we can loop through all
+// positions and find the right line # for each.
+var p = start_code_d;
+for (line = 0; line < num_lines_d; line++) {
+  for (column = 0; column < line_length_d; column++) {
+    var location = script.locationFromPosition(p);
+    assertEquals(p, location.position);
+    assertEquals(start_line_d + line, location.line);
+    assertEquals(column, location.column);
+    p++;
+  }
+}
+
+// Test first position.
+assertEquals(0, script.locationFromPosition(0).position);
+assertEquals(0, script.locationFromPosition(0).line);
+assertEquals(0, script.locationFromPosition(0).column);
+
+// Test second position.
+assertEquals(1, script.locationFromPosition(1).position);
+assertEquals(0, script.locationFromPosition(1).line);
+assertEquals(1, script.locationFromPosition(1).column);
+
+// Test first position in function a().
+assertEquals(start_a, script.locationFromPosition(start_a).position);
+assertEquals(0, script.locationFromPosition(start_a).line - comment_lines);
+assertEquals(10, script.locationFromPosition(start_a).column);
+
+// Test first position in function b().
+assertEquals(start_b, script.locationFromPosition(start_b).position);
+assertEquals(1, script.locationFromPosition(start_b).line - comment_lines);
+assertEquals(13, script.locationFromPosition(start_b).column);
+
+// Test first position in function c().
+assertEquals(start_c, script.locationFromPosition(start_c).position);
+assertEquals(4, script.locationFromPosition(start_c).line - comment_lines);
+assertEquals(12, script.locationFromPosition(start_c).column);
+
+// Test first position in function d().
+assertEquals(start_d, script.locationFromPosition(start_d).position);
+assertEquals(11, script.locationFromPosition(start_d).line - comment_lines);
+assertEquals(10, script.locationFromPosition(start_d).column);
+
+// Test first line.
+assertEquals(0, script.locationFromLine().position);
+assertEquals(0, script.locationFromLine().line);
+assertEquals(0, script.locationFromLine().column);
+assertEquals(0, script.locationFromLine(0).position);
+assertEquals(0, script.locationFromLine(0).line);
+assertEquals(0, script.locationFromLine(0).column);
+
+// Test first line column 1.
+assertEquals(1, script.locationFromLine(0, 1).position);
+assertEquals(0, script.locationFromLine(0, 1).line);
+assertEquals(1, script.locationFromLine(0, 1).column);
+
+// Test first line offset 1.
+assertEquals(1, script.locationFromLine(0, 0, 1).position);
+assertEquals(0, script.locationFromLine(0, 0, 1).line);
+assertEquals(1, script.locationFromLine(0, 0, 1).column);
+
+// Test offset function a().
+assertEquals(start_a, script.locationFromLine(void 0, void 0, start_a).position);
+assertEquals(0, script.locationFromLine(void 0, void 0, start_a).line - comment_lines);
+assertEquals(10, script.locationFromLine(void 0, void 0, start_a).column);
+assertEquals(start_a, script.locationFromLine(0, void 0, start_a).position);
+assertEquals(0, script.locationFromLine(0, void 0, start_a).line - comment_lines);
+assertEquals(10, script.locationFromLine(0, void 0, start_a).column);
+assertEquals(start_a, script.locationFromLine(0, 0, start_a).position);
+assertEquals(0, script.locationFromLine(0, 0, start_a).line - comment_lines);
+assertEquals(10, script.locationFromLine(0, 0, start_a).column);
+
+// Test second line offset function a().
+assertEquals(start_a + 13, script.locationFromLine(1, 0, start_a).position);
+assertEquals(1, script.locationFromLine(1, 0, start_a).line - comment_lines);
+assertEquals(0, script.locationFromLine(1, 0, start_a).column);
+
+// Test second line column 2 offset function a().
+assertEquals(start_a + 13 + 1, script.locationFromLine(1, 1, start_a).position);
+assertEquals(1, script.locationFromLine(1, 2, start_a).line - comment_lines);
+assertEquals(2, script.locationFromLine(1, 2, start_a).column);
+
+// Test offset function b().
+assertEquals(start_b, script.locationFromLine(0, 0, start_b).position);
+assertEquals(1, script.locationFromLine(0, 0, start_b).line - comment_lines);
+assertEquals(13, script.locationFromLine(0, 0, start_b).column);
+
+// Test second line offset function b().
+assertEquals(start_b + 5, script.locationFromLine(1, 0, start_b).position);
+assertEquals(2, script.locationFromLine(1, 0, start_b).line - comment_lines);
+assertEquals(0, script.locationFromLine(1, 0, start_b).column);
+
+// Test second line column 10 offset function b().
+assertEquals(start_b + 5 + 10, script.locationFromLine(1, 10, start_b).position);
+assertEquals(2, script.locationFromLine(1, 10, start_b).line - comment_lines);
+assertEquals(10, script.locationFromLine(1, 10, start_b).column);
+
+// Test second line column 11 offset function b. Second line in b is 10 long
+// using column 11 wraps to next line.
+assertEquals(start_b + 5 + 11, script.locationFromLine(1, 11, start_b).position);
+assertEquals(3, script.locationFromLine(1, 11, start_b).line - comment_lines);
+assertEquals(0, script.locationFromLine(1, 11, start_b).column);
+
+// Test the Debug.findSourcePosition which wraps SourceManager.
+assertEquals(0 + start_a, Debug.findFunctionSourceLocation(a, 0, 0).position);
+assertEquals(0 + start_b, Debug.findFunctionSourceLocation(b, 0, 0).position);
+assertEquals(5 + start_b, Debug.findFunctionSourceLocation(b, 1, 0).position);
+assertEquals(7 + start_b, Debug.findFunctionSourceLocation(b, 1, 2).position);
+assertEquals(16 + start_b, Debug.findFunctionSourceLocation(b, 2, 0).position);
+assertEquals(0 + start_c, Debug.findFunctionSourceLocation(c, 0, 0).position);
+assertEquals(6 + start_c, Debug.findFunctionSourceLocation(c, 1, 0).position);
+assertEquals(19 + start_c, Debug.findFunctionSourceLocation(c, 2, 0).position);
+assertEquals(35 + start_c, Debug.findFunctionSourceLocation(c, 3, 0).position);
+assertEquals(48 + start_c, Debug.findFunctionSourceLocation(c, 4, 0).position);
+assertEquals(64 + start_c, Debug.findFunctionSourceLocation(c, 5, 0).position);
+assertEquals(70 + start_c, Debug.findFunctionSourceLocation(c, 6, 0).position);
+assertEquals(0 + start_d, Debug.findFunctionSourceLocation(d, 0, 0).position);
+assertEquals(6 + start_d, Debug.findFunctionSourceLocation(d, 1, 0).position);
+for (i = 1; i <= num_lines_d; i++) {
+  assertEquals(6 + (i * line_length_d) + start_d, Debug.findFunctionSourceLocation(d, (i + 1), 0).position);
+}
+assertEquals(158 + start_d, Debug.findFunctionSourceLocation(d, 17, 0).position);
+
+// Make sure invalid inputs work properly.
+assertEquals(0, script.locationFromPosition(-1).line);
+assertEquals(null, script.locationFromPosition(last_position + 1));
+
+// Test last position.
+assertEquals(last_position, script.locationFromPosition(last_position).position);
+assertEquals(last_line, script.locationFromPosition(last_position).line);
+assertEquals(last_column, script.locationFromPosition(last_position).column);
+
+// Test that script.sourceLine(line) works.
+var location;
+
+for (line = 0; line < num_lines_d; line++) {
+  var line_content_regexp = new RegExp("  x = " + (line + 1));
+  assertTrue(line_content_regexp.test(script.sourceLine(start_line_d + line)));
+}
index c8c346b..1710942 100644 (file)
@@ -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: --turbo-filter=g --allow-natives-syntax
+// Flags: --expose-debug-as debug --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
diff --git a/deps/v8/test/mjsunit/debug-stepframe-clearing.js b/deps/v8/test/mjsunit/debug-stepframe-clearing.js
new file mode 100644 (file)
index 0000000..c440e78
--- /dev/null
@@ -0,0 +1,97 @@
+// 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: --expose-debug-as debug
+
+// This test ensures that IC learning doesn't interfere with stepping into
+// property accessor. f1()'s ICs are allowed to learn to a monomorphic state,
+// and the breakpoints flooding get() are allowed to expire, then we ensure
+// that we can step into get() again later (when k == 1).
+function f1() {
+  for (var k = 0; k < 2; k++) {     // Break 1
+    var v10 = 0;                    // Line 2
+    for (var i = 0; i < 10; i++) {  // Line 3
+      var v12 = o.slappy;           // Line 4
+      var v13 = 3                   // Line 5
+    }                               // Line 6
+    print("break here");            // Break 3
+  }                                 // Line 8
+  print("exiting f1");              // Line 9 (dummy break)
+}
+
+function get() {
+  var g0 = 0;                       // Break 2
+  var g1 = 1;
+  return 3;
+}
+
+
+var o = {};
+Object.defineProperty(o, "slappy", { get : get });
+
+Debug = debug.Debug;
+var break_count = 0
+var exception = null;
+var bp_f1_line7;
+var bp_f1_line9;
+
+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);
+    var match_value = parseInt(match[1]);
+
+    if (break_count >= 0 && break_count < 2) {
+      // 0, 1: Keep stepping through frames.
+      assertEquals(break_count, match_value);
+      exec_state.prepareStep(Debug.StepAction.StepFrame, 1);
+    } else if (break_count === 2) {
+      // 2: let the code run to a breakpoint we set. The load should
+      // go monomorphic.
+      assertEquals(break_count, match_value);
+    } else if (break_count === 3) {
+      // 3: back to frame stepping. Does the monomorphic slappy accessor
+      // call still have the ability to break like before?
+      assertEquals(break_count, match_value);
+      Debug.clearBreakPoint(bp_f1_line7);
+      exec_state.prepareStep(Debug.StepAction.StepFrame, 1);
+    } else {
+      assertEquals(4, break_count);
+      assertEquals(2, match_value);
+      // Apparently we can still stop in the accessor even though we cleared
+      // breakpoints earlier and there was a monomorphic step.
+      // Allow running to completion now.
+      Debug.clearBreakPoint(bp_f1_line9);
+    }
+
+    break_count++;
+  } catch (e) {
+    print(e + e.stack);
+    exception = e;
+  }
+}
+
+for (var j = 1; j < 3; j++) {
+  break_count = 0;
+  Debug.setListener(listener);
+
+  // Breakpoints are added here rather than in the listener because their
+  // addition causes a full (clearing) gc that clears type feedback when we
+  // want to let it build up. Also, bp_f1_line9 is set simply because if we
+  // handled then deleted bp_f1_line7, then the debugger clears DebugInfo from
+  // f1 while we are still using it, again, resetting type feedback which is
+  // undesirable.
+  bp_f1_line7 = Debug.setBreakPoint(f1, 7);
+  bp_f1_line9 = Debug.setBreakPoint(f1, 9);
+
+  debugger;                         // Break 0
+  f1();
+  Debug.setListener(null);
+  assertTrue(break_count === 5);
+}
+
+assertNull(exception);
index fa728e0..c2702f7 100644 (file)
@@ -37,15 +37,17 @@ function listener(event, exec_state, event_data, data) {
 };
 
 Debug.setListener(listener);
+var bound_callback = callback.bind(null);
 
 debugger; // Break 0.
 [1,2].forEach(callback); // Break 1.
+[3,4].forEach(bound_callback); // Break 6.
 
 function callback(x) {
-  return x; // Break 2. // Break 4.
-} // Break 3. // Break 5.
+  return x; // Break 2. // Break 4. // Break 7. // Break 9.
+} // Break 3. // Break 5. // Break 8. // Break 10.
 
-assertNull(exception); // Break 6.
+assertNull(exception); // Break 11.
 assertEquals(expected_breaks, break_count);
 
 Debug.setListener(null);
@@ -1,8 +1,6 @@
 // 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.
-//
-// Flags: --harmony-scoping
 
 // Test for conflicting variable bindings.
 
diff --git a/deps/v8/test/mjsunit/es6/block-const-assign.js b/deps/v8/test/mjsunit/es6/block-const-assign.js
new file mode 100644 (file)
index 0000000..f78faa6
--- /dev/null
@@ -0,0 +1,160 @@
+// 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:
+//
+//     * 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-computed-property-names
+
+// Test that we throw early syntax errors in harmony mode
+// when using an immutable binding in an assigment or with
+// prefix/postfix decrement/increment operators.
+
+"use strict";
+
+const decls = [
+  // Const declaration.
+  function(use) { return "const c = 1; " + use + ";" }, TypeError,
+  function(use) { return "const x = 0, c = 1; " + use + ";" }, TypeError,
+  function(use) { return "const c = 1, x = (" + use + ");" }, TypeError,
+  function(use) { return use + "; const c = 1;" }, ReferenceError,
+  function(use) { return use + "; const x = 0, c = 1;" }, ReferenceError,
+  function(use) { return "const x = (" + use + "), c = 1;" }, ReferenceError,
+  function(use) { return "const c = (" + use + ");" }, ReferenceError,
+
+  // Function expression.
+  function(use) { return "(function c() { " + use + "; })();"; }, TypeError,
+  // TODO(rossberg): Once we have default parameters, test using 'c' there.
+
+  // Class expression.
+  function(use) {
+    return "new class c { constructor() { " + use + " } };";
+  }, TypeError,
+  function(use) {
+    return "(new class c { m() { " + use + " } }).m();";
+  }, TypeError,
+  function(use) {
+    return "(new class c { get a() { " + use + " } }).a;";
+  }, TypeError,
+  function(use) {
+    return "(new class c { set a(x) { " + use + " } }).a = 0;";
+  }, TypeError,
+  function(use) {
+    return "(class c { static m() { " + use + " } }).s();";
+  }, TypeError,
+  function(use) {
+    return "(class c extends (" + use + ") {});";
+  }, ReferenceError,
+  function(use) {
+    return "(class c { [" + use + "]() {} });";
+  }, ReferenceError,
+  function(use) {
+    return "(class c { get [" + use + "]() {} });";
+  }, ReferenceError,
+  function(use) {
+    return "(class c { set [" + use + "](x) {} });";
+  }, ReferenceError,
+  function(use) {
+    return "(class c { static [" + use + "]() {} });";
+  }, ReferenceError,
+
+  // For loop.
+  function(use) {
+    return "for (const c = 0; " + use + ";) {}"
+  }, TypeError,
+  function(use) {
+    return "for (const x = 0, c = 0; " + use + ";) {}"
+  }, TypeError,
+  function(use) {
+    return "for (const c = 0; ; " + use + ") {}"
+  }, TypeError,
+  function(use) {
+    return "for (const x = 0, c = 0; ; " + use + ") {}"
+  }, TypeError,
+  function(use) {
+    return "for (const c = 0; ;) { " + use + "; }"
+  }, TypeError,
+  function(use) {
+    return "for (const x = 0, c = 0; ;) { " + use + "; }"
+  }, TypeError,
+  function(use) {
+    return "for (const c in {a: 1}) { " + use + "; }"
+  }, TypeError,
+  function(use) {
+    return "for (const c of [1]) { " + use + "; }"
+  }, TypeError,
+  function(use) {
+    return "for (const x = (" + use + "), c = 0; ;) {}"
+  }, ReferenceError,
+  function(use) {
+    return "for (const c = (" + use + "); ;) {}"
+  }, ReferenceError,
+]
+
+let uses = [
+  'c = 1',
+  'c += 1',
+  '++c',
+  'c--',
+];
+
+let declcontexts = [
+  function(decl) { return decl; },
+  function(decl) { return "eval(\'" + decl + "\')"; },
+  function(decl) { return "{ " + decl + " }"; },
+  function(decl) { return "(function() { " + decl + " })()"; },
+];
+
+let usecontexts = [
+  function(use) { return use; },
+  function(use) { return "eval(\"" + use + "\")"; },
+  function(use) { return "(function() { " + use + " })()"; },
+  function(use) { return "(function() { eval(\"" + use + "\"); })()"; },
+  function(use) { return "eval(\"(function() { " + use + "; })\")()"; },
+];
+
+function Test(program, error) {
+  program = "'use strict'; " + program;
+  try {
+    print(program, "  // throw " + error.name);
+    eval(program);
+  } catch (e) {
+    assertInstanceof(e, error);
+    if (e === TypeError) {
+      assertTrue(e.toString().indexOf("Assignment to constant variable") >= 0);
+    }
+    return;
+  }
+  assertUnreachable();
+}
+
+for (var d = 0; d < decls.length; d += 2) {
+  for (var u = 0; u < uses.length; ++u) {
+    for (var o = 0; o < declcontexts.length; ++o) {
+      for (var i = 0; i < usecontexts.length; ++i) {
+        Test(declcontexts[o](decls[d](usecontexts[i](uses[u]))), decls[d + 1]);
+      }
+    }
+  }
+}
@@ -25,8 +25,6 @@
 // (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
-
 function CheckException(e) {
   var string = e.toString();
   assertInstanceof(e, SyntaxError);
similarity index 99%
rename from deps/v8/test/mjsunit/harmony/block-for.js
rename to deps/v8/test/mjsunit/es6/block-for.js
index 110f1cc..b91af01 100644 (file)
@@ -24,9 +24,6 @@
 // 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
-
 "use strict";
 
 function props(x) {
@@ -147,7 +144,7 @@ function closure_in_for_cond() {
     assertEquals(k, a[k]());
   }
 }
-closure_in_for_next();
+closure_in_for_cond();
 
 
 function closure_in_for_next() {
similarity index 99%
rename from deps/v8/test/mjsunit/harmony/block-leave.js
rename to deps/v8/test/mjsunit/es6/block-leave.js
index 87d35b3..338631b 100644 (file)
@@ -25,8 +25,6 @@
 // (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
-
 "use strict";
 
 // We want to test the context chain shape.  In each of the tests cases
@@ -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: --allow-natives-syntax
 
 "use strict";
 
@@ -25,8 +25,6 @@
 // (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 let declarations in various settings.
 
 "use strict";
@@ -70,8 +68,8 @@ TestLocalThrows("do let x; while (false)", SyntaxError);
 TestLocalThrows("while (false) let x;", SyntaxError);
 TestLocalThrows("label: let x;", SyntaxError);
 TestLocalThrows("for (;false;) let x;", SyntaxError);
-TestLocalThrows("switch (true) { case true: let x; }", SyntaxError);
-TestLocalThrows("switch (true) { default: let x; }", SyntaxError);
+TestLocalDoesNotThrow("switch (true) { case true: let x; }");
+TestLocalDoesNotThrow("switch (true) { default: let x; }");
 
 // Test const declarations with initialisers in statement positions.
 TestLocalThrows("if (true) const x = 1;", SyntaxError);
@@ -80,8 +78,8 @@ TestLocalThrows("do const x = 1; while (false)", SyntaxError);
 TestLocalThrows("while (false) const x = 1;", SyntaxError);
 TestLocalThrows("label: const x = 1;", SyntaxError);
 TestLocalThrows("for (;false;) const x = 1;", SyntaxError);
-TestLocalThrows("switch (true) { case true: const x = 1; }", SyntaxError);
-TestLocalThrows("switch (true) { default: const x = 1; }", SyntaxError);
+TestLocalDoesNotThrow("switch (true) { case true: const x = 1; }");
+TestLocalDoesNotThrow("switch (true) { default: const x = 1; }");
 
 // Test const declarations without initialisers.
 TestLocalThrows("const x;", SyntaxError);
@@ -149,11 +147,11 @@ function f() {
 f();
 
 // Test function declarations in statement position in strict mode.
-TestLocalThrows("function f() { if (true) function g() {}", SyntaxError);
-TestLocalThrows("function f() { if (true) {} else function g() {}", SyntaxError);
-TestLocalThrows("function f() { do function g() {} while (false)", SyntaxError);
-TestLocalThrows("function f() { while (false) function g() {}", SyntaxError);
-TestLocalThrows("function f() { label: function g() {}", SyntaxError);
-TestLocalThrows("function f() { for (;false;) function g() {}", SyntaxError);
-TestLocalThrows("function f() { switch (true) { case true: function g() {} }", SyntaxError);
-TestLocalThrows("function f() { switch (true) { default: function g() {} }", SyntaxError);
+TestLocalThrows("function f() { if (true) function g() {} }", SyntaxError);
+TestLocalThrows("function f() { if (true) {} else function g() {} }", SyntaxError);
+TestLocalThrows("function f() { do function g() {} while (false) }", SyntaxError);
+TestLocalThrows("function f() { while (false) function g() {} }", SyntaxError);
+TestLocalThrows("function f() { label: function g() {} }", SyntaxError);
+TestLocalThrows("function f() { for (;false;) function g() {} }", SyntaxError);
+TestLocalDoesNotThrow("function f() { switch (true) { case true: function g() {} } }");
+TestLocalDoesNotThrow("function f() { switch (true) { default: function g() {} } }");
@@ -25,8 +25,6 @@
 // (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
-
 "use strict";
 
 // Test temporal dead zone semantics of let bound variables in
@@ -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 --harmony-classes
+// Flags: --harmony-classes
 
 function CheckError(source) {
   var exception = null;
similarity index 98%
rename from deps/v8/test/mjsunit/harmony/block-scoping.js
rename to deps/v8/test/mjsunit/es6/block-scoping.js
index 001d9fb..5f481b8 100644 (file)
@@ -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 --harmony-scoping
+// Flags: --allow-natives-syntax
 // Test functionality of block scopes.
 
 "use strict";
@@ -101,7 +101,8 @@ function f4(one) {
       assertEquals(4, eval('z'));
       assertEquals(5, eval('u'));
       assertEquals(6, eval('v'));
-    };
+    }
+    f();
   }
 }
 f4(1);
@@ -122,7 +123,8 @@ function f5(one) {
       assertEquals(4, z);
       assertEquals(5, u);
       assertEquals(6, v);
-    };
+    }
+    f();
   }
 }
 f5(1);
index 92cd087..888b686 100644 (file)
@@ -51,6 +51,21 @@ function TestValidMapCalls(m) {
   assertDoesNotThrow(function () { m.set(new Object) });
   assertDoesNotThrow(function () { m.has(new Object) });
   assertDoesNotThrow(function () { m.delete(new Object) });
+  assertDoesNotThrow(function () { m.get(undefined) });
+  assertDoesNotThrow(function () { m.get(null) });
+  assertDoesNotThrow(function () { m.get(0) });
+  assertDoesNotThrow(function () { m.get('a-key') });
+  assertDoesNotThrow(function () { m.get(Symbol()) });
+  assertDoesNotThrow(function () { m.has(undefined) });
+  assertDoesNotThrow(function () { m.has(null) });
+  assertDoesNotThrow(function () { m.has(0) });
+  assertDoesNotThrow(function () { m.has('a-key') });
+  assertDoesNotThrow(function () { m.has(Symbol()) });
+  assertDoesNotThrow(function () { m.delete(undefined) });
+  assertDoesNotThrow(function () { m.delete(null) });
+  assertDoesNotThrow(function () { m.delete(0) });
+  assertDoesNotThrow(function () { m.delete('a-key') });
+  assertDoesNotThrow(function () { m.delete(Symbol()) });
 }
 TestValidMapCalls(new Map);
 TestValidMapCalls(new WeakMap);
@@ -58,14 +73,11 @@ TestValidMapCalls(new WeakMap);
 
 // Test invalid getter and setter calls for WeakMap only
 function TestInvalidCalls(m) {
-  assertThrows(function () { m.get(undefined) }, TypeError);
   assertThrows(function () { m.set(undefined, 0) }, TypeError);
-  assertThrows(function () { m.get(null) }, TypeError);
   assertThrows(function () { m.set(null, 0) }, TypeError);
-  assertThrows(function () { m.get(0) }, TypeError);
   assertThrows(function () { m.set(0, 0) }, TypeError);
-  assertThrows(function () { m.get('a-key') }, TypeError);
   assertThrows(function () { m.set('a-key', 0) }, TypeError);
+  assertThrows(function () { m.set(Symbol(), 0) }, TypeError);
 }
 TestInvalidCalls(new WeakMap);
 
@@ -73,57 +85,79 @@ TestInvalidCalls(new WeakMap);
 // Test expected behavior for Sets and WeakSets
 function TestSet(set, key) {
   assertFalse(set.has(key));
-  assertSame(set, set.add(key));
-  assertTrue(set.has(key));
-  assertTrue(set.delete(key));
+  assertFalse(set.delete(key));
+  if (typeof key === 'object' && !(set instanceof WeakSet)) {
+    assertSame(set, set.add(key));
+    assertTrue(set.has(key));
+    assertTrue(set.delete(key));
+  }
   assertFalse(set.has(key));
   assertFalse(set.delete(key));
   assertFalse(set.has(key));
 }
 function TestSetBehavior(set) {
+  // Fill
   for (var i = 0; i < 20; i++) {
     TestSet(set, new Object);
     TestSet(set, i);
     TestSet(set, i / 100);
     TestSet(set, 'key-' + i);
+    TestSet(set, Symbol(i));
   }
-  var keys = [ +0, -0, +Infinity, -Infinity, true, false, null, undefined ];
+
+  var keys = [
+    -0, +0, 1, 1/3, 10, +Infinity, -Infinity, NaN, true, false, null, undefined,
+    'x', Symbol(), {}, function(){}
+  ];
   for (var i = 0; i < keys.length; i++) {
     TestSet(set, keys[i]);
   }
 }
 TestSetBehavior(new Set);
-TestSet(new WeakSet, new Object);
+TestSetBehavior(new WeakSet);
 
 
 // Test expected mapping behavior for Maps and WeakMaps
 function TestMapping(map, key, value) {
-  assertSame(map, map.set(key, value));
-  assertSame(value, map.get(key));
+  assertFalse(map.has(key));
+  assertSame(undefined, map.get(key));
+  assertFalse(map.delete(key));
+  if (typeof key === 'object' && !(map instanceof WeakMap)) {
+    assertSame(map, map.set(key, value));
+    assertSame(value, map.get(key));
+    assertTrue(map.has(key));
+    assertTrue(map.delete(key));
+  }
+  assertFalse(map.has(key));
+  assertSame(undefined, map.get(key));
+  assertFalse(map.delete(key));
+  assertFalse(map.has(key));
+  assertSame(undefined, map.get(key));
 }
-function TestMapBehavior1(m) {
+function TestMapBehavior(m) {
+  // Fill
   TestMapping(m, new Object, 23);
   TestMapping(m, new Object, 'the-value');
   TestMapping(m, new Object, new Object);
-}
-TestMapBehavior1(new Map);
-TestMapBehavior1(new WeakMap);
-
-
-// Test expected mapping behavior for Maps only
-function TestMapBehavior2(m) {
   for (var i = 0; i < 20; i++) {
     TestMapping(m, i, new Object);
     TestMapping(m, i / 10, new Object);
     TestMapping(m, 'key-' + i, new Object);
+    TestMapping(m, Symbol(i), new Object);
   }
-  // -0 is handled in TestMinusZeroMap
-  var keys = [ 0, +Infinity, -Infinity, true, false, null, undefined ];
+
+  var keys = [
+    -0, +0, 1, 1/3, 10, +Infinity, -Infinity, NaN, true, false, null, undefined,
+    'x', Symbol(), {}, function(){}
+  ];
   for (var i = 0; i < keys.length; i++) {
+    TestMapping(m, keys[i], 23);
+    TestMapping(m, keys[i], 'the-value');
     TestMapping(m, keys[i], new Object);
   }
 }
-TestMapBehavior2(new Map);
+TestMapBehavior(new Map);
+TestMapBehavior(new WeakMap);
 
 
 // Test expected querying behavior of Maps and WeakMaps
@@ -132,8 +166,6 @@ function TestQuery(m) {
   var values = [ 'x', 0, +Infinity, -Infinity, true, false, null, undefined ];
   for (var i = 0; i < values.length; i++) {
     TestMapping(m, key, values[i]);
-    assertTrue(m.has(key));
-    assertFalse(m.has(new Object));
   }
 }
 TestQuery(new Map);
@@ -144,7 +176,6 @@ TestQuery(new WeakMap);
 function TestDelete(m) {
   var key = new Object;
   TestMapping(m, key, 'to-be-deleted');
-  assertTrue(m.delete(key));
   assertFalse(m.delete(key));
   assertFalse(m.delete(new Object));
   assertSame(m.get(key), undefined);
@@ -1190,8 +1221,9 @@ function TestSetConstructorIterableValue(ctor) {
   // Strict mode is required to prevent implicit wrapping in the getter.
   Object.defineProperty(Number.prototype, Symbol.iterator, {
     get: function() {
-      assertEquals('object', typeof this);
+      assertEquals('number', typeof this);
       return function() {
+        assertEquals('number', typeof this);
         return oneAndTwo.keys();
       };
     },
@@ -1380,8 +1412,9 @@ function TestMapConstructorIterableValue(ctor) {
   // Strict mode is required to prevent implicit wrapping in the getter.
   Object.defineProperty(Number.prototype, Symbol.iterator, {
     get: function() {
-      assertEquals('object', typeof this);
+      assertEquals('number', typeof this);
       return function() {
+        assertEquals('number', typeof this);
         return oneAndTwo.entries();
       };
     },
@@ -1406,3 +1439,38 @@ TestCollectionToString(Map);
 TestCollectionToString(Set);
 TestCollectionToString(WeakMap);
 TestCollectionToString(WeakSet);
+
+
+function TestConstructorOrderOfAdderIterator(ctor, adderName) {
+  var iterable = new Map();
+  iterable.set({}, {});
+  iterable.set({}, {});
+  var iterableFunction = iterable[Symbol.iterator];
+  Object.defineProperty(iterable, Symbol.iterator, {
+    get: function() {
+      log += 'iterator';
+      return iterableFunction;
+    }
+  });
+
+  var log = '';
+  var adderFunction = ctor.prototype[adderName];
+
+  Object.defineProperty(ctor.prototype, adderName, {
+    get: function() {
+      log += adderName;
+      return adderFunction;
+    }
+  });
+
+  new ctor(iterable);
+  assertEquals(adderName + 'iterator', log);
+
+  Object.defineProperty(ctor.prototype, adderName, {
+    value: adderFunction
+  });
+}
+TestConstructorOrderOfAdderIterator(Map, 'set');
+TestConstructorOrderOfAdderIterator(Set, 'add');
+TestConstructorOrderOfAdderIterator(WeakMap, 'set');
+TestConstructorOrderOfAdderIterator(WeakSet, 'add');
@@ -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 --harmony-scoping
+// Flags: --expose-debug-as debug
 // The functions used for testing backtraces. They are at the top to make the
 // testing of source line/column easier.
 
@@ -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 --harmony-scoping
+// Flags: --expose-debug-as debug
 
 // Test debug evaluation for functions without local context, but with
 // nested catch contexts.
@@ -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 --harmony-scoping
+// Flags: --expose-debug-as debug
 
 "use strict";
 let top_level_let = 255;
diff --git a/deps/v8/test/mjsunit/es6/debug-promises/resolve-after-aborted-try-finally.js b/deps/v8/test/mjsunit/es6/debug-promises/resolve-after-aborted-try-finally.js
new file mode 100644 (file)
index 0000000..918ae2a
--- /dev/null
@@ -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: --expose-debug-as debug --allow-natives-syntax
+
+// Test debug events when we listen to all exceptions and
+// there is a catch handler for the exception thrown in a Promise.
+// We expect a normal Exception debug event to be triggered.
+
+Debug = debug.Debug;
+
+var events = [];
+
+function listener(event, exec_state, event_data, data) {
+  if (event == Debug.DebugEvent.PromiseEvent) events.push(event_data.status());
+}
+
+Debug.setListener(listener);
+
+var p = new Promise(function(resolve, reject) {
+  do {
+    try {
+      throw new Error("reject");
+    } finally {
+      break;  // No rethrow.
+    }
+  } while (false);
+  resolve();
+});
+
+assertEquals([0 /* create */, 1 /* resolve */], events);
diff --git a/deps/v8/test/mjsunit/es6/debug-promises/resolve-after-try-catch.js b/deps/v8/test/mjsunit/es6/debug-promises/resolve-after-try-catch.js
new file mode 100644 (file)
index 0000000..298201f
--- /dev/null
@@ -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: --expose-debug-as debug --allow-natives-syntax
+
+// Test debug events when we listen to all exceptions and
+// there is a catch handler for the exception thrown in a Promise.
+// We expect a normal Exception debug event to be triggered.
+
+Debug = debug.Debug;
+
+var events = [];
+
+function listener(event, exec_state, event_data, data) {
+  if (event == Debug.DebugEvent.PromiseEvent) events.push(event_data.status());
+}
+
+Debug.setListener(listener);
+
+var p = new Promise(function (resolve, reject) {
+  try {
+    throw new Error("reject");
+  } catch (e) {
+  }
+  resolve();
+});
+
+assertEquals([0 /* create */, 1 /* resolve */], events);
diff --git a/deps/v8/test/mjsunit/es6/debug-promises/rethrow-in-try-finally.js b/deps/v8/test/mjsunit/es6/debug-promises/rethrow-in-try-finally.js
new file mode 100644 (file)
index 0000000..b1e2ff9
--- /dev/null
@@ -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.
+
+// Flags: --expose-debug-as debug --allow-natives-syntax
+
+// Test debug events when we listen to all exceptions and
+// there is a catch handler for the exception thrown in a Promise.
+// We expect a normal Exception debug event to be triggered.
+
+Debug = debug.Debug;
+
+var events = [];
+
+function listener(event, exec_state, event_data, data) {
+  if (event == Debug.DebugEvent.PromiseEvent) events.push(event_data.status());
+}
+
+Debug.setListener(listener);
+
+var p = new Promise(function(resolve, reject) {
+  try {
+    throw new Error("reject");
+  } finally {
+    // Implicit rethrow.
+  }
+  resolve();
+});
+
+assertEquals([0 /* create */, -1 /* rethrown */], events);
diff --git a/deps/v8/test/mjsunit/es6/debug-stepin-promises.js b/deps/v8/test/mjsunit/es6/debug-stepin-promises.js
new file mode 100644 (file)
index 0000000..8548a2b
--- /dev/null
@@ -0,0 +1,65 @@
+// 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: --expose-debug-as debug --allow-natives-syntax --noalways-opt
+// Tests stepping into through Promises.
+
+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);
+
+Promise.resolve(42)
+  .then(
+    function f0() {
+      debugger;  // Break 0.
+    } // Break 1.
+  )
+  .then(callback)
+  .then(callback.bind(null))
+  .then(Object)
+  .then(callback.bind(null).bind(null))
+  .then(finalize)
+  .catch(function(err) {
+    %AbortJS("FAIL: " + err);
+  });
+
+function callback(x) {
+  return x; // Break 2. // Break 4. // Break 6.
+} // Break 3. // Break 5. // Break 7.
+
+function finalize() {
+  assertNull(exception); // Break 8.
+  assertEquals(expected_breaks, break_count);
+
+  Debug.setListener(null);
+}
similarity index 98%
rename from deps/v8/test/mjsunit/harmony/empty-for.js
rename to deps/v8/test/mjsunit/es6/empty-for.js
index 0221126..dad892d 100644 (file)
@@ -25,8 +25,6 @@
 // (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
-
 "use strict";
 
 function for_const() {
diff --git a/deps/v8/test/mjsunit/es6/function-length-configurable.js b/deps/v8/test/mjsunit/es6/function-length-configurable.js
new file mode 100644 (file)
index 0000000..e5b51ab
--- /dev/null
@@ -0,0 +1,119 @@
+// 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 getStrictF() {
+  'use strict';
+  return function f(x) {};
+}
+
+
+function getSloppyF() {
+  return function f(x) {};
+}
+
+
+function getStrictGenerator() {
+  'use strict';
+  return function* f(x) {};
+}
+
+
+function getSloppyGenerator() {
+  return function* f(x) {};
+}
+
+
+function test(testFunction) {
+  testFunction(getStrictF());
+  testFunction(getSloppyF());
+  testFunction(getStrictGenerator());
+  testFunction(getSloppyGenerator());
+}
+
+
+function testDescriptor(f) {
+  var descr = Object.getOwnPropertyDescriptor(f, 'length');
+  assertTrue(descr.configurable);
+  assertFalse(descr.enumerable);
+  assertEquals(1, descr.value);
+  assertFalse(descr.writable);
+}
+test(testDescriptor);
+
+
+function testSet(f) {
+  f.length = 2;
+  assertEquals(1, f.length);
+}
+test(testSet);
+
+
+function testSetStrict(f) {
+  'use strict';
+  assertThrows(function() {
+    f.length = 2;
+  }, TypeError);
+}
+test(testSetStrict);
+
+
+function testReconfigureAsDataProperty(f) {
+  Object.defineProperty(f, 'length', {
+    value: 2,
+  });
+  assertEquals(2, f.length);
+  Object.defineProperty(f, 'length', {
+    writable: true
+  });
+  f.length = 3;
+  assertEquals(3, f.length);
+
+  f.length = 42;
+  assertEquals(42, f.length);
+}
+test(testReconfigureAsDataProperty);
+
+
+function testReconfigureAsAccessorProperty(f) {
+  var length = 2;
+  Object.defineProperty(f, 'length', {
+    get: function() { return length; },
+    set: function(v) { length = v; }
+  });
+  assertEquals(2, f.length);
+  f.length = 3;
+  assertEquals(3, f.length);
+}
+test(testReconfigureAsAccessorProperty);
+
+
+(function testSetOnInstance() {
+  // This needs to come before testDelete below
+  assertTrue(Function.prototype.hasOwnProperty('length'));
+
+  function f() {}
+  delete f.length;
+  assertEquals(0, f.length);
+
+  f.length = 42;
+  assertEquals(0, f.length);  // non writable prototype property.
+  assertFalse(f.hasOwnProperty('length'));
+
+  Object.defineProperty(Function.prototype, 'length', {writable: true});
+
+  f.length = 123;
+  assertTrue(f.hasOwnProperty('length'));
+  assertEquals(123, f.length);
+})();
+
+
+(function testDelete() {
+  function f(x) {}
+  assertTrue(delete f.length);
+  assertFalse(f.hasOwnProperty('length'));
+  assertEquals(0, f.length);
+
+  assertTrue(delete Function.prototype.length);
+  assertEquals(undefined, f.length);
+})();
diff --git a/deps/v8/test/mjsunit/es6/function-name-configurable.js b/deps/v8/test/mjsunit/es6/function-name-configurable.js
new file mode 100644 (file)
index 0000000..f0ff406
--- /dev/null
@@ -0,0 +1,115 @@
+// 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 getStrictF() {
+  'use strict';
+  return function f() {};
+}
+
+
+function getSloppyF() {
+  return function f() {};
+}
+
+
+function test(testFunction) {
+  testFunction(getStrictF());
+  testFunction(getSloppyF());
+}
+
+
+function testDescriptor(f) {
+  var descr = Object.getOwnPropertyDescriptor(f, 'name');
+  assertTrue(descr.configurable);
+  assertFalse(descr.enumerable);
+  assertEquals('f', descr.value);
+  assertFalse(descr.writable);
+}
+test(testDescriptor);
+
+
+function testSet(f) {
+  f.name = 'g';
+  assertEquals('f', f.name);
+}
+test(testSet);
+
+
+function testSetStrict(f) {
+  'use strict';
+  assertThrows(function() {
+    f.name = 'g';
+  }, TypeError);
+}
+test(testSetStrict);
+
+
+function testReconfigureAsDataProperty(f) {
+  Object.defineProperty(f, 'name', {
+    value: 'g',
+  });
+  assertEquals('g', f.name);
+  Object.defineProperty(f, 'name', {
+    writable: true
+  });
+  f.name = 'h';
+  assertEquals('h', f.name);
+
+  f.name = 42;
+  assertEquals(42, f.name);
+}
+test(testReconfigureAsDataProperty);
+
+
+function testReconfigureAsAccessorProperty(f) {
+  var name = 'g';
+  Object.defineProperty(f, 'name', {
+    get: function() { return name; },
+    set: function(v) { name = v; }
+  });
+  assertEquals('g', f.name);
+  f.name = 'h';
+  assertEquals('h', f.name);
+}
+test(testReconfigureAsAccessorProperty);
+
+
+function testFunctionToString(f) {
+  Object.defineProperty(f, 'name', {
+    value: {toString: function() { assertUnreachable(); }},
+  });
+  assertEquals('function f() {}', f.toString());
+}
+test(testFunctionToString);
+
+
+(function testSetOnInstance() {
+  // This needs to come before testDelete below
+  assertTrue(Function.prototype.hasOwnProperty('name'));
+
+  function f() {}
+  delete f.name;
+  assertEquals('Empty', f.name);
+
+  f.name = 42;
+  assertEquals('Empty', f.name);  // non writable prototype property.
+  assertFalse(f.hasOwnProperty('name'));
+
+  Object.defineProperty(Function.prototype, 'name', {writable: true});
+
+  f.name = 123;
+  assertTrue(f.hasOwnProperty('name'));
+  assertEquals(123, f.name);
+})();
+
+
+(function testDelete() {
+  function f() {}
+  assertTrue(delete f.name);
+  assertFalse(f.hasOwnProperty('name'));
+  assertEquals('Empty', f.name);
+
+  assertTrue(delete Function.prototype.name);
+  assertEquals(undefined, f.name);
+})();
index 6f0c443..987a42c 100644 (file)
@@ -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: --expose-debug-as debug
+// Flags: --expose-debug-as debug --allow-natives-syntax
 
 var Debug = debug.Debug;
 var LiveEdit = Debug.LiveEdit;
@@ -54,7 +54,7 @@ function patch(fun, from, to) {
       print("Change log: " + JSON.stringify(log) + "\n");
     }
   }
-  Debug.ExecuteInDebugContext(debug, false);
+  %ExecuteInDebugContext(debug);
 }
 
 // Try to edit a MakeGenerator while it's running, then again while it's
index 8039ca8..5112443 100644 (file)
@@ -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 --harmony-tostring
+// Flags: --allow-natives-syntax --harmony-tostring
 
 // Test instantations of generators.
 
diff --git a/deps/v8/test/mjsunit/es6/indexed-integer-exotics.js b/deps/v8/test/mjsunit/es6/indexed-integer-exotics.js
new file mode 100644 (file)
index 0000000..7aefd78
--- /dev/null
@@ -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.
+
+// Flags: --allow-natives-syntax
+
+Object.prototype["10"] = "unreachable";
+Object.prototype["7"] = "unreachable";
+Object.prototype["-1"] = "unreachable";
+Object.prototype["-0"] = "unreachable";
+Object.prototype["4294967296"] = "unreachable";
+
+var array = new Int32Array(10);
+
+function check() {
+  for (var i = 0; i < 4; i++) {
+    assertEquals(undefined, array["-1"]);
+    assertEquals(undefined, array["-0"]);
+    assertEquals(undefined, array["10"]);
+    assertEquals(undefined, array["4294967296"]);
+  }
+  assertEquals("unreachable", array.__proto__["-1"]);
+  assertEquals("unreachable", array.__proto__["-0"]);
+  assertEquals("unreachable", array.__proto__["10"]);
+  assertEquals("unreachable", array.__proto__["4294967296"]);
+}
+
+check();
+
+array["-1"] = "unreachable";
+array["-0"] = "unreachable";
+array["10"] = "unreachable";
+array["4294967296"] = "unreachable";
+
+check();
+
+delete array["-0"];
+delete array["-1"];
+delete array["10"];
+delete array["4294967296"];
+
+assertEquals(undefined, Object.getOwnPropertyDescriptor(array, "-1"));
+assertEquals(undefined, Object.getOwnPropertyDescriptor(array, "-0"));
+assertEquals(undefined, Object.getOwnPropertyDescriptor(array, "10"));
+assertEquals(undefined, Object.getOwnPropertyDescriptor(array, "4294967296"));
+assertEquals(10, Object.keys(array).length);
+
+check();
+
+function f() { return array["-1"]; }
+
+for (var i = 0; i < 3; i++) {
+  assertEquals(undefined, f());
+}
+%OptimizeFunctionOnNextCall(f);
+assertEquals(undefined, f());
+
+Object.defineProperty(new Int32Array(), "-1", {'value': 1});
+Object.defineProperty(new Int32Array(), "-0", {'value': 1});
+Object.defineProperty(new Int32Array(), "-10", {'value': 1});
+Object.defineProperty(new Int32Array(), "4294967296", {'value': 1});
+
+check();
index 544c94d..f29e6e0 100644 (file)
@@ -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 --harmony-proxies
+// Flags: --harmony-proxies
 
 // Test for-of semantics.
 
@@ -200,9 +200,11 @@ assertEquals([undefined, 1, 2, 3],
                            // Done.
                            { value: 4, done: 42 }])));
 // Results that are not objects.
-assertEquals([undefined, undefined, undefined],
-             fold(append, [],
-                  results([10, "foo", /qux/, { value: 37, done: true }])));
+assertThrows(function() {
+  assertEquals([undefined, undefined, undefined],
+               fold(append, [],
+                    results([10, "foo", /qux/, { value: 37, done: true }])));
+}, TypeError);
 // Getters (shudder).
 assertEquals([1, 2],
              fold(append, [],
@@ -334,3 +336,25 @@ function poison_proxy_after(iterable, n) {
   }));
 }
 assertEquals(45, fold(sum, 0, poison_proxy_after(integers_until(10), 10)));
+
+
+function test_iterator_result_object_non_object(value, descr) {
+  var arr = [];
+  var ex;
+  var message = 'Iterator result ' + (descr || value) + ' is not an object';
+  try {
+    fold(append, arr,
+         results([{value: 1}, {}, value, {value: 2}, {done: true}]));
+  } catch (e) {
+    ex = e;
+  }
+  assertInstanceof(ex, TypeError);
+  assertEquals(message, ex.message);
+  assertArrayEquals([1, undefined], arr);
+}
+test_iterator_result_object_non_object(null);
+test_iterator_result_object_non_object(undefined);
+test_iterator_result_object_non_object(42);
+test_iterator_result_object_non_object('abc');
+test_iterator_result_object_non_object(false);
+test_iterator_result_object_non_object(Symbol('x'), 'Symbol(x)');
index 4be94c5..c6a7d47 100644 (file)
@@ -25,8 +25,6 @@
 // (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-of syntax.
 
 "use strict";
diff --git a/deps/v8/test/mjsunit/es6/map-minus-zero.js b/deps/v8/test/mjsunit/es6/map-minus-zero.js
new file mode 100644 (file)
index 0000000..f9f397e
--- /dev/null
@@ -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.
+
+'use strict';
+
+var map = new Map();
+
+var objectKey = {};
+var stringKey = 'keykeykey';
+var numberKey = 42.24;
+var booleanKey = true;
+var undefinedKey = undefined;
+var nullKey = null;
+var nanKey = NaN;
+var zeroKey = 0;
+var minusZeroKey = -0;
+
+assertEquals(map.size, 0);
+
+map.set(objectKey, 'aaa');
+map.set(stringKey, 'bbb');
+map.set(numberKey, 'ccc');
+map.set(booleanKey, 'ddd');
+map.set(undefinedKey, 'eee');
+map.set(nullKey, 'fff');
+map.set(nanKey, 'ggg');
+map.set(zeroKey, 'hhh');
+
+assertEquals(8, map.size);
+
+assertEquals('aaa', map.get(objectKey));
+assertEquals('bbb', map.get(stringKey));
+assertEquals('ccc', map.get(numberKey));
+assertEquals('ddd', map.get(booleanKey));
+assertEquals('eee', map.get(undefinedKey));
+assertEquals('fff', map.get(nullKey));
+assertEquals('ggg', map.get(nanKey));
+assertEquals('hhh', map.get(zeroKey));
+
+assertEquals(undefined, map.get({}));
+assertEquals('bbb', map.get('keykeykey'));
+assertEquals('ccc', map.get(42.24));
+assertEquals('ddd', map.get(true));
+assertEquals('eee', map.get(undefined));
+assertEquals('fff', map.get(null));
+assertEquals('ggg', map.get(NaN));
+assertEquals('hhh', map.get(0));
+assertEquals('hhh', map.get(-0));
+assertEquals('hhh', map.get(1 / Infinity));
+assertEquals('hhh', map.get(-1 / Infinity));
index 04059aa..63b6d2f 100644 (file)
@@ -32,6 +32,8 @@ var call = Function.prototype.call.call.bind(Function.prototype.call)
 var observe = Object.observe;
 var getOwnPropertyNames = Object.getOwnPropertyNames;
 var defineProperty = Object.defineProperty;
+var numberPrototype = Number.prototype;
+var symbolIterator = Symbol.iterator;
 
 
 (function() {
@@ -637,14 +639,6 @@ function assertAsyncDone(iteration) {
 })();
 
 (function() {
-  Promise.all({}).chain(
-    assertUnreachable,
-    function(r) { assertAsync(r instanceof TypeError, "all/no-array") }
-  )
-  assertAsyncRan()
-})();
-
-(function() {
   Promise.all([]).chain(
     function(x) { assertAsync(x.length === 0, "all/resolve/empty") },
     assertUnreachable
@@ -653,6 +647,45 @@ function assertAsyncDone(iteration) {
 })();
 
 (function() {
+  function testPromiseAllNonIterable(value) {
+    Promise.all(value).chain(
+        assertUnreachable,
+        function(r) {
+          assertAsync(r instanceof TypeError, 'all/non iterable');
+        });
+    assertAsyncRan();
+  }
+  testPromiseAllNonIterable(null);
+  testPromiseAllNonIterable(undefined);
+  testPromiseAllNonIterable({});
+  testPromiseAllNonIterable(42);
+})();
+
+(function() {
+  var deferred = Promise.defer();
+  var p = deferred.promise;
+  function* f() {
+    yield 1;
+    yield p;
+    yield 3;
+  }
+  Promise.all(f()).chain(
+      function(x) {
+        assertAsync(x.length === 3, "all/resolve/iterable");
+        assertAsync(x[0] === 1, "all/resolve/iterable/0");
+        assertAsync(x[1] === 2, "all/resolve/iterable/1");
+        assertAsync(x[2] === 3, "all/resolve/iterable/2");
+      },
+      assertUnreachable);
+  deferred.resolve(2);
+  assertAsyncRan();
+  assertAsyncRan();
+  assertAsyncRan();
+  assertAsyncRan();
+})();
+
+
+(function() {
   var deferred1 = Promise.defer()
   var p1 = deferred1.promise
   var deferred2 = Promise.defer()
@@ -706,6 +739,52 @@ function assertAsyncDone(iteration) {
   assertAsyncRan()
 })();
 
+
+(function() {
+  'use strict';
+  var getCalls = 0;
+  var funcCalls = 0;
+  var nextCalls = 0;
+  defineProperty(numberPrototype, symbolIterator, {
+    get: function() {
+      assertEquals('number', typeof this);
+      getCalls++;
+      return function() {
+        assertEquals('number', typeof this);
+        funcCalls++;
+        var n = this;
+        var i = 0
+        return {
+          next() {
+            nextCalls++;
+            return {value: i++, done: i > n};
+          }
+        };
+      };
+    },
+    configurable: true
+  });
+
+  Promise.all(3).chain(
+      function(x) {
+        assertAsync(x.length === 3, "all/iterable/number/length");
+        assertAsync(x[0] === 0, "all/iterable/number/0");
+        assertAsync(x[1] === 1, "all/iterable/number/1");
+        assertAsync(x[2] === 2, "all/iterable/number/2");
+      },
+      assertUnreachable);
+  delete numberPrototype[symbolIterator];
+
+  assertEquals(getCalls, 1);
+  assertEquals(funcCalls, 1);
+  assertEquals(nextCalls, 3 + 1);  // + 1 for {done: true}
+  assertAsyncRan();
+  assertAsyncRan();
+  assertAsyncRan();
+  assertAsyncRan();
+})();
+
+
 (function() {
   Promise.race([]).chain(
     assertUnreachable,
@@ -736,14 +815,6 @@ function assertAsyncDone(iteration) {
 })();
 
 (function() {
-  Promise.race({}).chain(
-    assertUnreachable,
-    function(r) { assertAsync(r instanceof TypeError, "one/no-array") }
-  )
-  assertAsyncRan()
-})();
-
-(function() {
   var deferred1 = Promise.defer()
   var p1 = deferred1.promise
   var deferred2 = Promise.defer()
@@ -804,6 +875,103 @@ function assertAsyncDone(iteration) {
   assertAsyncRan()
 })();
 
+
+(function() {
+  function testPromiseRaceNonIterable(value) {
+    Promise.race(value).chain(
+        assertUnreachable,
+        function(r) {
+          assertAsync(r instanceof TypeError, 'race/non iterable');
+        });
+    assertAsyncRan();
+  }
+  testPromiseRaceNonIterable(null);
+  testPromiseRaceNonIterable(undefined);
+  testPromiseRaceNonIterable({});
+  testPromiseRaceNonIterable(42);
+})();
+
+
+(function() {
+  var deferred1 = Promise.defer()
+  var p1 = deferred1.promise
+  var deferred2 = Promise.defer()
+  var p2 = deferred2.promise
+  var deferred3 = Promise.defer()
+  var p3 = deferred3.promise
+  function* f() {
+    yield p1;
+    yield p2;
+    yield p3;
+  }
+  Promise.race(f()).chain(
+    function(x) { assertAsync(x === 3, "race/iterable/resolve/reject") },
+    assertUnreachable
+  )
+  deferred3.resolve(3)
+  deferred1.reject(1)
+  assertAsyncRan()
+})();
+
+(function() {
+  var deferred1 = Promise.defer()
+  var p1 = deferred1.promise
+  var deferred2 = Promise.defer()
+  var p2 = deferred2.promise
+  var deferred3 = Promise.defer()
+  var p3 = deferred3.promise
+  function* f() {
+    yield p1;
+    yield p2;
+    yield p3;
+  }
+  Promise.race(f()).chain(
+    assertUnreachable,
+    function(x) { assertAsync(x === 3, "race/iterable/reject/resolve") }
+  )
+  deferred3.reject(3)
+  deferred1.resolve(1)
+  assertAsyncRan()
+})();
+
+(function() {
+  'use strict';
+  var getCalls = 0;
+  var funcCalls = 0;
+  var nextCalls = 0;
+  defineProperty(numberPrototype, symbolIterator, {
+    get: function() {
+      assertEquals('number', typeof this);
+      getCalls++;
+      return function() {
+        assertEquals('number', typeof this);
+        funcCalls++;
+        var n = this;
+        var i = 0
+        return {
+          next() {
+            nextCalls++;
+            return {value: i++, done: i > n};
+          }
+        };
+      };
+    },
+    configurable: true
+  });
+
+  Promise.race(3).chain(
+      function(x) {
+        assertAsync(x === 0, "race/iterable/number");
+      },
+      assertUnreachable);
+  delete numberPrototype[symbolIterator];
+
+  assertEquals(getCalls, 1);
+  assertEquals(funcCalls, 1);
+  assertEquals(nextCalls, 3 + 1);  // + 1 for {done: true}
+  assertAsyncRan();
+})();
+
 (function() {
   var log
   function MyPromise(resolver) {
@@ -25,7 +25,5 @@
 // (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
-
 assertThrows("'use strict'; (function f() { f = 123; })()", TypeError);
 assertThrows("(function f() { 'use strict'; f = 123; })()", TypeError);
@@ -25,8 +25,6 @@
 // (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
-
 "use strict";
 
 assertThrows("'use strict'; for (let x in x);", ReferenceError);
@@ -1,8 +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.
-//
-// Flags: --harmony-scoping
 
 'use strict';
 
@@ -1,8 +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.
-//
-// Flags: --harmony-scoping
 "use strict";
 
 function f() {
@@ -2,6 +2,4 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Flags: --harmony-scoping
-
 assertThrows("(function() { 'use strict'; { let f; var f; } })", SyntaxError);
@@ -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 --harmony
+// Flags: --allow-natives-syntax
 
 function foo() {
   return Math.clz32(12.34);
@@ -1,8 +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.
-//
-// Flags: --harmony-scoping
 
 "use strict";
 
@@ -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 --allow-natives-syntax
+// Flags: --allow-natives-syntax
 'use strict';
 function f24(deopt) {
   let x = 1;
diff --git a/deps/v8/test/mjsunit/es6/regress/regress-3938.js b/deps/v8/test/mjsunit/es6/regress/regress-3938.js
new file mode 100644 (file)
index 0000000..bd7d1be
--- /dev/null
@@ -0,0 +1,8 @@
+// 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.
+
+'use strict';
+
+assertThrows(function() { for (const i = 0; ; i++) {} }, TypeError);
+assertThrows("'use strict'; for (const i = 0; ; i++) {}", TypeError);
@@ -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 --harmony
+// Flags: --allow-natives-syntax
 
 try {
   %OptimizeFunctionOnNextCall(print);
diff --git a/deps/v8/test/mjsunit/es6/regress/regress-468661.js b/deps/v8/test/mjsunit/es6/regress/regress-468661.js
new file mode 100644 (file)
index 0000000..656190d
--- /dev/null
@@ -0,0 +1,75 @@
+// 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: --expose-debug-as debug
+
+Debug = debug.Debug
+var exception = null;
+var break_count = 0;
+
+var expected_values =
+  [ReferenceError, ReferenceError, 0, 0, 0, 0, 0, 1, ReferenceError, ReferenceError];
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      assertTrue(exec_state.frameCount() != 0, "FAIL: Empty stack trace");
+      // Count number of expected breakpoints in this source file.
+      if (!break_count) {
+        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 frameMirror = exec_state.frame(0);
+
+      var v = null;;
+      try {
+        v = frameMirror.evaluate('i').value();
+      } catch(e) {
+        v = e;
+      }
+      frameMirror.allScopes();
+      var source = frameMirror.sourceLineText();
+      print("paused at: " + source);
+      assertTrue(source.indexOf("// Break " + break_count + ".") > 0,
+                 "Unexpected pause at: " + source + "\n" +
+                 "Expected: // Break " + break_count + ".");
+      if (expected_values[break_count] === ReferenceError) {
+        assertTrue(v instanceof ReferenceError);
+      } else {
+        assertSame(expected_values[break_count], v);
+      }
+      ++break_count;
+
+      if (break_count !== expected_breaks) {
+        exec_state.prepareStep(Debug.StepAction.StepIn, 1);
+        print("Next step prepared");
+      }
+    }
+  } catch(e) {
+    exception = e;
+    print(e, e.stack);
+  }
+};
+
+Debug.setListener(listener);
+
+var sum = 0;
+(function (){
+  'use strict';
+
+  debugger; // Break 0.
+
+  for (let i=0; // Break 1.
+       i < 1;   // Break 2. // Break 3. // Break 6. // Break 7.
+       i++) {
+    let key = i; // Break 4.
+    sum += key;   // Break 5.
+  }
+}()); // Break 8.
+
+assertNull(exception); // Break 9.
+assertEquals(expected_breaks, break_count);
+
+Debug.setListener(null);
diff --git a/deps/v8/test/mjsunit/es6/regress/regress-474783.js b/deps/v8/test/mjsunit/es6/regress/regress-474783.js
new file mode 100644 (file)
index 0000000..e258dcb
--- /dev/null
@@ -0,0 +1,24 @@
+// 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.
+
+
+"use strict";
+class Base {
+}
+class Subclass extends Base {
+  constructor(a,b,c) {
+    arguments[1];
+  }
+}
+assertThrows(function() { Subclass(); }, TypeError);
+assertThrows(function() { Subclass(1); }, TypeError);
+assertThrows(function() { Subclass(1, 2); }, TypeError);
+assertThrows(function() { Subclass(1, 2, 3); }, TypeError);
+assertThrows(function() { Subclass(1, 2, 3, 4); }, TypeError);
+
+assertThrows(function() { Subclass.call(); }, TypeError);
+assertThrows(function() { Subclass.call({}); }, TypeError);
+assertThrows(function() { Subclass.call({}, 1); }, TypeError);
+assertThrows(function() { Subclass.call({}, 1, 2); }, TypeError);
+assertThrows(function() { Subclass.call({}, 1, 2, 3, 4); }, TypeError);
diff --git a/deps/v8/test/mjsunit/es6/set-minus-zero.js b/deps/v8/test/mjsunit/es6/set-minus-zero.js
new file mode 100644 (file)
index 0000000..792332c
--- /dev/null
@@ -0,0 +1,51 @@
+// 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.
+
+'use strict';
+
+var set = new Set();
+
+var objectKey = {};
+var stringKey = 'keykeykey';
+var numberKey = 42.24;
+var booleanKey = true;
+var undefinedKey = undefined;
+var nullKey = null;
+var nanKey = NaN;
+var zeroKey = 0;
+var minusZeroKey = -0;
+
+assertEquals(set.size, 0);
+
+set.add(objectKey);
+set.add(stringKey);
+set.add(numberKey);
+set.add(booleanKey);
+set.add(undefinedKey);
+set.add(nullKey);
+set.add(nanKey);
+set.add(zeroKey);
+
+assertEquals(8, set.size);
+
+assertTrue(set.has(objectKey));
+assertTrue(set.has(stringKey));
+assertTrue(set.has(numberKey));
+assertTrue(set.has(booleanKey));
+assertTrue(set.has(undefinedKey));
+assertTrue(set.has(nullKey));
+assertTrue(set.has(nanKey));
+assertTrue(set.has(zeroKey));
+
+assertFalse(set.has({}));
+assertTrue(set.has('keykeykey'));
+assertTrue(set.has(42.24));
+assertTrue(set.has(true));
+assertTrue(set.has(undefined));
+assertTrue(set.has(null));
+assertTrue(set.has(NaN));
+assertTrue(set.has(0));
+assertTrue(set.has(-0));
+assertTrue(set.has(1 / Infinity));
+assertTrue(set.has(-1 / Infinity));
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Flags: --harmony-strings
-
 // Tests taken from:
 // https://github.com/mathiasbynens/String.prototype.codePointAt
 
@@ -25,8 +25,6 @@
 // (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.endsWith.length);
 
 var testString = "Hello World";
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Flags: --harmony-strings
-
 // Tests taken from:
 // https://github.com/mathiasbynens/String.fromCodePoint
 
@@ -25,8 +25,6 @@
 // (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)?";
similarity index 88%
rename from deps/v8/test/mjsunit/harmony/string-raw.js
rename to deps/v8/test/mjsunit/es6/string-raw.js
index 28e2af9..2c6bb2f 100644 (file)
@@ -2,8 +2,6 @@
 // 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);
 })();
   assertEquals("12345", String.raw(callSiteObj, arg(2), arg(4), arg(6)));
   assertEquals(["length", "raw1", "arg2", "raw3", "arg4", "raw5"], order);
 })();
+
+
+(function testStringRawToStringSubstitutionsOrder() {
+  var subs = [];
+  var log = [];
+  function stringify(toString) {
+    var valueOf = "_" + toString + "_";
+    return {
+      toString: function() { return toString; },
+      valueOf: function() { return valueOf; }
+    };
+  }
+  function getter(name, value) {
+    return {
+      get: function() {
+        log.push("get" + name);
+        return value;
+      },
+      set: function(v) {
+        log.push("set" + name);
+      }
+    };
+  }
+  Object.defineProperties(subs, {
+    0: getter(0, stringify("a")),
+    1: getter(1, stringify("b")),
+    2: getter(2, stringify("c"))
+  });
+
+  assertEquals("-a-b-c-", String.raw`-${subs[0]}-${subs[1]}-${subs[2]}-`);
+  assertArrayEquals(["get0", "get1", "get2"], log);
+
+  log.length = 0;
+  assertEquals("-a-", String.raw`-${subs[0]}-`);
+  assertArrayEquals(["get0"], log);
+})();
similarity index 99%
rename from deps/v8/test/mjsunit/harmony/string-repeat.js
rename to deps/v8/test/mjsunit/es6/string-repeat.js
index 0af7448..15caea1 100644 (file)
@@ -25,8 +25,6 @@
 // (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("000", String.prototype.repeat.call(0, 3));
 assertEquals("-1-1-1", String.prototype.repeat.call(-1, 3));
 assertEquals("2.12.12.1", String.prototype.repeat.call(2.1, 3));
@@ -25,8 +25,6 @@
 // (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.startsWith.length);
 
 var testString = "Hello World";
index b9811f5..46c3dab 100644 (file)
@@ -245,25 +245,20 @@ TestCall()
 function TestCollections() {
   var set = new Set
   var map = new Map
-  var weakmap = new WeakMap
   for (var i in symbols) {
     set.add(symbols[i])
     map.set(symbols[i], i)
-    weakmap.set(symbols[i], i)
   }
   assertEquals(symbols.length, set.size)
   assertEquals(symbols.length, map.size)
   for (var i in symbols) {
     assertTrue(set.has(symbols[i]))
     assertTrue(map.has(symbols[i]))
-    assertTrue(weakmap.has(symbols[i]))
     assertEquals(i, map.get(symbols[i]))
-    assertEquals(i, weakmap.get(symbols[i]))
   }
   for (var i in symbols) {
     assertTrue(set.delete(symbols[i]))
     assertTrue(map.delete(symbols[i]))
-    assertTrue(weakmap.delete(symbols[i]))
   }
   assertEquals(0, set.size)
   assertEquals(0, map.size)
similarity index 80%
rename from deps/v8/test/mjsunit/harmony/templates.js
rename to deps/v8/test/mjsunit/es6/templates.js
index a884f58..15296e8 100644 (file)
@@ -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-templates --harmony-unicode
+// Flags: --harmony-unicode
 
 var num = 5;
 var str = "str";
@@ -423,10 +423,12 @@ var obj = {
   Object.defineProperty(Array.prototype, 0, {
     set: function() {
       assertUnreachable();
-    }
+    },
+    configurable: true
   });
   function tag(){}
   tag`a${1}b`;
+  delete Array.prototype[0];
 })();
 
 
@@ -518,3 +520,162 @@ var obj = {
   assertThrows("`${(function() { \"use strict\"; return \"\\07\"; })()}`",
                SyntaxError);
 })();
+
+
+var global = this;
+(function testCallNew() {
+  "use strict";
+  var called = false;
+  var calledWith;
+  global.log = function(x) { called = true; calledWith = x; }
+
+  assertInstanceof(new Function`log("test")`, Object);
+  assertTrue(called);
+  assertSame("test", calledWith);
+  delete global.log;
+})();
+
+
+(function testCallNew2() {
+  "use strict";
+  var log = [];
+  function tag(x) {
+    log.push(x);
+    if (!(this instanceof tag)) {
+      return tag;
+    }
+    this.x = x === void 0 ? null : x;
+    return this;
+  }
+  // No arguments passed to constructor
+  var instance = new tag`x``y``z`;
+  assertInstanceof(instance, tag);
+  assertSame(tag.prototype, Object.getPrototypeOf(instance));
+  assertEquals({ x: null }, instance);
+  assertEquals([["x"], ["y"], ["z"], undefined], log);
+
+  // Arguments passed to constructor
+  log.length = 0;
+  instance = new tag`x2` `y2` `z2` (`test`);
+  assertInstanceof(instance, tag);
+  assertSame(tag.prototype, Object.getPrototypeOf(instance));
+  assertEquals({ x: "test" }, instance);
+  assertEquals([["x2"], ["y2"], ["z2"], "test"], log);
+})();
+
+
+(function testCallResultOfTagFn() {
+  "use strict";
+  var i = 0;
+  var raw = [];
+  function tag(cs) {
+    var args = Array.prototype.slice.call(arguments);
+    var text = String.raw.apply(null, args);
+    if (i++ < 2) {
+      raw.push("tag;" + text);
+      return tag;
+    }
+
+    raw.push("raw;" + text);
+    return text;
+  }
+  assertEquals("test3", tag`test1``test2``test3`);
+  assertEquals([
+    "tag;test1",
+    "tag;test2",
+    "raw;test3"
+  ], raw);
+})();
+
+
+(function testToStringSubstitutions() {
+  var a = {
+    toString: function() { return "a"; },
+    valueOf: function() { return "-a-"; }
+  };
+  var b = {
+    toString: function() { return "b"; },
+    valueOf: function() { return "-b-"; }
+  };
+  assertEquals("a", `${a}`);
+  assertEquals("ab", `${a}${b}`);
+  assertEquals("-a--b-", `${a + b}`);
+  assertEquals("-a-", `${a + ""}`);
+  assertEquals("1a", `1${a}`);
+  assertEquals("1a2", `1${a}2`);
+  assertEquals("1a2b", `1${a}2${b}`);
+  assertEquals("1a2b3", `1${a}2${b}3`);
+})();
+
+
+(function testToStringSubstitutionsOrder() {
+  var subs = [];
+  var log = [];
+  function getter(name, value) {
+    return {
+      get: function() {
+        log.push("get" + name);
+        return value;
+      },
+      set: function(v) {
+        log.push("set" + name);
+      }
+    };
+  }
+  Object.defineProperties(subs, {
+    0: getter(0, "a"),
+    1: getter(1, "b"),
+    2: getter(2, "c")
+  });
+
+  assertEquals("-a-b-c-", `-${subs[0]}-${subs[1]}-${subs[2]}-`);
+  assertArrayEquals(["get0", "get1", "get2"], log);
+})();
+
+
+(function testTaggedToStringSubstitutionsOrder() {
+  var subs = [];
+  var log = [];
+  var tagged = [];
+  function getter(name, value) {
+    return {
+      get: function() {
+        log.push("get" + name);
+        return value;
+      },
+      set: function(v) {
+        log.push("set" + name);
+      }
+    };
+  }
+  Object.defineProperties(subs, {
+    0: getter(0, 1),
+    1: getter(1, 2),
+    2: getter(2, 3)
+  });
+
+  function tag(cs) {
+    var n_substitutions = arguments.length - 1;
+    var n_cooked = cs.length;
+    var e = cs[0];
+    var i = 0;
+    assertEquals(n_cooked, n_substitutions + 1);
+    while (i < n_substitutions) {
+      var sub = arguments[i++ + 1];
+      var tail = cs[i];
+      tagged.push(sub);
+      e = e.concat(sub, tail);
+    }
+    return e;
+  }
+
+  assertEquals("-1-2-3-", tag`-${subs[0]}-${subs[1]}-${subs[2]}-`);
+  assertArrayEquals(["get0", "get1", "get2"], log);
+  assertArrayEquals([1, 2, 3], tagged);
+
+  tagged.length = 0;
+  log.length = 0;
+  assertEquals("-1-", tag`-${subs[0]}-`);
+  assertArrayEquals(["get0"], log);
+  assertArrayEquals([1], tagged);
+})();
index 5af205e..b2853c4 100644 (file)
@@ -1142,7 +1142,9 @@ var properties = ["a", "1", 1, "length", "setPrototype", "name", "caller"];
 function blacklisted(obj, prop) {
   return (obj instanceof Int32Array && prop == 1) ||
          (obj instanceof Int32Array && prop === "length") ||
-         (obj instanceof ArrayBuffer && prop == 1)
+         (obj instanceof ArrayBuffer && prop == 1) ||
+         (obj instanceof Function && prop === "name") ||  // Has its own test.
+         (obj instanceof Function && prop === "length");  // Has its own test.
 }
 
 for (var i in objects) for (var j in properties) {
@@ -1798,3 +1800,66 @@ for (var b1 = 0; b1 < 2; ++b1)
     for (var n = 0; n < 3; ++n)
       for (var i in mutationByIncr)
         TestFastElementsLength(mutationByIncr[i], b1 != 0, b2 != 0, 7*n, 7*n+1);
+
+
+(function TestFunctionName() {
+  reset();
+
+  function fun() {}
+  Object.observe(fun, observer.callback);
+  fun.name = 'x';  // No change. Not writable.
+  Object.defineProperty(fun, 'name', {value: 'a'});
+  Object.defineProperty(fun, 'name', {writable: true});
+  fun.name = 'b';
+  delete fun.name;
+  fun.name = 'x';  // No change. Function.prototype.name is non writable
+  Object.defineProperty(Function.prototype, 'name', {writable: true});
+  fun.name = 'c';
+  fun.name = 'c';  // Same, no update.
+  Object.deliverChangeRecords(observer.callback);
+  observer.assertCallbackRecords([
+    { object: fun, type: 'update', name: 'name', oldValue: 'fun' },
+    { object: fun, type: 'reconfigure', name: 'name'},
+    { object: fun, type: 'update', name: 'name', oldValue: 'a' },
+    { object: fun, type: 'delete', name: 'name', oldValue: 'b' },
+    { object: fun, type: 'add', name: 'name' },
+  ]);
+})();
+
+
+(function TestFunctionLength() {
+  reset();
+
+  function fun(x) {}
+  Object.observe(fun, observer.callback);
+  fun.length = 'x';  // No change. Not writable.
+  Object.defineProperty(fun, 'length', {value: 'a'});
+  Object.defineProperty(fun, 'length', {writable: true});
+  fun.length = 'b';
+  delete fun.length;
+  fun.length = 'x';  // No change. Function.prototype.length is non writable
+  Object.defineProperty(Function.prototype, 'length', {writable: true});
+  fun.length = 'c';
+  fun.length = 'c';  // Same, no update.
+  Object.deliverChangeRecords(observer.callback);
+  observer.assertCallbackRecords([
+    { object: fun, type: 'update', name: 'length', oldValue: 1 },
+    { object: fun, type: 'reconfigure', name: 'length'},
+    { object: fun, type: 'update', name: 'length', oldValue: 'a' },
+    { object: fun, type: 'delete', name: 'length', oldValue: 'b' },
+    { object: fun, type: 'add', name: 'length' },
+  ]);
+})();
+
+
+(function TestObserveInvalidAcceptMessage() {
+  var ex;
+  try {
+    Object.observe({}, function(){}, "not an object");
+  } catch (e) {
+    ex = e;
+  }
+  assertInstanceof(ex, TypeError);
+  assertEquals("Third argument to Object.observe must be an array of strings.",
+               ex.message);
+})()
index 97c9f65..386ac99 100644 (file)
@@ -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 --lazy
+// Flags: --lazy
 
 function foo(a, b, c, d) {
   "use strict"
index 7eac6df..76ab53c 100644 (file)
@@ -34,6 +34,9 @@ function TestNonObjectPrototype(value) {
   var f = new F();
   assertEquals(value, F.prototype);
   assertEquals(Object.prototype, f.__proto__);
+  // Test that map transitions don't break anything.
+  F.property = "value";
+  assertEquals(value, F.prototype);
 }
 
 var values = [123, "asdf", true];
diff --git a/deps/v8/test/mjsunit/harmony/block-const-assign.js b/deps/v8/test/mjsunit/harmony/block-const-assign.js
deleted file mode 100644 (file)
index c21a0a3..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-// 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:
-//
-//     * 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 that we throw early syntax errors in harmony mode
-// when using an immutable binding in an assigment or with
-// prefix/postfix decrement/increment operators.
-
-"use strict";
-
-// Function local const.
-function constDecl0(use) {
-  return "(function() { const constvar = 1; " + use + "; })();";
-}
-
-
-function constDecl1(use) {
-  return "(function() { " + use + "; const constvar = 1; })();";
-}
-
-
-// Function local const, assign from eval.
-function constDecl2(use) {
-  use = "eval('(function() { " + use + " })')()";
-  return "(function() { const constvar = 1; " + use + "; })();";
-}
-
-
-function constDecl3(use) {
-  use = "eval('(function() { " + use + " })')()";
-  return "(function() { " + use + "; const constvar = 1; })();";
-}
-
-
-// Block local const.
-function constDecl4(use) {
-  return "(function() { { const constvar = 1; " + use + "; } })();";
-}
-
-
-function constDecl5(use) {
-  return "(function() { { " + use + "; const constvar = 1; } })();";
-}
-
-
-// Block local const, assign from eval.
-function constDecl6(use) {
-  use = "eval('(function() {" + use + "})')()";
-  return "(function() { { const constvar = 1; " + use + "; } })();";
-}
-
-
-function constDecl7(use) {
-  use = "eval('(function() {" + use + "})')()";
-  return "(function() { { " + use + "; const constvar = 1; } })();";
-}
-
-
-// Function expression name.
-function constDecl8(use) {
-  return "(function constvar() { " + use + "; })();";
-}
-
-
-// Function expression name, assign from eval.
-function constDecl9(use) {
-  use = "eval('(function(){" + use + "})')()";
-  return "(function constvar() { " + use + "; })();";
-}
-
-let decls = [ constDecl0,
-              constDecl1,
-              constDecl2,
-              constDecl3,
-              constDecl4,
-              constDecl5,
-              constDecl6,
-              constDecl7,
-              constDecl8,
-              constDecl9
-              ];
-let declsForTDZ = new Set([constDecl1, constDecl3, constDecl5, constDecl7]);
-let uses = [ 'constvar = 1;',
-             'constvar += 1;',
-             '++constvar;',
-             'constvar++;'
-             ];
-
-function Test(d,u) {
-  'use strict';
-  try {
-    print(d(u));
-    eval(d(u));
-  } catch (e) {
-    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;
-  }
-  assertUnreachable();
-}
-
-for (var d = 0; d < decls.length; ++d) {
-  for (var u = 0; u < uses.length; ++u) {
-    Test(decls[d], uses[u]);
-  }
-}
index 4e50f8a..ab5d39e 100644 (file)
@@ -312,41 +312,74 @@ function assertIteratorResult(value, done, result) {
 
 
 (function TestPrototype() {
-  // Normally a static prototype property is not allowed.
-  class C {
-    static ['prototype']() {
-      return 1;
+  assertThrows(function() {
+    class C {
+      static ['prototype']() {
+        return 1;
+      }
     }
-  }
-  assertEquals(1, C.prototype());
+  }, TypeError);
 
-  class C2 {
-    static get ['prototype']() {
-      return 2;
+  assertThrows(function() {
+    class C2 {
+      static get ['prototype']() {
+        return 2;
+      }
     }
-  }
-  assertEquals(2, C2.prototype);
+  }, TypeError);
 
-  var calls = 0;
-  class C3 {
-    static set ['prototype'](x) {
-      assertEquals(3, x);
-      calls++;
+  assertThrows(function() {
+    class C3 {
+      static set ['prototype'](x) {
+        assertEquals(3, x);
+      }
     }
-  }
-  C3.prototype = 3;
-  assertEquals(1, calls);
+  }, TypeError);
+
+  assertThrows(function() {
+    class C4 {
+      static *['prototype']() {
+        yield 1;
+        yield 2;
+      }
+    }
+  }, TypeError);
+})();
 
-  class C4 {
-    static *['prototype']() {
-      yield 1;
-      yield 2;
+
+(function TestPrototypeConcat() {
+  assertThrows(function() {
+    class C {
+      static ['pro' + 'tot' + 'ype']() {
+        return 1;
+      }
     }
-  }
-  var iter = C4.prototype();
-  assertIteratorResult(1, false, iter.next());
-  assertIteratorResult(2, false, iter.next());
-  assertIteratorResult(undefined, true, iter.next());
+  }, TypeError);
+
+  assertThrows(function() {
+    class C2 {
+      static get ['pro' + 'tot' + 'ype']() {
+        return 2;
+      }
+    }
+  }, TypeError);
+
+  assertThrows(function() {
+    class C3 {
+      static set ['pro' + 'tot' + 'ype'](x) {
+        assertEquals(3, x);
+      }
+    }
+  }, TypeError);
+
+  assertThrows(function() {
+    class C4 {
+      static *['pro' + 'tot' + 'ype']() {
+        yield 1;
+        yield 2;
+      }
+    }
+  }, TypeError);
 })();
 
 
@@ -388,3 +421,45 @@ function assertIteratorResult(value, done, result) {
   assertIteratorResult(2, false, iter.next());
   assertIteratorResult(undefined, true, iter.next());
 })();
+
+
+(function TestExceptionInName() {
+  function MyError() {};
+  function throwMyError() {
+    throw new MyError();
+  }
+  assertThrows(function() {
+    class C {
+      [throwMyError()]() {}
+    }
+  }, MyError);
+  assertThrows(function() {
+    class C {
+      get [throwMyError()]() { return 42; }
+    }
+  }, MyError);
+  assertThrows(function() {
+    class C {
+      set [throwMyError()](_) { }
+    }
+  }, MyError);
+})();
+
+
+(function TestTdzName() {
+  assertThrows(function() {
+    class C {
+      [C]() {}
+    }
+  }, ReferenceError);
+  assertThrows(function() {
+    class C {
+      get [C]() { return 42; }
+    }
+  }, ReferenceError);
+  assertThrows(function() {
+    class C {
+      set [C](_) { }
+    }
+  }, ReferenceError);
+})();
index 6936077..36e1411 100644 (file)
@@ -277,3 +277,26 @@ function ID(x) {
   assertEquals('X', object.x);
   assertEquals(proto, Object.getPrototypeOf(object));
 })();
+
+
+(function TestExceptionInName() {
+  function MyError() {};
+  function throwMyError() {
+    throw new MyError();
+  }
+  assertThrows(function() {
+    var o = {
+      [throwMyError()]: 42
+    };
+  }, MyError);
+  assertThrows(function() {
+    var o = {
+      get [throwMyError()]() { return 42; }
+    };
+  }, MyError);
+  assertThrows(function() {
+    var o = {
+      set [throwMyError()](_) { }
+    };
+  }, MyError);
+})();
index 3a5bc89..faaf7f2 100644 (file)
@@ -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-modules --harmony-scoping
+// Flags: --harmony-modules
 
 // Test basic module linking and initialization.
 
index 1a95347..7f1e431 100644 (file)
@@ -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-modules --harmony-scoping
+// Flags: --harmony-modules
 
 // Test basic module interface inference.
 
index 218094c..c08daf1 100644 (file)
@@ -196,25 +196,20 @@ TestSet()
 function TestCollections() {
   var set = new Set
   var map = new Map
-  var weakmap = new WeakMap
   for (var i in symbols) {
     set.add(symbols[i])
     map.set(symbols[i], i)
-    weakmap.set(symbols[i], i)
   }
   assertEquals(symbols.length, set.size)
   assertEquals(symbols.length, map.size)
   for (var i in symbols) {
     assertTrue(set.has(symbols[i]))
     assertTrue(map.has(symbols[i]))
-    assertTrue(weakmap.has(symbols[i]))
     assertEquals(i, map.get(symbols[i]))
-    assertEquals(i, weakmap.get(symbols[i]))
   }
   for (var i in symbols) {
     assertTrue(set.delete(symbols[i]))
     assertTrue(map.delete(symbols[i]))
-    assertTrue(weakmap.delete(symbols[i]))
   }
   assertEquals(0, set.size)
   assertEquals(0, map.size)
diff --git a/deps/v8/test/mjsunit/harmony/reflect-apply.js b/deps/v8/test/mjsunit/harmony/reflect-apply.js
new file mode 100644 (file)
index 0000000..2cfb982
--- /dev/null
@@ -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.
+
+// Flags: --harmony-reflect
+
+
+(function testReflectApplyArity() {
+  assertEquals(3, Reflect.apply.length);
+})();
+
+
+(function testReflectApplyNonConstructor() {
+  assertThrows(function() {
+    new Reflect.apply(function(){}, null, []);
+  }, TypeError);
+})();
+
+
+(function testAppliedReceiverSloppy() {
+  function returnThis() { return this; }
+  var receiver = {};
+
+  assertSame(this, Reflect.apply(returnThis, void 0, []));
+  assertSame(this, Reflect.apply(returnThis, null, []));
+  assertSame(this, Reflect.apply(returnThis, this, []));
+  assertSame(receiver, Reflect.apply(returnThis, receiver, []));
+
+  // Wrap JS values
+  assertSame(String.prototype,
+             Object.getPrototypeOf(Reflect.apply(returnThis, "str", [])));
+  assertSame(Number.prototype,
+             Object.getPrototypeOf(Reflect.apply(returnThis, 123, [])));
+  assertSame(Boolean.prototype,
+             Object.getPrototypeOf(Reflect.apply(returnThis, true, [])));
+  assertSame(Symbol.prototype,
+             Object.getPrototypeOf(
+                Reflect.apply(returnThis, Symbol("test"), [])));
+})();
+
+
+(function testAppliedReceiverStrict() {
+  function returnThis() { 'use strict'; return this; }
+  var receiver = {};
+
+  assertSame(void 0, Reflect.apply(returnThis, void 0, []));
+  assertSame(this, Reflect.apply(returnThis, this, []));
+  assertSame(receiver, Reflect.apply(returnThis, receiver, []));
+
+  // Don't wrap value types
+  var regexp = /123/;
+  var symbol = Symbol("test");
+  assertSame("str", Reflect.apply(returnThis, "str", []));
+  assertSame(123, Reflect.apply(returnThis, 123, []));
+  assertSame(true, Reflect.apply(returnThis, true, []));
+  assertSame(regexp, Reflect.apply(returnThis, regexp, []));
+  assertSame(symbol, Reflect.apply(returnThis, symbol, []));
+})();
+
+
+(function testAppliedArgumentsLength() {
+  function returnLengthStrict() { 'use strict'; return arguments.length; }
+  function returnLengthSloppy() { return arguments.length; }
+
+  assertEquals(0, Reflect.apply(returnLengthStrict, this, []));
+  assertEquals(0, Reflect.apply(returnLengthSloppy, this, []));
+  assertEquals(0, Reflect.apply(returnLengthStrict, this, {}));
+  assertEquals(0, Reflect.apply(returnLengthSloppy, this, {}));
+
+  for (var i = 0; i < 256; ++i) {
+    assertEquals(i, Reflect.apply(returnLengthStrict, this, new Array(i)));
+    assertEquals(i, Reflect.apply(returnLengthSloppy, this, new Array(i)));
+    assertEquals(i, Reflect.apply(returnLengthStrict, this, { length: i }));
+    assertEquals(i, Reflect.apply(returnLengthSloppy, this, { length: i }));
+  }
+})();
+
+
+(function testAppliedArgumentsLengthThrows() {
+  function noopStrict() { 'use strict'; }
+  function noopSloppy() { }
+  function MyError() {}
+
+  var argsList = {};
+  Object.defineProperty(argsList, "length", {
+    get: function() { throw new MyError(); }
+  });
+
+  assertThrows(function() {
+    Reflect.apply(noopStrict, this, argsList);
+  }, MyError);
+
+  assertThrows(function() {
+    Reflect.apply(noopSloppy, this, argsList);
+  }, MyError);
+})();
+
+
+(function testAppliedArgumentsElementThrows() {
+  function noopStrict() { 'use strict'; }
+  function noopSloppy() { }
+  function MyError() {}
+
+  var argsList = { length: 1 };
+  Object.defineProperty(argsList, "0", {
+    get: function() { throw new MyError(); }
+  });
+
+  assertThrows(function() {
+    Reflect.apply(noopStrict, this, argsList);
+  }, MyError);
+
+  assertThrows(function() {
+    Reflect.apply(noopSloppy, this, argsList);
+  }, MyError);
+})();
+
+
+(function testAppliedNonFunctionStrict() {
+  'use strict';
+  assertThrows(function() { Reflect.apply(void 0); }, TypeError);
+  assertThrows(function() { Reflect.apply(null); }, TypeError);
+  assertThrows(function() { Reflect.apply(123); }, TypeError);
+  assertThrows(function() { Reflect.apply("str"); }, TypeError);
+  assertThrows(function() { Reflect.apply(Symbol("x")); }, TypeError);
+  assertThrows(function() { Reflect.apply(/123/); }, TypeError);
+  assertThrows(function() { Reflect.apply(NaN); }, TypeError);
+  assertThrows(function() { Reflect.apply({}); }, TypeError);
+  assertThrows(function() { Reflect.apply([]); }, TypeError);
+})();
+
+
+(function testAppliedNonFunctionSloppy() {
+  assertThrows(function() { Reflect.apply(void 0); }, TypeError);
+  assertThrows(function() { Reflect.apply(null); }, TypeError);
+  assertThrows(function() { Reflect.apply(123); }, TypeError);
+  assertThrows(function() { Reflect.apply("str"); }, TypeError);
+  assertThrows(function() { Reflect.apply(Symbol("x")); }, TypeError);
+  assertThrows(function() { Reflect.apply(/123/); }, TypeError);
+  assertThrows(function() { Reflect.apply(NaN); }, TypeError);
+  assertThrows(function() { Reflect.apply({}); }, TypeError);
+  assertThrows(function() { Reflect.apply([]); }, TypeError);
+})();
+
+
+(function testAppliedArgumentsNonList() {
+  function noopStrict() { 'use strict'; }
+  function noopSloppy() {}
+  var R = void 0;
+  assertThrows(function() { Reflect.apply(noopStrict, R, null); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopSloppy, R, null); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopStrict, R, 1); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopSloppy, R, 1); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopStrict, R, "BAD"); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopSloppy, R, "BAD"); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopStrict, R, true); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopSloppy, R, true); }, TypeError);
+  var sym = Symbol("x");
+  assertThrows(function() { Reflect.apply(noopStrict, R, sym); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopSloppy, R, sym); }, TypeError);
+})();
+
+
+(function testAppliedArgumentValue() {
+  function returnFirstStrict(a) { 'use strict'; return a; }
+  function returnFirstSloppy(a) { return a; }
+  function returnLastStrict(a) {
+    'use strict'; return arguments[arguments.length - 1]; }
+  function returnLastSloppy(a) { return arguments[arguments.length - 1]; }
+  function returnSumStrict() {
+    'use strict';
+    var sum = arguments[0];
+    for (var i = 1; i < arguments.length; ++i) {
+      sum += arguments[i];
+    }
+    return sum;
+  }
+  function returnSumSloppy() {
+    var sum = arguments[0];
+    for (var i = 1; i < arguments.length; ++i) {
+      sum += arguments[i];
+    }
+    return sum;
+  }
+
+  assertEquals("OK!", Reflect.apply(returnFirstStrict, this, ["OK!"]));
+  assertEquals("OK!", Reflect.apply(returnFirstSloppy, this, ["OK!"]));
+  assertEquals("OK!", Reflect.apply(returnFirstStrict, this,
+                                    { 0: "OK!", length: 1 }));
+  assertEquals("OK!", Reflect.apply(returnFirstSloppy, this,
+                                    { 0: "OK!", length: 1 }));
+  assertEquals("OK!", Reflect.apply(returnLastStrict, this,
+                                    [0, 1, 2, 3, 4, 5, 6, 7, 8, "OK!"]));
+  assertEquals("OK!", Reflect.apply(returnLastSloppy, this,
+                                    [0, 1, 2, 3, 4, 5, 6, 7, 8, "OK!"]));
+  assertEquals("OK!", Reflect.apply(returnLastStrict, this,
+                                    { 9: "OK!", length: 10 }));
+  assertEquals("OK!", Reflect.apply(returnLastSloppy, this,
+                                    { 9: "OK!", length: 10 }));
+  assertEquals("TEST", Reflect.apply(returnSumStrict, this,
+                                     ["T", "E", "S", "T"]));
+  assertEquals("TEST!!", Reflect.apply(returnSumStrict, this,
+                                       ["T", "E", "S", "T", "!", "!"]));
+  assertEquals(10, Reflect.apply(returnSumStrict, this,
+                                 { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 }));
+  assertEquals("TEST", Reflect.apply(returnSumSloppy, this,
+                                     ["T", "E", "S", "T"]));
+  assertEquals("TEST!!", Reflect.apply(returnSumSloppy, this,
+                                       ["T", "E", "S", "T", "!", "!"]));
+  assertEquals(10, Reflect.apply(returnSumSloppy, this,
+                                 { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 }));
+})();
diff --git a/deps/v8/test/mjsunit/harmony/reflect-construct.js b/deps/v8/test/mjsunit/harmony/reflect-construct.js
new file mode 100644 (file)
index 0000000..2211e3f
--- /dev/null
@@ -0,0 +1,277 @@
+// Copyright 2014 the V8 project 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-reflect
+
+
+(function testReflectConstructArity() {
+  assertEquals(2, Reflect.construct.length);
+})();
+
+
+(function testReflectConstructNonConstructor() {
+  assertThrows(function() {
+    new Reflect.construct(function(){}, []);
+  }, TypeError);
+})();
+
+
+(function testReflectConstructBasic() {
+  function Constructor() { "use strict"; }
+  assertInstanceof(Reflect.construct(Constructor, []), Constructor);
+})();
+
+
+(function testReflectConstructBasicSloppy() {
+  function Constructor() {}
+  assertInstanceof(Reflect.construct(Constructor, []), Constructor);
+})();
+
+
+(function testReflectConstructReturnSomethingElseStrict() {
+  var R = {};
+  function Constructor() { "use strict"; return R; }
+  assertSame(R, Reflect.construct(Constructor, []));
+})();
+
+
+(function testReflectConstructReturnSomethingElseSloppy() {
+  var R = {};
+  function Constructor() { return R; }
+  assertSame(R, Reflect.construct(Constructor, []));
+})();
+
+
+(function testReflectConstructNewTargetStrict() {
+  "use strict";
+  function Constructor() { this[9] = 1; }
+  var O = Reflect.construct(Constructor, [], Array);
+  assertEquals(1, O[9]);
+  // Ordinary object with Array.prototype --- no exotic Array magic
+  assertFalse(Array.isArray(O));
+  assertEquals(0, O.length);
+  assertSame(Array.prototype, Object.getPrototypeOf(O));
+})();
+
+
+(function testReflectConstructNewTargetSloppy() {
+  function Constructor() { this[9] = 1; }
+  var O = Reflect.construct(Constructor, [], Array);
+  assertEquals(1, O[9]);
+  // Ordinary object with Array.prototype --- no exotic Array magic
+  assertFalse(Array.isArray(O));
+  assertEquals(0, O.length);
+  assertSame(Array.prototype, Object.getPrototypeOf(O));
+})();
+
+
+(function testReflectConstructNewTargetStrict2() {
+  "use strict";
+  function Constructor() { this[9] = 1; }
+  Constructor.prototype.add = function(x) {
+    this[this.length] = x; return this;
+  }
+  var O = Reflect.construct(Array, [1, 2, 3], Constructor);
+  // Exotic Array object with Constructor.prototype
+  assertTrue(Array.isArray(O));
+  assertSame(Constructor.prototype, Object.getPrototypeOf(O));
+  assertFalse(O instanceof Array);
+  assertEquals(3, O.length);
+  assertEquals(undefined, O[9]);
+  assertSame(O, O.add(4));
+  assertEquals(4, O.length);
+  assertEquals(4, O[3]);
+})();
+
+
+(function testReflectConstructNewTargetSloppy2() {
+  function Constructor() { this[9] = 1; }
+  Constructor.prototype.add = function(x) {
+    this[this.length] = x; return this;
+  }
+  var O = Reflect.construct(Array, [1, 2, 3], Constructor);
+  // Exotic Array object with Constructor.prototype
+  assertTrue(Array.isArray(O));
+  assertSame(Constructor.prototype, Object.getPrototypeOf(O));
+  assertFalse(O instanceof Array);
+  assertEquals(3, O.length);
+  assertEquals(undefined, O[9]);
+  assertSame(O, O.add(4));
+  assertEquals(4, O.length);
+  assertEquals(4, O[3]);
+})();
+
+
+(function testReflectConstructNewTargetStrict3() {
+  "use strict";
+  function A() {}
+  function B() {}
+  var O = Reflect.construct(A, [], B);
+  // TODO(caitp): bug: newTarget prototype is not used if it is not
+  // explicitly set.
+  //assertSame(B.prototype, Object.getPrototypeOf(O));
+})();
+
+
+(function testReflectConstructNewTargetSloppy3() {
+  function A() {}
+  function B() {}
+  var O = Reflect.construct(A, [], B);
+  // TODO(caitp): bug: newTarget prototype is not used if it is not
+  // explicitly set.
+  //assertSame(B.prototype, Object.getPrototypeOf(O));
+})();
+
+
+(function testAppliedArgumentsLength() {
+  function lengthStrict() { 'use strict'; this.a = arguments.length; }
+  function lengthSloppy() { this.a = arguments.length; }
+
+  assertEquals(0, Reflect.construct(lengthStrict, []).a);
+  assertEquals(0, Reflect.construct(lengthSloppy, []).a);
+  assertEquals(0, Reflect.construct(lengthStrict, {}).a);
+  assertEquals(0, Reflect.construct(lengthSloppy, {}).a);
+
+  for (var i = 0; i < 256; ++i) {
+    assertEquals(i, Reflect.construct(lengthStrict, new Array(i)).a);
+    assertEquals(i, Reflect.construct(lengthSloppy, new Array(i)).a);
+    assertEquals(i, Reflect.construct(lengthStrict, { length: i }).a);
+    assertEquals(i, Reflect.construct(lengthSloppy, { length: i }).a);
+  }
+})();
+
+
+(function testAppliedArgumentsLengthThrows() {
+  function noopStrict() { 'use strict'; }
+  function noopSloppy() { }
+  function MyError() {}
+
+  var argsList = {};
+  Object.defineProperty(argsList, "length", {
+    get: function() { throw new MyError(); }
+  });
+
+  assertThrows(function() {
+    Reflect.construct(noopStrict, argsList);
+  }, MyError);
+
+  assertThrows(function() {
+    Reflect.construct(noopSloppy, argsList);
+  }, MyError);
+})();
+
+
+(function testAppliedArgumentsElementThrows() {
+  function noopStrict() { 'use strict'; }
+  function noopSloppy() { }
+  function MyError() {}
+
+  var argsList = { length: 1 };
+  Object.defineProperty(argsList, "0", {
+    get: function() { throw new MyError(); }
+  });
+
+  assertThrows(function() {
+    Reflect.construct(noopStrict, argsList);
+  }, MyError);
+
+  assertThrows(function() {
+    Reflect.construct(noopSloppy, argsList);
+  }, MyError);
+})();
+
+
+(function testAppliedNonFunctionStrict() {
+  'use strict';
+  assertThrows(function() { Reflect.construct(void 0, []); }, TypeError);
+  assertThrows(function() { Reflect.construct(null, []); }, TypeError);
+  assertThrows(function() { Reflect.construct(123, []); }, TypeError);
+  assertThrows(function() { Reflect.construct("str", []); }, TypeError);
+  assertThrows(function() { Reflect.construct(Symbol("x"), []); }, TypeError);
+  assertThrows(function() { Reflect.construct(/123/, []); }, TypeError);
+  assertThrows(function() { Reflect.construct(NaN, []); }, TypeError);
+  assertThrows(function() { Reflect.construct({}, []); }, TypeError);
+  assertThrows(function() { Reflect.construct([], []); }, TypeError);
+})();
+
+
+(function testAppliedNonFunctionSloppy() {
+  assertThrows(function() { Reflect.construct(void 0, []); }, TypeError);
+  assertThrows(function() { Reflect.construct(null, []); }, TypeError);
+  assertThrows(function() { Reflect.construct(123, []); }, TypeError);
+  assertThrows(function() { Reflect.construct("str", []); }, TypeError);
+  assertThrows(function() { Reflect.construct(Symbol("x"), []); }, TypeError);
+  assertThrows(function() { Reflect.construct(/123/, []); }, TypeError);
+  assertThrows(function() { Reflect.construct(NaN, []); }, TypeError);
+  assertThrows(function() { Reflect.construct({}, []); }, TypeError);
+  assertThrows(function() { Reflect.construct([], []); }, TypeError);
+})();
+
+
+(function testAppliedArgumentsNonList() {
+  function noopStrict() { 'use strict'; }
+  function noopSloppy() {}
+  assertThrows(function() { Reflect.construct(noopStrict, null); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopSloppy, null); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopStrict, 1); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopSloppy, 1); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopStrict, "BAD"); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopSloppy, "BAD"); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopStrict, true); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopSloppy, true); }, TypeError);
+  var sym = Symbol("x");
+  assertThrows(function() { Reflect.construct(noopStrict, sym); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopSloppy, sym); }, TypeError);
+})();
+
+
+(function testAppliedArgumentValue() {
+  function firstStrict(a) { 'use strict'; this.a = a; }
+  function firstSloppy(a) { this.a = a; }
+  function lastStrict(a) {
+    'use strict'; this.a = arguments[arguments.length - 1]; }
+  function lastSloppy(a) { this.a = arguments[arguments.length - 1]; }
+  function sumStrict() {
+    'use strict';
+    var sum = arguments[0];
+    for (var i = 1; i < arguments.length; ++i) {
+      sum += arguments[i];
+    }
+    this.a = sum;
+  }
+  function sumSloppy() {
+    var sum = arguments[0];
+    for (var i = 1; i < arguments.length; ++i) {
+      sum += arguments[i];
+    }
+    this.a = sum;
+  }
+
+  assertEquals("OK!", Reflect.construct(firstStrict, ["OK!"]).a);
+  assertEquals("OK!", Reflect.construct(firstSloppy, ["OK!"]).a);
+  assertEquals("OK!", Reflect.construct(firstStrict,
+                                        { 0: "OK!", length: 1 }).a);
+  assertEquals("OK!", Reflect.construct(firstSloppy,
+                                        { 0: "OK!", length: 1 }).a);
+  assertEquals("OK!", Reflect.construct(lastStrict,
+                                        [0, 1, 2, 3, 4, 5, 6, 7, 8, "OK!"]).a);
+  assertEquals("OK!", Reflect.construct(lastSloppy,
+                                        [0, 1, 2, 3, 4, 5, 6, 7, 8, "OK!"]).a);
+  assertEquals("OK!", Reflect.construct(lastStrict,
+                                        { 9: "OK!", length: 10 }).a);
+  assertEquals("OK!", Reflect.construct(lastSloppy,
+                                        { 9: "OK!", length: 10 }).a);
+  assertEquals("TEST", Reflect.construct(sumStrict,
+                                         ["T", "E", "S", "T"]).a);
+  assertEquals("TEST!!", Reflect.construct(sumStrict,
+                                           ["T", "E", "S", "T", "!", "!"]).a);
+  assertEquals(10, Reflect.construct(sumStrict,
+                                     { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 }).a);
+  assertEquals("TEST", Reflect.construct(sumSloppy,
+                                         ["T", "E", "S", "T"]).a);
+  assertEquals("TEST!!", Reflect.construct(sumSloppy,
+                                           ["T", "E", "S", "T", "!", "!"]).a);
+  assertEquals(10, Reflect.construct(sumSloppy,
+                                     { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 }).a);
+})();
diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-crbug-461520.js b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-461520.js
new file mode 100644 (file)
index 0000000..c30260d
--- /dev/null
@@ -0,0 +1,18 @@
+// 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: --harmony-proxies
+
+var fuse = 1;
+var handler = {
+  get: function() { return function() {} },
+  getPropertyDescriptor: function() {
+    if (fuse-- == 0) throw "please die";
+    return {value: function() {}, configurable: true};
+  }
+};
+
+var p = Proxy.create(handler);
+var o = Object.create(p);
+with (o) { f() }
diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-crbug-465671-null.js b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-465671-null.js
new file mode 100644 (file)
index 0000000..d24599c
--- /dev/null
@@ -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: --harmony-arrow-functions
+
+// This used to trigger a segfault because of NULL being accessed.
+function f() {
+  var a = [10];
+  try {
+    f();
+  } catch(e) {
+    a.map((v) => v + 1);
+  }
+}
+f();
diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-crbug-465671.js b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-465671.js
new file mode 100644 (file)
index 0000000..24f4d05
--- /dev/null
@@ -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: --harmony-arrow-functions
+
+// This used to trigger crash because of an unhandled stack overflow.
+function f() {
+  var a = [10];
+  try {
+    f();
+  } catch(e) {
+    a.map(v => v + 1);
+  }
+}
+f();
index 5bb258e..341cb33 100644 (file)
@@ -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-rest-parameters
+// Flags: --harmony-rest-parameters --harmony-classes
 
 (function testRestIndex() {
   assertEquals(5, (function(...args) { return args.length; })(1,2,3,4,5));
@@ -180,3 +180,35 @@ var O = {
   assertEquals([], ((...args) => args)());
   assertEquals([1,2,3], ((...args) => args)(1,2,3));
 })();*/
+
+
+(function testRestParamsWithNewTarget() {
+  "use strict";
+  class Base {
+    constructor(...a) {
+      this.base = a;
+      assertEquals(arguments.length, a.length);
+      var args = [];
+      for (var i = 0; i < arguments.length; ++i) {
+        args.push(arguments[i]);
+      }
+      assertEquals(args, a);
+    }
+  }
+  class Child extends Base {
+    constructor(...b) {
+      super(1, 2, 3);
+      this.child = b;
+      assertEquals(arguments.length, b.length);
+      var args = [];
+      for (var i = 0; i < arguments.length; ++i) {
+        args.push(arguments[i]);
+      }
+      assertEquals(args, b);
+    }
+  }
+
+  var c = new Child(1, 2, 3);
+  assertEquals([1, 2, 3], c.child);
+  assertEquals([1, 2, 3], c.base);
+})();
index a4d6e79..0cdb7ed 100644 (file)
@@ -530,7 +530,7 @@ function TestTypedArraysWithIllegalIndices() {
    * assertEquals(undefined, a[-Infinity]);
    */
   a[1.5] = 10;
-  assertEquals(undefined, a[1.5]);
+  assertEquals(10, a[1.5]);
   var nan = Math.sqrt(-1);
   a[nan] = 5;
   assertEquals(5, a[nan]);
@@ -579,7 +579,7 @@ function TestTypedArraysWithIllegalIndicesStrict() {
    * assertEquals(undefined, a[-Infinity]);
    */
   a[1.5] = 10;
-  assertEquals(undefined, a[1.5]);
+  assertEquals(10, a[1.5]);
   var nan = Math.sqrt(-1);
   a[nan] = 5;
   assertEquals(5, a[nan]);
index f048f05..f68c76c 100644 (file)
@@ -183,3 +183,8 @@ try {
   externalizeString(str, true);
 } catch (e) { }
 TestStringify("\"external\"", str, null, 0);
+
+var o = {};
+o.somespecialproperty = 10;
+o["\x19"] = 10;
+assertThrows("JSON.parse('{\"somespecialproperty\":100, \"\x19\":10}')");
index dc96a1d..4b3ae5d 100644 (file)
@@ -68,6 +68,7 @@
   'compare-known-objects-slow': [PASS, NO_VARIANTS],
   'elements-kind': [PASS, NO_VARIANTS],
   'opt-elements-kind': [PASS, NO_VARIANTS],
+  'smi-representation': [PASS, NO_VARIANTS],
 
   # Some tests are just too slow to run for now.
   'big-object-literal': [PASS, NO_VARIANTS],
   'debug-evaluate-locals': [PASS, NO_VARIANTS],
   'debug-liveedit-check-stack': [PASS, NO_VARIANTS],  # only in no-snap mode.
   'debug-liveedit-double-call': [PASS, NO_VARIANTS],
-  'debug-step-stub-callfunction': [PASS, NO_VARIANTS],
   'debug-set-variable-value': [PASS, NO_VARIANTS],
-  'debug-stepin-accessor': [PASS, NO_VARIANTS],
-  'debug-stepin-builtin': [PASS, NO_VARIANTS],
-  'debug-stepin-constructor': [PASS, NO_VARIANTS],
-  'debug-stepin-function-call': [PASS, NO_VARIANTS],
-  'debug-stepnext-do-while': [PASS, NO_VARIANTS],
   'debug-stepout-scope-part1': [PASS, NO_VARIANTS],
   'debug-stepout-scope-part2': [PASS, NO_VARIANTS],
   'debug-stepout-scope-part3': [PASS, NO_VARIANTS],
-  'es6/debug-stepin-microtasks': [PASS, NO_VARIANTS],
-  'es6/debug-stepnext-for': [PASS, NO_VARIANTS],
-  'harmony/debug-evaluate-blockscopes': [PASS, NO_VARIANTS],
-
-  # TODO(jarin): Some tests don't like --turbo-deoptimzation very much.
-  'asm/embenchen/lua_binarytrees': [SKIP],
-  'es6/symbols': [PASS, NO_VARIANTS],
-  'regress/regress-354433': [PASS, NO_VARIANTS],  # only on ARM simulator.
-  'regress/regress-crbug-259300': [PASS, NO_VARIANTS],
+  'es6/debug-evaluate-blockscopes': [PASS, NO_VARIANTS],
 
   ##############################################################################
   # Too slow in debug mode with --stress-opt mode.
   'regress/regress-create-exception': [PASS, ['mode == debug', SKIP]],
 
   ##############################################################################
+  # Too slow in debug mode for validation of elements.
+  'regress/regress-430201': [PASS, ['mode == debug', SKIP]],
+  'regress/regress-430201b': [PASS, ['mode == debug', SKIP]],
+
+  ##############################################################################
   # Too slow in debug mode for GC stress mode.
   'regress/regress-crbug-217858': [PASS, ['mode == debug', SKIP]],
 
 
   # Very slow on ARM and MIPS, contains no architecture dependent code.
   'unicode-case-overoptimization': [PASS, NO_VARIANTS, ['arch == arm or arch == android_arm or arch == android_arm64 or arch == mipsel or arch == mips64el or arch == mips', TIMEOUT]],
+  'regress/regress-3976': [PASS, NO_VARIANTS, ['arch == arm or arch == android_arm or arch == android_arm64 or arch == mipsel or arch == mips64el or arch == mips', SKIP]],
 
   ##############################################################################
   # This test expects to reach a certain recursion depth, which may not work
   # nosse2. Also for arm novfp3.
   'regress/regress-2989': [FAIL, NO_VARIANTS, ['system == linux and arch == x87 or arch == arm and simulator == True', PASS]],
 
+  # BUG(v8:3985). Wrong materialization of arguments object after throwing
+  # an exception.
+  'regress/regress-3985': [PASS, FAIL],
+
   # Skip endain dependent test for mips due to different typed views of the same
   # array buffer.
   'nans': [PASS, ],
 
   # Too slow for slow variants.
   'asm/embenchen/*': [PASS, SLOW, FAST_VARIANTS],
+
+  # BUG(v8:3838).
+  'regress/regress-3116': [PASS, ['isolates', FLAKY]],
 }],  # ALWAYS
 
 ##############################################################################
   'fast-prototype': [SKIP],
   'field-type-tracking': [SKIP],
   'getters-on-elements': [SKIP],
-  'harmony/block-let-crankshaft': [SKIP],
+  'es6/block-let-crankshaft': [SKIP],
   'opt-elements-kind': [SKIP],
   'osr-elements-kind': [SKIP],
   'regress/regress-crbug-137689': [SKIP],
 
   # Issue 3723.
   'regress/regress-3717': [SKIP],
-  # Issue 3776.
-  'debug-stepframe': [SKIP],
+  # Issue 3924.
+  'mjsunit/debug-clearbreakpointgroup': [SKIP],
+  # Issue 3969.
+  'mjsunit/debug-references': [SKIP],
 }],  # 'gc_stress == True'
 
 ##############################################################################
   'readonly': [SKIP],
   'array-feedback': [SKIP],
 
+  # Deopting uses just enough memory to make this one OOM.
+  'regress/regress-3976': [SKIP],
+
   # Deopt every n garbage collections collides with deopt every n times.
   'regress/regress-2653': [SKIP],
 }],  # 'deopt_fuzzer == True'
+
+##############################################################################
+['arch == ppc and simulator_run == True or arch == ppc64 and simulator_run == True', {
+
+  # take too long with the simulator.
+  'regress/regress-1132': [SKIP],
+}],  # 'arch == ppc and simulator_run == True'
 ]
diff --git a/deps/v8/test/mjsunit/regexp-stack-overflow.js b/deps/v8/test/mjsunit/regexp-stack-overflow.js
new file mode 100644 (file)
index 0000000..63f6971
--- /dev/null
@@ -0,0 +1,18 @@
+// 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: --stack-size=100
+
+var re = /\w/;
+re.test("a");  // Trigger regexp compile.
+
+function rec() {
+  try {
+    return rec();
+  } catch (e) {
+    return re.test("b");
+  }
+}
+
+assertTrue(rec());
index 20d1f26..fa86f62 100644 (file)
@@ -80,8 +80,10 @@ assertFalse(Object.getOwnPropertyDescriptor(f, 'prototype').writable);
 assertThrows("'use strict'; f.prototype = {}");
 assertThrows("Object.defineProperty(f, 'prototype', { value: {} })");
 
-// Verify that non-writability of other properties is respected.
-assertThrows("Object.defineProperty(f, 'name', { value: {} })");
-assertThrows("Object.defineProperty(f, 'length', { value: {} })");
+// Verify that non-configurability of other properties is respected, but
+// non-writability is ignored by Object.defineProperty().
+// name and length are configurable in ES6
+Object.defineProperty(f, 'name', { value: {} });
+Object.defineProperty(f, 'length', { value: {} });
 assertThrows("Object.defineProperty(f, 'caller', { value: {} })");
 assertThrows("Object.defineProperty(f, 'arguments', { value: {} })");
index 6e0865c..63f4d14 100644 (file)
@@ -39,7 +39,7 @@ function g(x) {
 
 function checkNameDescriptor(f) {
   var descriptor = Object.getOwnPropertyDescriptor(f, "name");
-  assertFalse(descriptor.configurable);
+  assertTrue(descriptor.configurable);
   assertFalse(descriptor.enumerable);
   assertFalse(descriptor.writable);
 }
index d94b804..eb0d3f3 100644 (file)
@@ -58,4 +58,4 @@ f(10, o3);
 
 // The old code is already deoptimized, but f still points to it.
 // Disassembling it will crash.
-%DebugDisassembleFunction(f);
+%DisassembleFunction(f);
diff --git a/deps/v8/test/mjsunit/regress/regress-3960.js b/deps/v8/test/mjsunit/regress/regress-3960.js
new file mode 100644 (file)
index 0000000..4aaab0b
--- /dev/null
@@ -0,0 +1,36 @@
+// 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
+
+// Test that setting break point is works correctly when the debugger is
+// activated late, which leads to duplicate shared function infos.
+
+(function() {
+  var Debug = %GetDebugContext().Debug;
+
+  function listener(event, exec_state, event_data, data) {
+    if (event != Debug.DebugEvent.Break) return;
+    try {
+      assertTrue(/foo/.test(exec_state.frame(0).sourceLineText()));
+      break_count++;
+    } catch (e) {
+      exception = e;
+    }
+  }
+
+  for (var i = 0; i < 3; i++) {
+    var foo = function() { a = 1; }
+    var exception = null;
+    var break_count = 0;
+    Debug.setListener(listener);
+    if (i < 2) Debug.setBreakPoint(foo, 0, 0);
+    assertTrue(/\[B\d\]a = 1/.test(Debug.showBreakPoints(foo)));
+    foo();
+    assertEquals(1, break_count);
+    assertNull(exception);
+  }
+
+  Debug.setListener(null);
+})();
diff --git a/deps/v8/test/mjsunit/regress/regress-3969.js b/deps/v8/test/mjsunit/regress/regress-3969.js
new file mode 100644 (file)
index 0000000..4659e1c
--- /dev/null
@@ -0,0 +1,36 @@
+// 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 Inner() {
+  this.property = "OK";
+  this.o2 = 1;
+}
+
+function Outer(inner) {
+  this.inner = inner;
+}
+
+var inner = new Inner();
+var outer = new Outer(inner);
+
+Outer.prototype.boom = function() {
+  return this.inner.property;
+}
+
+assertEquals("OK", outer.boom());
+assertEquals("OK", outer.boom());
+%OptimizeFunctionOnNextCall(Outer.prototype.boom);
+assertEquals("OK", outer.boom());
+
+inner = undefined;
+%SetAllocationTimeout(0 /*interval*/, 2 /*timeout*/);
+// Call something that will do GC while holding a handle to outer's map.
+// The key is that this lets inner's map die while keeping outer's map alive.
+delete outer.inner;
+
+outer = new Outer({field: 1.51, property: "OK"});
+
+assertEquals("OK", outer.boom());
diff --git a/deps/v8/test/mjsunit/regress/regress-3976.js b/deps/v8/test/mjsunit/regress/regress-3976.js
new file mode 100644 (file)
index 0000000..c151f68
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2015 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: --max-old-space-size=60
+
+table = [];
+
+for (var i = 0; i < 32; i++) {
+ table[i] = String.fromCharCode(i + 0x410);
+}
+
+
+var random = (function() {
+  var seed = 10;
+  return function() {
+    seed = (seed * 1009) % 8831;
+    return seed;
+  };
+})();
+
+
+function key(length) {
+  var s = "";
+  for (var i = 0; i < length; i++) {
+    s += table[random() % 32];
+  }
+  return '"' + s + '"';
+}
+
+
+function value() {
+  return '[{' + '"field1" : ' + random() + ', "field2" : ' + random() + '}]';
+}
+
+
+function generate(n) {
+  var s = '{';
+  for (var i = 0; i < n; i++) {
+     if (i > 0) s += ', ';
+     s += key(random() % 10 + 7);
+     s += ':';
+     s += value();
+  }
+  s += '}';
+  return s;
+}
+
+
+print("generating");
+
+var str = generate(50000);
+
+print("parsing "  + str.length);
+JSON.parse(str);
+
+print("done");
diff --git a/deps/v8/test/mjsunit/regress/regress-3985.js b/deps/v8/test/mjsunit/regress/regress-3985.js
new file mode 100644 (file)
index 0000000..6dbc4bd
--- /dev/null
@@ -0,0 +1,45 @@
+// 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
+
+var shouldThrow = false;
+
+function h() {
+  try {  // Prevent inlining in Crankshaft.
+  } catch(e) { }
+  var res = g.arguments[0].x;
+  if (shouldThrow) {
+    throw res;
+  }
+  return res;
+}
+
+function g(o) { h(); }
+
+function f1() {
+  var o = { x : 1 };
+  g(o);
+  return o.x;
+}
+
+function f2() {
+  var o = { x : 2 };
+  g(o);
+  return o.x;
+}
+
+f1();
+f2();
+f1();
+f2();
+%OptimizeFunctionOnNextCall(f1);
+%OptimizeFunctionOnNextCall(f2);
+shouldThrow = true;
+try { f1(); } catch(e) {
+  assertEquals(e, 1);
+}
+try { f2(); } catch(e) {
+  assertEquals(e, 2);
+}
diff --git a/deps/v8/test/mjsunit/regress/regress-4023.js b/deps/v8/test/mjsunit/regress/regress-4023.js
new file mode 100644 (file)
index 0000000..902741f
--- /dev/null
@@ -0,0 +1,67 @@
+// 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 --expose-gc --block-concurrent-recompilation
+
+function Inner() {
+  this.property = "OK";
+  this.prop2 = 1;
+}
+
+function Outer() {
+  this.o = "u";
+}
+function KeepMapAlive(o) {
+  return o.o;
+}
+function SetInner(o, i) {
+  o.inner_field = i;
+}
+function Crash(o) {
+  return o.inner_field.property;
+}
+
+var inner = new Inner();
+var outer = new Outer();
+
+// Collect type feedback.
+SetInner(new Outer(), inner);
+SetInner(outer, inner);
+
+// This function's only purpose is to stash away a Handle that keeps
+// outer's map alive during the gc() call below. We store this handle
+// on the compiler thread :-)
+KeepMapAlive(outer);
+KeepMapAlive(outer);
+%OptimizeFunctionOnNextCall(KeepMapAlive, "concurrent");
+KeepMapAlive(outer);
+
+// So far, all is well. Collect type feedback and optimize.
+print(Crash(outer));
+print(Crash(outer));
+%OptimizeFunctionOnNextCall(Crash);
+print(Crash(outer));
+
+// Null out references and perform GC. This will keep outer's map alive
+// (due to the handle created above), but will let inner's map die. Hence,
+// inner_field's field type stored in outer's map will get cleared.
+inner = undefined;
+outer = undefined;
+gc();
+
+// We could unblock the compiler thread now. But why bother?
+
+// Now optimize SetInner while inner_field's type is still cleared!
+// This will generate optimized code that stores arbitrary objects
+// into inner_field without checking their type against the field type.
+%OptimizeFunctionOnNextCall(SetInner);
+
+// Use the optimized code to store an arbitrary object into
+// o2's inner_field, without triggering any dependent code deopts...
+var o2 = new Outer();
+SetInner(o2, { invalid: 1.51, property: "OK" });
+// ...and then use the existing code expecting an Inner-class object to
+// read invalid data (in this case, a raw double).
+// We crash trying to convert the raw double into a printable string.
+print(Crash(o2));
diff --git a/deps/v8/test/mjsunit/regress/regress-4027.js b/deps/v8/test/mjsunit/regress/regress-4027.js
new file mode 100644 (file)
index 0000000..3a5d11b
--- /dev/null
@@ -0,0 +1,60 @@
+// 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 --expose-gc
+
+function Inner() {
+  this.inner_name = "inner";
+}
+
+function Boom() {
+  this.boom = "boom";
+}
+
+function Outer() {
+  this.outer_name = "outer";
+}
+
+function SetInner(inner, value) {
+  inner.prop = value;
+}
+
+function SetOuter(outer, value) {
+  outer.inner = value;
+}
+
+var inner1 = new Inner();
+var inner2 = new Inner();
+
+SetInner(inner1, 10);
+SetInner(inner2, 10);
+
+var outer1 = new Outer();
+var outer2 = new Outer();
+var outer3 = new Outer();
+
+SetOuter(outer1, inner1);
+SetOuter(outer1, inner1);
+SetOuter(outer1, inner1);
+
+SetOuter(outer2, inner2);
+SetOuter(outer2, inner2);
+SetOuter(outer2, inner2);
+
+SetOuter(outer3, inner2);
+SetOuter(outer3, inner2);
+SetOuter(outer3, inner2);
+
+
+SetInner(inner2, 6.5);
+
+outer1 = null;
+inner1 = null;
+
+gc();
+
+var boom = new Boom();
+SetOuter(outer2, boom);
+
+gc();
similarity index 80%
rename from deps/v8/test/preparser/strict-const.js
rename to deps/v8/test/mjsunit/regress/regress-430201b.js
index 97b9081..056504d 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// 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:
 // 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;
+// Flags: --allow-natives-syntax --expose-gc
+
+(function() {
+  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/deps/v8/test/mjsunit/regress/regress-460937.js b/deps/v8/test/mjsunit/regress/regress-460937.js
new file mode 100644 (file)
index 0000000..cd57f93
--- /dev/null
@@ -0,0 +1,19 @@
+// 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() {
+  var a = new Array(100000);
+  var i = 0;
+  while (!%HasFastDoubleElements(a)) {
+    a[i] = i;
+    i += 0.1;
+  }
+  a[1] = 1.5;
+}
+
+f();
+%OptimizeFunctionOnNextCall(f);
+f();
diff --git a/deps/v8/test/mjsunit/regress/regress-463028.js b/deps/v8/test/mjsunit/regress/regress-463028.js
new file mode 100644 (file)
index 0000000..1454ef1
--- /dev/null
@@ -0,0 +1,18 @@
+// 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
+
+var o = {}
+Object.defineProperty(o, "z", {
+    set: function() {
+      %DeoptimizeFunction(f);
+    },
+});
+
+function f(o) {
+  return 19 + (void(o.z = 12));
+}
+
+f(o);
diff --git a/deps/v8/test/mjsunit/regress/regress-469605.js b/deps/v8/test/mjsunit/regress/regress-469605.js
new file mode 100644 (file)
index 0000000..6572511
--- /dev/null
@@ -0,0 +1,43 @@
+// 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 counter() {
+  var i = 100;
+  return function() {
+    if (i-- > 0) return i;
+    throw "done";
+  }
+}
+
+var c1 = counter();
+var c2 = counter();
+
+var f = (function() {
+  "use asm";
+  return function f(i) {
+    i = i|0;
+    do {
+      if (i > 0) c1();
+      else c2();
+    } while (true);
+  }
+})();
+
+assertThrows(function() { f(0); });
+assertThrows(function() { f(1); });
+
+var c3 = counter();
+
+var g = (function() {
+  "use asm";
+  return function g(i) {
+    i = i + 1;
+    do {
+      i = c3(i);
+    } while (true);
+  }
+})();
+
+assertThrows(function() { g(0); });
+assertThrows(function() { g(1); });
diff --git a/deps/v8/test/mjsunit/regress/regress-470804.js b/deps/v8/test/mjsunit/regress/regress-470804.js
new file mode 100644 (file)
index 0000000..cebb91f
--- /dev/null
@@ -0,0 +1,53 @@
+// 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: --expose-gc
+
+function f() {
+  this.foo00 = 0;
+  this.foo01 = 0;
+  this.foo02 = 0;
+  this.foo03 = 0;
+  this.foo04 = 0;
+  this.foo05 = 0;
+  this.foo06 = 0;
+  this.foo07 = 0;
+  this.foo08 = 0;
+  this.foo09 = 0;
+  this.foo0a = 0;
+  this.foo0b = 0;
+  this.foo0c = 0;
+  this.foo0d = 0;
+  this.foo0e = 0;
+  this.foo0f = 0;
+  this.foo10 = 0;
+  this.foo11 = 0;
+  this.foo12 = 0;
+  this.foo13 = 0;
+  this.foo14 = 0;
+  this.foo15 = 0;
+  this.foo16 = 0;
+  this.foo17 = 0;
+  this.foo18 = 0;
+  this.foo19 = 0;
+  this.foo1a = 0;
+  this.foo1b = 0;
+  this.foo1c = 0;
+  this.foo1d = 0;
+  this.foo1e = 0;
+  this.foo1f = 0;
+  this.d = 1.3;
+  gc();
+  this.boom = 230;
+  this.boom = 1.4;
+}
+
+function g() {
+  return new f();
+}
+g();
+g();
+var o = g();
+assertEquals(0, o.foo00);
+assertEquals(1.4, o.boom);
index 34713e2..e9023e1 100644 (file)
@@ -4,7 +4,7 @@
 
 // Flags: --stack-size=200 --allow-natives-syntax
 
-%Break(); // Schedule an interrupt that does not go away.
+%ScheduleBreak(); // Schedule an interrupt that does not go away.
 
 function f() { f(); }
 assertThrows(f, RangeError);
index 96dce04..67ea191 100644 (file)
@@ -10,7 +10,7 @@ Debug.setBreakOnException();
 
 try {
   try {
-    %DebugPushPromise(new Promise(function() {}));
+    %DebugPushPromise(new Promise(function() {}), function() {});
   } catch (e) {
   }
   throw new Error();
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-465564.js b/deps/v8/test/mjsunit/regress/regress-crbug-465564.js
new file mode 100644 (file)
index 0000000..ea0c8dc
--- /dev/null
@@ -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 --cache=code
+
+assertEquals(-1, %StringCompare("a", "b"));
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-467047.js b/deps/v8/test/mjsunit/regress/regress-crbug-467047.js
new file mode 100644 (file)
index 0000000..373e984
--- /dev/null
@@ -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.
+
+// Flags: --stack-size=100
+
+function captureMatch(re) {
+  var local_variable = 0;
+  "abcd".replace(re, function() { });
+  assertEquals("abcd", RegExp.input);
+  assertEquals("a", RegExp.leftContext);
+  assertEquals("bc", RegExp.lastMatch);
+  assertEquals("d", RegExp.rightContext);
+  assertEquals("foo", captureMatch(/^bar/));
+}
+
+assertThrows(function() { captureMatch(/(bc)/) }, RangeError);
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-467531.js b/deps/v8/test/mjsunit/regress/regress-crbug-467531.js
new file mode 100644 (file)
index 0000000..73256c7
--- /dev/null
@@ -0,0 +1,25 @@
+// 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: --turbo-filter=* --always-opt
+
+assertThrows(function() {
+  "use strict";
+  try {
+    x = ref_error;
+    let x = 0;
+  } catch (e) {
+    throw e;
+  }
+}, ReferenceError);
+
+assertThrows(function() {
+  "use strict";
+  try {
+    x = ref_error;
+    let x = 0;
+  } finally {
+    // re-throw
+  }
+}, ReferenceError);
diff --git a/deps/v8/test/mjsunit/regress/regress-filter-contexts.js b/deps/v8/test/mjsunit/regress/regress-filter-contexts.js
new file mode 100644 (file)
index 0000000..d2abe00
--- /dev/null
@@ -0,0 +1,14 @@
+// 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() { return f.x; }
+f.__proto__ = null;
+f.prototype = "";
+
+f();
+f();
+%OptimizeFunctionOnNextCall(f);
+f();
index 700f34a..77cca24 100644 (file)
@@ -37,5 +37,5 @@ var desc = Object.getOwnPropertyDescriptor(foo, 'length');
 assertEquals(3, desc.value);
 assertFalse(desc.writable);
 assertFalse(desc.enumerable);
-assertFalse(desc.configurable);
+assertTrue(desc.configurable);
 assertThrows(function() { foo.length = 2; }, TypeError);
index 45f4734..ae4b33a 100644 (file)
@@ -4,4 +4,4 @@
 
 // Flags: --allow-natives-syntax
 
-assertEquals(-1, %StringCompare("abc\u0102", "abc\u0201"));
+assertEquals(-1, %StringCompareRT("abc\u0102", "abc\u0201"));
index f80a627..b256033 100644 (file)
@@ -94,6 +94,37 @@ function testAnonymousMethod() {
   (function () { FAIL }).call([1, 2, 3]);
 }
 
+function testFunctionName() {
+  function gen(name, counter) {
+    var f = function foo() {
+      if (counter === 0) {
+        FAIL;
+      }
+      gen(name, counter - 1)();
+    }
+    if (counter === 4) {
+      Object.defineProperty(f, 'name', {get: function(){ throw 239; }});
+    } else if (counter == 3) {
+      Object.defineProperty(f, 'name', {value: 'boo' + '_' + counter});
+    } else {
+      Object.defineProperty(f, 'name', {writable: true});
+      if (counter === 2)
+        f.name = 42;
+      else
+        f.name = name + '_' + counter;
+    }
+    return f;
+  }
+  gen('foo', 4)();
+}
+
+function testFunctionInferredName() {
+  var f = function() {
+    FAIL;
+  }
+  f();
+}
+
 function CustomError(message, stripPoint) {
   this.message = message;
   Error.captureStackTrace(this, stripPoint);
@@ -261,6 +292,9 @@ testTrace("testValue", testValue, ["at Number.causeError"]);
 testTrace("testConstructor", testConstructor, ["new Plonk"]);
 testTrace("testRenamedMethod", testRenamedMethod, ["Wookie.a$b$c$d [as d]"]);
 testTrace("testAnonymousMethod", testAnonymousMethod, ["Array.<anonymous>"]);
+testTrace("testFunctionName", testFunctionName,
+    [" at foo_0 ", " at foo_1", " at foo ", " at boo_3 ", " at foo "]);
+testTrace("testFunctionInferredName", testFunctionInferredName, [" at f "]);
 testTrace("testDefaultCustomError", testDefaultCustomError,
     ["hep-hey", "new CustomError"],
     ["collectStackTrace"]);
index d0839ba..c97429f 100644 (file)
@@ -25,8 +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: --turbo-deoptimization --noharmony-scoping
-// Flags: --noharmony-classes --noharmony-object-literals
+// Flags: --turbo-deoptimization
 
 function CheckStrictMode(code, exception) {
   assertDoesNotThrow(code);
@@ -287,19 +286,6 @@ CheckStrictMode("function strict() { print(--arguments); }", SyntaxError);
 CheckStrictMode("function strict() { var x = --eval; }", SyntaxError);
 CheckStrictMode("function strict() { var x = --arguments; }", SyntaxError);
 
-// Use of const in strict mode is disallowed in anticipation of ES Harmony.
-CheckStrictMode("const x = 0;", SyntaxError);
-CheckStrictMode("for (const x = 0; false;) {}", SyntaxError);
-CheckStrictMode("function strict() { const x = 0; }", SyntaxError);
-
-// Strict mode only allows functions in StatementList
-CheckStrictMode("if (true) { function invalid() {} }", SyntaxError);
-CheckStrictMode("for (;false;) { function invalid() {} }", SyntaxError);
-CheckStrictMode("{ function invalid() {} }", SyntaxError);
-CheckStrictMode("try { function invalid() {} } catch(e) {}", SyntaxError);
-CheckStrictMode("try { } catch(e) { function invalid() {} }", SyntaxError);
-CheckStrictMode("function outer() {{ function invalid() {} }}", SyntaxError);
-
 // Delete of an unqualified identifier
 CheckStrictMode("delete unqualified;", SyntaxError);
 CheckStrictMode("function strict() { delete unqualified; }", SyntaxError);
diff --git a/deps/v8/test/mjsunit/string-concat.js b/deps/v8/test/mjsunit/string-concat.js
new file mode 100644 (file)
index 0000000..c669b3b
--- /dev/null
@@ -0,0 +1,14 @@
+// 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 Stringified(toString) {
+  var valueOf = "-" + toString + "-";
+  return {
+    toString: function() { return toString; },
+    valueOf: function() { return valueOf; }
+  };
+}
+
+assertEquals("a.b.", "a.".concat(Stringified("b.")));
+assertEquals("a.b.c.", "a.".concat(Stringified("b."), Stringified("c.")));
index 315708c..1c0e3d9 100644 (file)
@@ -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
+
 /**
  * @fileoverview Test indexing on strings with [].
  */
@@ -250,6 +252,20 @@ for (var i = 0; i < 100; ++i) {
   assertEquals(expected, actual);
 }
 
+// Test out of range with a heap number case.
+var num = Math.floor(4) * 0.5;
+// TODO(mvstanton): figure out a reliable way to get a heap number every time.
+// assertFalse(!%_IsSmi(num));
+var keys = [0, num];
+var str = 'ab', arr = ['a', undefined];
+for (var i = 0; i < 100; ++i) {
+  var index = Math.floor(i / 50);
+  var key = keys[index];
+  var expected = arr[index];
+  var actual = str[key];
+  assertEquals(expected, actual);
+}
+
 // Test two byte string.
 var str = '\u0427', arr = ['\u0427'];
 for (var i = 0; i < 50; ++i) {
diff --git a/deps/v8/test/mjsunit/strong/arrays.js b/deps/v8/test/mjsunit/strong/arrays.js
new file mode 100644 (file)
index 0000000..b9e4fad
--- /dev/null
@@ -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: --strong-mode
+
+(function NoEllisions() {
+  assertThrows("'use strong'; [,]", SyntaxError);
+  assertThrows("'use strong'; [,3]", SyntaxError);
+  assertThrows("'use strong'; [3,,4]", SyntaxError);
+  assertTrue(eval("'use strong'; [3,] !== [3,4,]"));
+})();
index 3c7caf5..e33742a 100644 (file)
@@ -3,15 +3,58 @@
 // found in the LICENSE file.
 
 // Flags: --strong-mode
+// Flags: --harmony-classes --harmony-arrow-functions
 
 'use strong';
 
 class C {}
 
+function assertTypeError(script) { assertThrows(script, TypeError) }
+function assertSyntaxError(script) { assertThrows(script, SyntaxError) }
+function assertReferenceError(script) { assertThrows(script, ReferenceError) }
+
 (function ImmutableClassBindings() {
   class D {}
-  assertThrows(function(){ eval("C = 0") }, TypeError);
-  assertThrows(function(){ eval("D = 0") }, TypeError);
+  assertTypeError(function(){ eval("C = 0") });
+  assertTypeError(function(){ eval("D = 0") });
   assertEquals('function', typeof C);
   assertEquals('function', typeof D);
 })();
+
+function constructor(body) {
+  return "'use strong'; " +
+      "(class extends Object { constructor() { " + body + " } })";
+}
+
+(function NoMissingSuper() {
+  assertReferenceError(constructor(""));
+  assertReferenceError(constructor("1"));
+})();
+
+(function NoNestedSuper() {
+  assertSyntaxError(constructor("(super());"));
+  assertSyntaxError(constructor("(() => super())();"));
+  assertSyntaxError(constructor("{ super(); }"));
+  assertSyntaxError(constructor("if (1) super();"));
+})();
+
+(function NoDuplicateSuper() {
+  assertSyntaxError(constructor("super(), super();"));
+  assertSyntaxError(constructor("super(); super();"));
+  assertSyntaxError(constructor("super(); (super());"));
+  assertSyntaxError(constructor("super(); { super() }"));
+  assertSyntaxError(constructor("super(); (() => super())();"));
+})();
+
+(function NoReturnValue() {
+  assertSyntaxError(constructor("return {};"));
+  assertSyntaxError(constructor("return undefined;"));
+  assertSyntaxError(constructor("{ return {}; }"));
+  assertSyntaxError(constructor("if (1) return {};"));
+})();
+
+(function NoReturnBeforeSuper() {
+  assertSyntaxError(constructor("return; super();"));
+  assertSyntaxError(constructor("if (0) return; super();"));
+  assertSyntaxError(constructor("{ return; } super();"));
+})();
diff --git a/deps/v8/test/mjsunit/strong/declaration-after-use.js b/deps/v8/test/mjsunit/strong/declaration-after-use.js
new file mode 100644 (file)
index 0000000..aa5ff67
--- /dev/null
@@ -0,0 +1,258 @@
+// 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: --strong-mode --harmony_rest_parameters --harmony_arrow_functions --harmony_classes --harmony_computed-property_names
+
+// Note that it's essential for these tests that the reference is inside dead
+// code (because we already produce ReferenceErrors for run-time unresolved
+// variables and don't want to confuse those with strong mode errors). But the
+// errors should *not* be inside lazy, unexecuted functions, since lazy parsing
+// doesn't produce strong mode scoping errors).
+
+// In addition, assertThrows will call eval and that changes variable binding
+// types (see e.g., UNBOUND_EVAL_SHADOWED). We can avoid unwanted side effects
+// by wrapping the code to be tested inside an outer function.
+function assertThrowsHelper(code) {
+  "use strict";
+  let prologue = "(function outer() { if (false) { ";
+  let epilogue = " } })();";
+
+  assertThrows("'use strong'; " + prologue + code + epilogue, ReferenceError);
+
+  // Make sure the error happens only in strong mode (note that we need strict
+  // mode here because of let).
+  assertDoesNotThrow("'use strict'; " + prologue + code + epilogue);
+}
+
+(function DeclarationAfterUse() {
+  // Note that these tests only test cases where the declaration is found but is
+  // after the use. In particular, we cannot yet detect cases where the use can
+  // possibly bind to a global variable.
+  assertThrowsHelper("x; let x = 0;");
+  assertThrowsHelper("function f() { x; let x = 0; }");
+  assertThrowsHelper("function f() { x; } let x = 0;");
+
+  // These tests needs to be done a bit more manually, since var is not allowed
+  // in strong mode:
+  assertThrows(
+      `(function outer() {
+        function f() { 'use strong'; if (false) { x; } } var x = 0; f();
+      })()`,
+      ReferenceError);
+  assertDoesNotThrow(
+      "(function outer() {\n" +
+      "  function f() { if (false) { x; } } var x = 0; f(); \n" +
+      "})()");
+
+  assertThrows(
+      "(function outer() {\n" +
+      "  function f() { 'use strong'; if (false) { x; } } var x; f(); \n" +
+      "})()",
+      ReferenceError);
+  assertDoesNotThrow(
+      "(function outer() {\n" +
+      "  function f() { if (false) { x; } } var x; f(); \n" +
+      "})()");
+
+  // Errors are also detected when the declaration and the use are in the same
+  // eval scope.
+  assertThrows("'use strong'; eval('if (false) { x; let x = 0;}')",
+               ReferenceError);
+  assertDoesNotThrow("'use strict'; eval('if (false) { x; let x = 0; }')");
+
+  // Use occurring in the initializer of the declaration:
+  assertThrowsHelper("let x = x + 1;");
+  assertThrowsHelper("let x = x;");
+  assertThrowsHelper("let x = y, y = 4;");
+  assertThrowsHelper("let x = function() { x; }");
+  assertThrowsHelper("let x = a => { x; }");
+  assertThrowsHelper("function f(x) { return x; }; let x = f(x);");
+  assertThrowsHelper("const x = x;");
+  assertThrowsHelper("const x = function() { x; }");
+  assertThrowsHelper("const x = a => { x; }");
+  assertThrowsHelper("function f(x) {return x}; const x = f(x);");
+
+  assertThrowsHelper("for (let x = x; ; ) { }");
+  assertThrowsHelper("for (const x = x; ; ) { }");
+  assertThrowsHelper("for (let x = y, y; ; ) { }");
+  assertThrowsHelper("for (const x = y, y = 0; ; ) { }");
+
+  // Computed property names
+  assertThrowsHelper("let o = { 'a': 'b', [o.a]: 'c'};");
+})();
+
+
+(function DeclarationAfterUseInClasses() {
+  assertThrowsHelper("class C extends C { }");
+  assertThrowsHelper("let C = class C2 extends C { }");
+  assertThrowsHelper("let C = class C2 extends C2 { }");
+
+  assertThrowsHelper("let C = class C2 { constructor() { C; } }");
+  assertThrowsHelper("let C = class C2 { method() { C; } }");
+  assertThrowsHelper("let C = class C2 { *generator_method() { C; } }");
+
+  assertThrowsHelper(
+      `let C = class C2 {
+        static a() { return 'A'; }
+        [C.a()]() { return 'B'; }
+      };`);
+
+  assertThrowsHelper(
+      `let C = class C2 {
+        static a() { return 'A'; }
+        [C2.a()]() { return 'B'; }
+      };`);
+
+  assertThrowsHelper(
+      `let C = class C2 {
+        [(function() { C; return 'A';})()]() { return 'B'; }
+      };`);
+
+  // The reference to C or C2 is inside a function, but not a method.
+  assertThrowsHelper(
+      `let C = class C2 {
+        [(function() { C2; return 'A';})()]() { return 'B'; }
+      };`);
+
+  assertThrowsHelper(
+      `let C = class C2 {
+        [(function() { C; return 'A';})()]() { return 'B'; }
+      };`);
+
+  // The reference to C or C2 is inside a method, but it's not a method of the
+  // relevant class (C2).
+  assertThrowsHelper(
+      `let C = class C2 {
+        [(new (class D { m() { C2; return 'A'; } })).m()]() {
+          return 'B';
+        }
+      }`);
+
+  assertThrowsHelper(
+      `let C = class C2 {
+        [(new (class D { m() { C; return 'A'; } })).m()]() {
+          return 'B';
+        }
+      }`);
+
+  assertThrowsHelper(
+      `let C = class C2 {
+        [({m() { C2; return 'A'; }}).m()]() { return 'B'; }
+      }`);
+
+  assertThrowsHelper(
+      `let C = class C2 {
+        [({m() { C; return 'A'; }}).m()]() { return 'B'; }
+      }`);
+
+  assertThrowsHelper(
+      `class COuter {
+        m() {
+          class CInner {
+            [({ m() { CInner; return 'A'; } }).m()]() {
+                return 'B';
+            }
+          }
+        }
+      }`);
+})();
+
+
+(function UsesWhichAreFine() {
+  "use strong";
+
+  let var1 = 0;
+  var1;
+
+  let var2a = 0, var2b = var2a + 1, var2c = 2 + var2b;
+
+  for (let var3 = 0; var3 < 1; var3++) {
+    var3;
+  }
+
+  for (let var4a = 0, var4b = var4a; var4a + var4b < 4; var4a++, var4b++) {
+    var4a;
+    var4b;
+  }
+
+  let var5 = 5;
+  for (; var5 < 10; ++var5) { }
+
+  let arr = [1, 2];
+  for (let i of arr) {
+    i;
+  }
+
+  let var6 = [1, 2];
+  // The second var6 resolves to outside (not to the first var6).
+  for (let var6 of var6) { var6; }
+
+  try {
+    throw "error";
+  } catch (e) {
+    e;
+  }
+
+  function func1() { func1; this; }
+  func1();
+  func1;
+
+  function * func2() { func2; this; }
+  func2();
+  func2;
+
+  function func4(p, ...rest) { p; rest; this; func2; }
+  func4();
+
+  let func5 = (p1, p2) => { p1; p2; };
+  func5();
+
+  let func5b = p1 => p1;
+  func5b();
+
+  function func6() {
+    var1, var2a, var2b, var2c;
+  }
+
+  (function eval1() {
+    let var7 = 0; // Declaration position will be something large.
+    // But use position will be something small, however, this is not an error,
+    // since the use is inside an eval scope.
+    eval("var7;");
+  })();
+
+
+  class C1 { constructor() { C1; } }; new C1();
+  let C2 = class C3 { constructor() { C3; } }; new C2();
+
+  class C4 { method() { C4; } *generator_method() { C4; } }; new C4();
+  let C5 = class C6 { method() { C6; } *generator_method() { C6; } }; new C5();
+
+  class C7 { static method() { C7; } }; new C7();
+  let C8 = class C9 { static method() { C9; } }; new C8();
+
+  class C10 { get x() { C10; } }; new C10();
+  let C11 = class C12 { get x() { C12; } }; new C11();
+
+  // Regression test for unnamed classes.
+  let C13 = class { m() { var1; } };
+
+  class COuter {
+    m() {
+      class CInner {
+        // Here we can refer to COuter but not to CInner (see corresponding
+        // assertion test):
+        [({ m() { COuter; return 'A'; } }).m()]() { return 'B'; }
+        // And here we can refer to both:
+        n() { COuter; CInner; }
+      }
+      return new CInner();
+    }
+  }
+  (new COuter()).m().n();
+
+  // Making sure the check which is supposed to prevent "object literal inside
+  // computed property name references the class name" is not too generic:
+  class C14 { m() { let obj = { n() { C14 } }; obj.n(); } }; (new C14()).m();
+})();
index 4869ac6..6956462 100644 (file)
@@ -6,28 +6,82 @@
 
 'use strong';
 
+function f() {}
+function* g() {}
+
 (function NoArguments() {
   assertThrows("'use strong'; arguments", SyntaxError);
   assertThrows("'use strong'; function f() { arguments }", SyntaxError);
+  assertThrows("'use strong'; function* g() { arguments }", SyntaxError);
   assertThrows("'use strong'; let f = function() { arguments }", SyntaxError);
+  assertThrows("'use strong'; let g = function*() { arguments }", SyntaxError);
   assertThrows("'use strong'; let f = () => arguments", SyntaxError);
   // The following are strict mode errors already.
   assertThrows("'use strong'; let arguments", SyntaxError);
   assertThrows("'use strong'; function f(arguments) {}", SyntaxError);
+  assertThrows("'use strong'; function* g(arguments) {}", SyntaxError);
   assertThrows("'use strong'; let f = (arguments) => {}", SyntaxError);
 })();
 
-function g() {}
+(function NoArgumentsProperty() {
+  assertFalse(f.hasOwnProperty("arguments"));
+  assertFalse(g.hasOwnProperty("arguments"));
+  assertThrows(function(){ f.arguments = 0 }, TypeError);
+  assertThrows(function(){ g.arguments = 0 }, TypeError);
+})();
+
+(function NoCaller() {
+  assertFalse(f.hasOwnProperty("caller"));
+  assertFalse(g.hasOwnProperty("caller"));
+  assertThrows(function(){ f.caller = 0 }, TypeError);
+  assertThrows(function(){ g.caller = 0 }, TypeError);
+})();
+
+(function NoCallee() {
+  assertFalse("callee" in f);
+  assertFalse("callee" in g);
+  assertThrows(function(){ f.callee = 0 }, TypeError);
+  assertThrows(function(){ g.callee = 0 }, TypeError);
+})();
 
-(function LexicalFunctionBindings(global) {
+(function LexicalBindings(global) {
+  assertEquals('function', typeof f);
   assertEquals('function', typeof g);
+  assertEquals(undefined, global.f);
   assertEquals(undefined, global.g);
 })(this);
 
-(function ImmutableFunctionBindings() {
-  function f() {}
-  assertThrows(function(){ eval("g = 0") }, TypeError);
-  assertThrows(function(){ eval("f = 0") }, TypeError);
-  assertEquals('function', typeof g);
+(function ImmutableBindings() {
+  function f2() {}
+  function* g2() {}
+  assertThrows(function(){ f = 0 }, TypeError);
+  assertThrows(function(){ g = 0 }, TypeError);
+  assertThrows(function(){ f2 = 0 }, TypeError);
+  assertThrows(function(){ g2 = 0 }, TypeError);
   assertEquals('function', typeof f);
+  assertEquals('function', typeof g);
+  assertEquals('function', typeof f2);
+  assertEquals('function', typeof g2);
+})();
+
+(function NonExtensible() {
+  assertThrows(function(){ f.a = 0 }, TypeError);
+  assertThrows(function(){ g.a = 0 }, TypeError);
+  assertThrows(function(){ Object.defineProperty(f, "a", {value: 0}) }, TypeError);
+  assertThrows(function(){ Object.defineProperty(g, "a", {value: 0}) }, TypeError);
+  assertThrows(function(){ Object.setPrototypeOf(f, {}) }, TypeError);
+  assertThrows(function(){ Object.setPrototypeOf(g, {}) }, TypeError);
+})();
+
+(function NoPrototype() {
+  assertFalse("prototype" in f);
+  assertFalse(g.hasOwnProperty("prototype"));
+  assertThrows(function(){ f.prototype = 0 }, TypeError);
+  assertThrows(function(){ g.prototype = 0 }, TypeError);
+  assertThrows(function(){ f.prototype.a = 0 }, TypeError);
+})();
+
+(function NonConstructor() {
+  assertThrows(function(){ new f }, TypeError);
+  assertThrows(function(){ new g }, TypeError);
 })();
index 0d6baf0..a1254db 100644 (file)
   # TODO(turbofan): Large switch statements crash.
   'js1_5/Regress/regress-398085-01': [PASS, NO_VARIANTS],
 
+  ############################ INVALID TESTS #############################
+
+  # Function length properties are configurable in ES6
+  'ecma/Array/15.4.4.3-1': [FAIL],
+  'ecma/Array/15.4.4.4-1': [FAIL],
+  'ecma/Array/15.4.4.4-2': [FAIL],
+  'ecma/String/15.5.4.10-1': [FAIL],
+  'ecma/String/15.5.4.11-1': [FAIL],
+  'ecma/String/15.5.4.7-2': [FAIL],
+  'ecma/String/15.5.4.8-1': [FAIL],
+  'ecma/String/15.5.4.9-1': [FAIL],
+
+
   ##################### SKIPPED TESTS #####################
 
   # This test checks that we behave properly in an out-of-memory
diff --git a/deps/v8/test/preparser/strict-function-statement.pyt b/deps/v8/test/preparser/strict-function-statement.pyt
deleted file mode 100644 (file)
index cc3d7bb..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-# 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:
-#
-#     * 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.
-
-# In strict mode, function declarations may only appear as source elements.
-
-# A template that performs the same strict-mode test in different
-# scopes (global scope, function scope, and nested function scope).
-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", 
-       extra_flags)
-  Test(name + '-infunc2',
-       'function foo() {\n "use strict";\n  function bar() {\n' +
-       source +'\n }\n}\n',
-       "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)
-
-
-
index fd93f29..c004242 100644 (file)
   ############################### BUGS ###################################
 
   # BUG(v8:3455)
-  '11.2.3_b': [FAIL],
-  '12.2.3_b': [FAIL],
+  'intl402/ch11/11.2/11.2.3_b': [FAIL],
+  'intl402/ch12/12.2/12.2.3_b': [FAIL],
 
   # Unicode canonicalization is not available with i18n turned off.
-  '15.5.4.9_CE': [['no_i18n', SKIP]],
+  'ch15/15.5/15.5.4/15.5.4.9/15.5.4.9_CE': [['no_i18n', SKIP]],
 
   ###################### NEEDS INVESTIGATION #######################
 
   # Possibly same cause as S8.5_A2.1, below: floating-point tests.
-  'S15.8.2.16_A7': [PASS, FAIL_OK],
-  'S15.8.2.18_A7': [PASS, FAIL_OK],
-  'S15.8.2.7_A7': [PASS, FAIL_OK],
+  'ch15/15.8/15.8.2/15.8.2.16/S15.8.2.16_A7': [PASS, FAIL_OK],
+  'ch15/15.8/15.8.2/15.8.2.18/S15.8.2.18_A7': [PASS, FAIL_OK],
+  'ch15/15.8/15.8.2/15.8.2.7/S15.8.2.7_A7': [PASS, FAIL_OK],
 
   # This is an incompatibility between ES5 and V8 on enumerating
   # shadowed elements in a for..in loop.
   # https://code.google.com/p/v8/issues/detail?id=705
-  '12.6.4-2': [PASS, FAIL_OK],
+  'ch12/12.6/12.6.4/12.6.4-2': [PASS, FAIL_OK],
 
   ###################### MISSING ES6 FEATURES #######################
 
   # Array.fill (currently requires --harmony-arrays)
-  'S22.1.3.6_T1': [FAIL],
+  'es6/ch22/22.1/22.1.3/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],
+  'es6/ch22/22.1/22.1.2/S22.1.2.3_T1': [FAIL],
+  'es6/ch22/22.1/22.1.2/S22.1.2.3_T2': [FAIL],
+  'es6/Array.prototype.find/Array.prototype.find_empty-array-undefined': [FAIL],
+  'es6/Array.prototype.find/Array.prototype.find_length-property': [FAIL],
+  'es6/Array.prototype.find/Array.prototype.find_modify-after-start': [FAIL],
+  'es6/Array.prototype.find/Array.prototype.find_non-returning-predicate': [FAIL],
+  'es6/Array.prototype.find/Array.prototype.find_predicate-arguments': [FAIL],
+  'es6/Array.prototype.find/Array.prototype.find_push-after-start': [FAIL],
+  'es6/Array.prototype.find/Array.prototype.find_remove-after-start': [FAIL],
+  'es6/Array.prototype.find/Array.prototype.find_return-found-value': [FAIL],
+  'es6/Array.prototype.find/Array.prototype.find_skip-empty': [FAIL],
+  'es6/Array.prototype.find/Array.prototype.find_this-defined': [FAIL],
+  'es6/Array.prototype.find/Array.prototype.find_this-is-object': [FAIL],
+  'es6/Array.prototype.find/Array.prototype.find_this-undefined': [FAIL],
 
   # Array.from
-  'S22.1.2.1_T1': [FAIL],
-  'S22.1.2.1_T2': [FAIL],
+  'es6/ch22/22.1/22.1.2/S22.1.2.1_T1': [FAIL],
+  'es6/ch22/22.1/22.1.2/S22.1.2.1_T2': [FAIL],
 
   # Direct proxies
-  'Array.prototype.find_callable-predicate': [FAIL],
+  'es6/Array.prototype.find/Array.prototype.find_callable-predicate': [FAIL],
 
   ######################## OBSOLETED BY ES6 ###########################
 
   # ES6 allows duplicate properties
-  '11.1.5-4-4-a-1-s': [FAIL],
-  '11.1.5_4-4-b-1': [FAIL],
-  '11.1.5_4-4-b-2': [FAIL],
-  '11.1.5_4-4-c-1': [FAIL],
-  '11.1.5_4-4-c-2': [FAIL],
-  '11.1.5_4-4-d-1': [FAIL],
-  '11.1.5_4-4-d-2': [FAIL],
-  '11.1.5_4-4-d-3': [FAIL],
-  '11.1.5_4-4-d-4': [FAIL],
+  'ch11/11.1/11.1.5/11.1.5-4-4-a-1-s': [FAIL],
+  'ch11/11.1/11.1.5/11.1.5_4-4-b-1': [FAIL],
+  'ch11/11.1/11.1.5/11.1.5_4-4-b-2': [FAIL],
+  'ch11/11.1/11.1.5/11.1.5_4-4-c-1': [FAIL],
+  'ch11/11.1/11.1.5/11.1.5_4-4-c-2': [FAIL],
+  'ch11/11.1/11.1.5/11.1.5_4-4-d-1': [FAIL],
+  'ch11/11.1/11.1.5/11.1.5_4-4-d-2': [FAIL],
+  'ch11/11.1/11.1.5/11.1.5_4-4-d-3': [FAIL],
+  'ch11/11.1/11.1.5/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],
+  'ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1': [FAIL],
+  'ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-4': [FAIL],
+  'ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-5': [FAIL],
 
   # ES6 allows block-local functions.
-  'Sbp_A1_T1': [FAIL],
-  'Sbp_A2_T1': [FAIL],
-  'Sbp_A2_T2': [FAIL],
-  'Sbp_A3_T1': [FAIL],
-  'Sbp_A3_T2': [FAIL],
-  'Sbp_A4_T1': [FAIL],
-  'Sbp_A4_T2': [FAIL],
-  'Sbp_A5_T1': [PASS], # Test is broken (strict reference to unbound variable)
-  'Sbp_A5_T2': [FAIL],
+  'bestPractice/Sbp_A1_T1': [FAIL],
+  'bestPractice/Sbp_A2_T1': [FAIL],
+  'bestPractice/Sbp_A2_T2': [FAIL],
+  'bestPractice/Sbp_A3_T1': [FAIL],
+  'bestPractice/Sbp_A3_T2': [FAIL],
+  'bestPractice/Sbp_A4_T1': [FAIL],
+  'bestPractice/Sbp_A4_T2': [FAIL],
+  'bestPractice/Sbp_A5_T1': [PASS], # Test is broken (strict reference to unbound variable)
+  'bestPractice/Sbp_A5_T2': [FAIL],
 
   ######################## NEEDS INVESTIGATION ###########################
 
   # These test failures are specific to the intl402 suite and need investigation
   # to be either marked as bugs with issues filed for them or as deliberate
   # incompatibilities if the test cases turn out to be broken or ambiguous.
-  '6.2.3': [FAIL],
-  '9.2.1_2': [FAIL],
-  '9.2.6_2': [FAIL],
-  '10.1.1_a': [FAIL],
-  '10.1.1_19_c': [PASS, FAIL, NO_VARIANTS],
-  '10.1.2.1_4': [FAIL],
-  '10.2.3_b': [PASS, FAIL],
-  '10.3_a': [FAIL],
-  '11.1.1_17': [PASS, FAIL],
-  '11.1.1_19': [PASS, FAIL],
-  '11.1.1_20_c': [FAIL],
-  '11.1.1_a': [FAIL],
-  '11.1.2.1_4': [FAIL],
-  '11.3.2_FN_2': [PASS, FAIL],
-  '11.3.2_TRF': [PASS, FAIL],
-  '11.3_a': [FAIL],
-  '12.1.1_a': [FAIL],
-  '12.1.2.1_4': [FAIL],
-  '12.3.2_FDT_7_a_iv': [FAIL],
-  '12.3.3': [FAIL],
-  '12.3_a': [FAIL],
-  '15.5.4.9_3': [PASS, FAIL],
+  'intl402/ch06/6.2/6.2.3': [FAIL],
+  'intl402/ch09/9.2/9.2.1_2': [FAIL],
+  'intl402/ch09/9.2/9.2.6_2': [FAIL],
+  'intl402/ch10/10.1/10.1.1_a': [FAIL],
+  'intl402/ch10/10.1/10.1.1_19_c': [PASS, FAIL, NO_VARIANTS],
+  'intl402/ch10/10.1/10.1.2.1_4': [FAIL],
+  'intl402/ch10/10.2/10.2.3_b': [PASS, FAIL],
+  'intl402/ch10/10.3/10.3_a': [FAIL],
+  'intl402/ch11/11.1/11.1.1_17': [PASS, FAIL],
+  'intl402/ch11/11.1/11.1.1_19': [PASS, FAIL],
+  'intl402/ch11/11.1/11.1.1_20_c': [FAIL],
+  'intl402/ch11/11.1/11.1.1_a': [FAIL],
+  'intl402/ch11/11.1/11.1.2.1_4': [FAIL],
+  'intl402/ch11/11.3/11.3.2_FN_2': [PASS, FAIL],
+  'intl402/ch11/11.3/11.3.2_TRF': [PASS, FAIL],
+  'intl402/ch11/11.3/11.3_a': [FAIL],
+  'intl402/ch12/12.1/12.1.1_a': [FAIL],
+  'intl402/ch12/12.1/12.1.2.1_4': [FAIL],
+  'intl402/ch12/12.3/12.3.2_FDT_7_a_iv': [FAIL],
+  'intl402/ch12/12.3/12.3.3': [FAIL],
+  'intl402/ch12/12.3/12.3_a': [FAIL],
+  'intl402/ch15/15.5/15.5.4/15.5.4.915.5.4.9_3': [PASS, FAIL],
 
   ##################### DELIBERATE INCOMPATIBILITIES #####################
 
-  'S15.8.2.8_A6': [PASS, FAIL_OK],  # Math.exp (less precise with --fast-math)
+  'ch15/15.8/15.8.2/15.8.2.8/S15.8.2.8_A6': [PASS, FAIL_OK],  # Math.exp (less precise with --fast-math)
 
   # Linux for ia32 (and therefore simulators) default to extended 80 bit
   # floating point formats, so these tests checking 64-bit FP precision fail.
   # The other platforms/arch's pass these tests.
   # We follow the other major JS engines by keeping this default.
-  'S8.5_A2.1': [PASS, FAIL_OK],
-  'S8.5_A2.2': [PASS, FAIL_OK],
+  'ch08/8.5/S8.5_A2.1': [PASS, FAIL_OK],
+  'ch08/8.5/S8.5_A2.2': [PASS, FAIL_OK],
 
   ############################ INVALID TESTS #############################
 
   # tests in PST/PDT between first Sunday in March and first Sunday in April.
   # The DST switch was moved in 2007 whereas Test262 bases the reference value
   # on 2000. Test262 Bug: https://bugs.ecmascript.org/show_bug.cgi?id=293
-  'S15.9.3.1_A5_T1': [PASS, FAIL_OK],
-  'S15.9.3.1_A5_T2': [PASS, FAIL_OK],
-  'S15.9.3.1_A5_T3': [PASS, FAIL_OK],
-  'S15.9.3.1_A5_T4': [PASS, FAIL_OK],
-  'S15.9.3.1_A5_T5': [PASS, FAIL_OK],
-  'S15.9.3.1_A5_T6': [PASS, FAIL_OK],
+  'ch15/15.9/15.9.3/S15.9.3.1_A5_T1': [PASS, FAIL_OK],
+  'ch15/15.9/15.9.3/S15.9.3.1_A5_T2': [PASS, FAIL_OK],
+  'ch15/15.9/15.9.3/S15.9.3.1_A5_T3': [PASS, FAIL_OK],
+  'ch15/15.9/15.9.3/S15.9.3.1_A5_T4': [PASS, FAIL_OK],
+  'ch15/15.9/15.9.3/S15.9.3.1_A5_T5': [PASS, FAIL_OK],
+  'ch15/15.9/15.9.3/S15.9.3.1_A5_T6': [PASS, FAIL_OK],
 
   # Test makes unjustified assumptions about the number of calls to SortCompare.
   # Test262 Bug: https://bugs.ecmascript.org/show_bug.cgi?id=596
-  'bug_596_1': [PASS, FAIL_OK],
+  'es6/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],
+  'ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-1': [PASS, FAIL_OK],
+  'ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-2': [PASS, FAIL_OK],
+  'ch15/15.2/15.2.3/15.2.3.14/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],
-
+  'es6/String.prototype.contains/String.prototype.contains_FailBadLocation' : [FAIL_OK],
+  'es6/String.prototype.contains/String.prototype.contains_FailLocation' : [FAIL_OK],
+  'es6/String.prototype.contains/String.prototype.contains_FailMissingLetter' : [FAIL_OK],
+  'es6/String.prototype.contains/String.prototype.contains_lengthProp' : [FAIL_OK],
+  'es6/String.prototype.contains/String.prototype.contains_Success' : [FAIL_OK],
+  'es6/String.prototype.contains/String.prototype.contains_SuccessNoLocation' : [FAIL_OK],
+
+  # Function length properties are configurable in ES6
+  'ch11/11.4/11.4.1/11.4.1-5-a-28-s': [FAIL],
+  'ch13/13.2/13.2-15-1': [FAIL],
+  'ch15/15.1/15.1.2/15.1.2.1/S15.1.2.1_A4.2': [FAIL],
+  'ch15/15.1/15.1.2/15.1.2.2/S15.1.2.2_A9.2': [FAIL],
+  'ch15/15.1/15.1.2/15.1.2.3/S15.1.2.3_A7.2': [FAIL],
+  'ch15/15.1/15.1.2/15.1.2.4/S15.1.2.4_A2.2': [FAIL],
+  'ch15/15.1/15.1.2/15.1.2.5/S15.1.2.5_A2.2': [FAIL],
+  'ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A5.2': [FAIL],
+  'ch15/15.1/15.1.3/15.1.3.2/S15.1.3.2_A5.2': [FAIL],
+  'ch15/15.1/15.1.3/15.1.3.3/S15.1.3.3_A5.2': [FAIL],
+  'ch15/15.1/15.1.3/15.1.3.4/S15.1.3.4_A5.2': [FAIL],
+  'ch15/15.10/15.10.6/15.10.6.2/S15.10.6.2_A9': [FAIL],
+  'ch15/15.10/15.10.6/15.10.6.3/S15.10.6.3_A9': [FAIL],
+  'ch15/15.10/15.10.6/15.10.6.4/S15.10.6.4_A9': [FAIL],
+  'ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-186': [FAIL],
+  'ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-187': [FAIL],
+  'ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-191': [FAIL],
+  'ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-194': [FAIL],
+  'ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-201': [FAIL],
+  'ch15/15.2/15.2.4/15.2.4.2/S15.2.4.2_A9': [FAIL],
+  'ch15/15.2/15.2.4/15.2.4.3/S15.2.4.3_A9': [FAIL],
+  'ch15/15.2/15.2.4/15.2.4.4/S15.2.4.4_A9': [FAIL],
+  'ch15/15.2/15.2.4/15.2.4.5/S15.2.4.5_A9': [FAIL],
+  'ch15/15.2/15.2.4/15.2.4.6/S15.2.4.6_A9': [FAIL],
+  'ch15/15.2/15.2.4/15.2.4.7/S15.2.4.7_A9': [FAIL],
+  'ch15/15.3/15.3.3/15.3.3.2/15.3.3.2-1': [FAIL],
+  'ch15/15.3/15.3.4/15.3.4.2/S15.3.4.2_A9': [FAIL],
+  'ch15/15.3/15.3.4/15.3.4.3/S15.3.4.3_A9': [FAIL],
+  'ch15/15.3/15.3.4/15.3.4.4/S15.3.4.4_A9': [FAIL],
+  'ch15/15.3/15.3.5/S15.3.5.1_A2_T1': [FAIL],
+  'ch15/15.3/15.3.5/S15.3.5.1_A2_T2': [FAIL],
+  'ch15/15.3/15.3.5/S15.3.5.1_A2_T3': [FAIL],
+  'ch15/15.4/15.4.3/S15.4.3_A2.2': [FAIL],
+  'ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A5.2': [FAIL],
+  'ch15/15.4/15.4.4/15.4.4.11/S15.4.4.11_A7.2': [FAIL],
+  'ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A5.2': [FAIL],
+  'ch15/15.4/15.4.4/15.4.4.13/S15.4.4.13_A5.2': [FAIL],
+  'ch15/15.4/15.4.4/15.4.4.2/S15.4.4.2_A4.2': [FAIL],
+  'ch15/15.4/15.4.4/15.4.4.3/S15.4.4.3_A4.2': [FAIL],
+  'ch15/15.4/15.4.4/15.4.4.4/S15.4.4.4_A4.2': [FAIL],
+  'ch15/15.4/15.4.4/15.4.4.5/S15.4.4.5_A6.2': [FAIL],
+  'ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A5.2': [FAIL],
+  'ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A6.2': [FAIL],
+  'ch15/15.4/15.4.4/15.4.4.8/S15.4.4.8_A5.2': [FAIL],
+  'ch15/15.4/15.4.4/15.4.4.9/S15.4.4.9_A5.2': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.10/S15.5.4.10_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.11/S15.5.4.11_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.12/S15.5.4.12_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.13/S15.5.4.13_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.14/S15.5.4.14_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.15/S15.5.4.15_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.16/S15.5.4.16_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.17/S15.5.4.17_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.18/S15.5.4.18_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.19/S15.5.4.19_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.4/S15.5.4.4_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.5/S15.5.4.5_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.6/S15.5.4.6_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.7/S15.5.4.7_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.8/S15.5.4.8_A9': [FAIL],
+  'ch15/15.5/15.5.4/15.5.4.9/S15.5.4.9_A9': [FAIL],
+  'ch15/15.9/15.9.4/15.9.4.2/S15.9.4.2_A3_T2': [FAIL],
+  'ch15/15.9/15.9.4/15.9.4.3/S15.9.4.3_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.1/S15.9.5.1_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.10/S15.9.5.10_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.11/S15.9.5.11_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.12/S15.9.5.12_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.13/S15.9.5.13_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.14/S15.9.5.14_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.15/S15.9.5.15_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.16/S15.9.5.16_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.17/S15.9.5.17_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.18/S15.9.5.18_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.19/S15.9.5.19_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.2/S15.9.5.2_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.20/S15.9.5.20_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.21/S15.9.5.21_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.22/S15.9.5.22_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.23/S15.9.5.23_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.24/S15.9.5.24_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.25/S15.9.5.25_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.26/S15.9.5.26_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.27/S15.9.5.27_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.28/S15.9.5.28_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.29/S15.9.5.29_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.3/S15.9.5.3_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.30/S15.9.5.30_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.31/S15.9.5.31_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.32/S15.9.5.32_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.33/S15.9.5.33_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.34/S15.9.5.34_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.35/S15.9.5.35_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.36/S15.9.5.36_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.37/S15.9.5.37_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.38/S15.9.5.38_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.39/S15.9.5.39_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.4/S15.9.5.4_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.40/S15.9.5.40_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.41/S15.9.5.41_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.42/S15.9.5.42_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.5/S15.9.5.5_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.6/S15.9.5.6_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.7/S15.9.5.7_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.8/S15.9.5.8_A3_T2': [FAIL],
+  'ch15/15.9/15.9.5/15.9.5.9/S15.9.5.9_A3_T2': [FAIL],
+  'intl402/ch10/10.1/10.1_L15': [FAIL],
+  'intl402/ch10/10.2/10.2.2_L15': [FAIL],
+  'intl402/ch10/10.3/10.3.2_1_a_L15': [FAIL],
+  'intl402/ch10/10.3/10.3.2_L15': [FAIL],
+  'intl402/ch10/10.3/10.3.3_L15': [FAIL],
+  'intl402/ch11/11.1/11.1_L15': [FAIL],
+  'intl402/ch11/11.2/11.2.2_L15': [FAIL],
+  'intl402/ch11/11.3/11.3.2_1_a_L15': [FAIL],
+  'intl402/ch11/11.3/11.3.2_L15': [FAIL],
+  'intl402/ch11/11.3/11.3.3_L15': [FAIL],
+  'intl402/ch12/12.1/12.1_L15': [FAIL],
+  'intl402/ch12/12.2/12.2.2_L15': [FAIL],
+  'intl402/ch12/12.3/12.3.2_1_a_L15': [FAIL],
+  'intl402/ch12/12.3/12.3.2_L15': [FAIL],
+  'intl402/ch12/12.3/12.3.3_L15': [FAIL],
+  'intl402/ch13/13.1/13.1.1_L15': [FAIL],
+  'intl402/ch13/13.2/13.2.1_L15': [FAIL],
+  'intl402/ch13/13.3/13.3.1_L15': [FAIL],
+  'intl402/ch13/13.3/13.3.2_L15': [FAIL],
+  'intl402/ch13/13.3/13.3.3_L15': [FAIL],
 
   ############################ SKIPPED TESTS #############################
 
   # These tests take a looong time to run in debug mode.
-  'S15.1.3.1_A2.5_T1': [PASS, ['mode == debug', SKIP]],
-  'S15.1.3.2_A2.5_T1': [PASS, ['mode == debug', SKIP]],
+  'ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A2.5_T1': [PASS, ['mode == debug', SKIP]],
+  'ch15/15.1/15.1.3/15.1.3.2/S15.1.3.2_A2.5_T1': [PASS, ['mode == debug', SKIP]],
 }],  # ALWAYS
 
 ['system == macos', {
-  '11.3.2_TRP': [FAIL],
-  '9.2.5_11_g_ii_2': [FAIL],
+  'intl402/ch11/11.3/11.3.2_TRP': [FAIL],
+  'intl402/ch09/9.2/9.2.5_11_g_ii_2': [FAIL],
 }],  # system == macos
 
 ['arch == arm or arch == mipsel or arch == mips or arch == arm64 or arch == mips64el', {
 
   # TODO(mstarzinger): Causes stack overflow on simulators due to eager
   # compilation of parenthesized function literals. Needs investigation.
-  'S13.2.1_A1_T1': [SKIP],
+  'ch13/13.2/S13.2.1_A1_T1': [SKIP],
 
   # BUG(3251225): Tests that timeout with --nocrankshaft.
-  'S15.1.3.1_A2.4_T1': [SKIP],
-  'S15.1.3.1_A2.5_T1': [SKIP],
-  'S15.1.3.2_A2.4_T1': [SKIP],
-  'S15.1.3.2_A2.5_T1': [SKIP],
-  'S15.1.3.3_A2.3_T1': [SKIP],
-  'S15.1.3.4_A2.3_T1': [SKIP],
+  'ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A2.4_T1': [SKIP],
+  'ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A2.5_T1': [SKIP],
+  'ch15/15.1/15.1.3/15.1.3.2/S15.1.3.2_A2.4_T1': [SKIP],
+  'ch15/15.1/15.1.3/15.1.3.2/S15.1.3.2_A2.5_T1': [SKIP],
+  'ch15/15.1/15.1.3/15.1.3.3/S15.1.3.3_A2.3_T1': [SKIP],
+  'ch15/15.1/15.1.3/15.1.3.4/S15.1.3.4_A2.3_T1': [SKIP],
 }],  # 'arch == arm or arch == mipsel or arch == mips or arch == arm64'
 ]
index 0a89410..cb44da0 100644 (file)
@@ -57,9 +57,6 @@ class Test262TestSuite(testsuite.TestSuite):
     self.harness += [os.path.join(self.root, "harness-adapt.js")]
     self.ParseTestRecord = None
 
-  def CommonTestName(self, testcase):
-    return testcase.path.split(os.path.sep)[-1]
-
   def ListTests(self, context):
     tests = []
     for dirname, dirs, files in os.walk(self.testroot):
index d1800c5..8e7496b 100644 (file)
   '11.1.5_4-4-d-3': [FAIL],
   '11.1.5_4-4-d-4': [FAIL],
 
+  # Function length properties are configurable in ES6
+  '10.1_L15': [FAIL],
+  '10.2.2_L15': [FAIL],
+  '10.3.2_1_a_L15': [FAIL],
+  '10.3.2_L15': [FAIL],
+  '10.3.3_L15': [FAIL],
+  '11.1_L15': [FAIL],
+  '11.2.2_L15': [FAIL],
+  '11.3.2_1_a_L15': [FAIL],
+  '11.3.2_L15': [FAIL],
+  '11.3.3_L15': [FAIL],
+  '11.4.1-5-a-28-s': [FAIL],
+  '12.1_L15': [FAIL],
+  '12.2.2_L15': [FAIL],
+  '12.3.2_1_a_L15': [FAIL],
+  '12.3.2_L15': [FAIL],
+  '12.3.3_L15': [FAIL],
+  '13.1.1_L15': [FAIL],
+  '13.2-15-1': [FAIL],
+  '13.2.1_L15': [FAIL],
+  '13.3.1_L15': [FAIL],
+  '13.3.2_L15': [FAIL],
+  '13.3.3_L15': [FAIL],
+  '15.2.3.3-4-186': [FAIL],
+  '15.2.3.3-4-187': [FAIL],
+  '15.2.3.3-4-191': [FAIL],
+  '15.2.3.3-4-194': [FAIL],
+  '15.2.3.3-4-201': [FAIL],
+  '15.3.3.2-1': [FAIL],
+  'S15.1.2.1_A4.2': [FAIL],
+  'S15.1.2.2_A9.2': [FAIL],
+  'S15.1.2.3_A7.2': [FAIL],
+  'S15.1.2.4_A2.2': [FAIL],
+  'S15.1.2.5_A2.2': [FAIL],
+  'S15.1.3.1_A5.2': [FAIL],
+  'S15.1.3.2_A5.2': [FAIL],
+  'S15.1.3.3_A5.2': [FAIL],
+  'S15.1.3.4_A5.2': [FAIL],
+  'S15.10.6.2_A9': [FAIL],
+  'S15.10.6.3_A9': [FAIL],
+  'S15.10.6.4_A9': [FAIL],
+  'S15.2.4.2_A9': [FAIL],
+  'S15.2.4.3_A9': [FAIL],
+  'S15.2.4.4_A9': [FAIL],
+  'S15.2.4.5_A9': [FAIL],
+  'S15.2.4.6_A9': [FAIL],
+  'S15.2.4.7_A9': [FAIL],
+  'S15.3.4.2_A9': [FAIL],
+  'S15.3.4.3_A9': [FAIL],
+  'S15.3.4.4_A9': [FAIL],
+  'S15.3.5.1_A2_T1': [FAIL],
+  'S15.3.5.1_A2_T2': [FAIL],
+  'S15.3.5.1_A2_T3': [FAIL],
+  'S15.4.3_A2.2': [FAIL],
+  'S15.4.4.10_A5.2': [FAIL],
+  'S15.4.4.11_A7.2': [FAIL],
+  'S15.4.4.12_A5.2': [FAIL],
+  'S15.4.4.13_A5.2': [FAIL],
+  'S15.4.4.2_A4.2': [FAIL],
+  'S15.4.4.3_A4.2': [FAIL],
+  'S15.4.4.4_A4.2': [FAIL],
+  'S15.4.4.5_A6.2': [FAIL],
+  'S15.4.4.6_A5.2': [FAIL],
+  'S15.4.4.7_A6.2': [FAIL],
+  'S15.4.4.8_A5.2': [FAIL],
+  'S15.4.4.9_A5.2': [FAIL],
+  'S15.5.4.10_A9': [FAIL],
+  'S15.5.4.11_A9': [FAIL],
+  'S15.5.4.12_A9': [FAIL],
+  'S15.5.4.13_A9': [FAIL],
+  'S15.5.4.14_A9': [FAIL],
+  'S15.5.4.15_A9': [FAIL],
+  'S15.5.4.16_A9': [FAIL],
+  'S15.5.4.17_A9': [FAIL],
+  'S15.5.4.18_A9': [FAIL],
+  'S15.5.4.19_A9': [FAIL],
+  'S15.5.4.4_A9': [FAIL],
+  'S15.5.4.5_A9': [FAIL],
+  'S15.5.4.6_A9': [FAIL],
+  'S15.5.4.7_A9': [FAIL],
+  'S15.5.4.8_A9': [FAIL],
+  'S15.5.4.9_A9': [FAIL],
+  'S15.9.4.2_A3_T2': [FAIL],
+  'S15.9.4.3_A3_T2': [FAIL],
+  'S15.9.5.10_A3_T2': [FAIL],
+  'S15.9.5.11_A3_T2': [FAIL],
+  'S15.9.5.12_A3_T2': [FAIL],
+  'S15.9.5.13_A3_T2': [FAIL],
+  'S15.9.5.14_A3_T2': [FAIL],
+  'S15.9.5.15_A3_T2': [FAIL],
+  'S15.9.5.16_A3_T2': [FAIL],
+  'S15.9.5.17_A3_T2': [FAIL],
+  'S15.9.5.18_A3_T2': [FAIL],
+  'S15.9.5.19_A3_T2': [FAIL],
+  'S15.9.5.1_A3_T2': [FAIL],
+  'S15.9.5.20_A3_T2': [FAIL],
+  'S15.9.5.21_A3_T2': [FAIL],
+  'S15.9.5.22_A3_T2': [FAIL],
+  'S15.9.5.23_A3_T2': [FAIL],
+  'S15.9.5.24_A3_T2': [FAIL],
+  'S15.9.5.25_A3_T2': [FAIL],
+  'S15.9.5.26_A3_T2': [FAIL],
+  'S15.9.5.27_A3_T2': [FAIL],
+  'S15.9.5.28_A3_T2': [FAIL],
+  'S15.9.5.29_A3_T2': [FAIL],
+  'S15.9.5.2_A3_T2': [FAIL],
+  'S15.9.5.30_A3_T2': [FAIL],
+  'S15.9.5.31_A3_T2': [FAIL],
+  'S15.9.5.32_A3_T2': [FAIL],
+  'S15.9.5.33_A3_T2': [FAIL],
+  'S15.9.5.34_A3_T2': [FAIL],
+  'S15.9.5.35_A3_T2': [FAIL],
+  'S15.9.5.36_A3_T2': [FAIL],
+  'S15.9.5.37_A3_T2': [FAIL],
+  'S15.9.5.38_A3_T2': [FAIL],
+  'S15.9.5.39_A3_T2': [FAIL],
+  'S15.9.5.3_A3_T2': [FAIL],
+  'S15.9.5.40_A3_T2': [FAIL],
+  'S15.9.5.41_A3_T2': [FAIL],
+  'S15.9.5.42_A3_T2': [FAIL],
+  'S15.9.5.4_A3_T2': [FAIL],
+  'S15.9.5.5_A3_T2': [FAIL],
+  'S15.9.5.6_A3_T2': [FAIL],
+  'S15.9.5.7_A3_T2': [FAIL],
+  'S15.9.5.8_A3_T2': [FAIL],
+  'S15.9.5.9_A3_T2': [FAIL],
+
   ######################## NEEDS INVESTIGATION ###########################
 
   # These test failures are specific to the intl402 suite and need investigation
index 1fa0b10..85e5248 100644 (file)
@@ -2426,6 +2426,21 @@ TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrWithImmediateForARMv7) {
   }
 }
 
+
+TEST_F(InstructionSelectorTest, Word32Clz) {
+  StreamBuilder m(this, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Word32Clz(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmClz, 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()));
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 571dbec..02c8d2e 100644 (file)
@@ -472,6 +472,36 @@ TEST_P(InstructionSelectorAddSubTest, ShiftByImmediateOnRight) {
 }
 
 
+TEST_P(InstructionSelectorAddSubTest, ExtendByte) {
+  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.Word32And(m.Parameter(1), m.Int32Constant(0xff))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorAddSubTest, ExtendHalfword) {
+  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.Word32And(m.Parameter(1), m.Int32Constant(0xffff))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+}
+
+
 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest,
                         ::testing::ValuesIn(kAddSubInstructions));
 
@@ -616,6 +646,58 @@ TEST_F(InstructionSelectorTest, AddShiftByImmediateOnLeft) {
 }
 
 
+TEST_F(InstructionSelectorTest, AddExtendByteOnLeft) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xff)),
+                        m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt32, kMachInt64);
+    m.Return(m.Int64Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xff)),
+                        m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, AddExtendHalfwordOnLeft) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xffff)),
+                        m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt32, kMachInt64);
+    m.Return(m.Int64Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xffff)),
+                        m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
 // -----------------------------------------------------------------------------
 // Data processing controlled branches.
 
@@ -896,26 +978,6 @@ TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnRight) {
     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)));
-  }
 }
 
 
@@ -937,26 +999,6 @@ TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnLeft) {
     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)));
-  }
 }
 
 
@@ -2200,6 +2242,21 @@ TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) {
   }
 }
 
+
+TEST_F(InstructionSelectorTest, Word32Clz) {
+  StreamBuilder m(this, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Word32Clz(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArm64Clz32, 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()));
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 5b31f5e..5cfb8fd 100644 (file)
@@ -23,45 +23,15 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
-class ChangeLoweringTest : public GraphTest {
+class ChangeLoweringTest : public TypedGraphTest {
  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();
-  }
+  bool Is64() const { return WordRepresentation() == kRepWord64; }
 
   Reduction Reduce(Node* node) {
     MachineOperatorBuilder machine(zone(), WordRepresentation());
@@ -80,15 +50,33 @@ class ChangeLoweringTest : public GraphTest {
                   IsNumberConstant(BitEq(0.0)), effect_matcher,
                   control_matcher);
   }
+  Matcher<Node*> IsChangeInt32ToSmi(const Matcher<Node*>& value_matcher) {
+    return Is64() ? IsWord64Shl(IsChangeInt32ToInt64(value_matcher),
+                                IsSmiShiftBitsConstant())
+                  : IsWord32Shl(value_matcher, IsSmiShiftBitsConstant());
+  }
+  Matcher<Node*> IsChangeSmiToInt32(const Matcher<Node*>& value_matcher) {
+    return Is64() ? IsTruncateInt64ToInt32(
+                        IsWord64Sar(value_matcher, IsSmiShiftBitsConstant()))
+                  : IsWord32Sar(value_matcher, IsSmiShiftBitsConstant());
+  }
+  Matcher<Node*> IsChangeUint32ToSmi(const Matcher<Node*>& value_matcher) {
+    return Is64() ? IsWord64Shl(IsChangeUint32ToUint64(value_matcher),
+                                IsSmiShiftBitsConstant())
+                  : IsWord32Shl(value_matcher, IsSmiShiftBitsConstant());
+  }
   Matcher<Node*> IsLoadHeapNumber(const Matcher<Node*>& value_matcher,
                                   const Matcher<Node*>& control_matcher) {
     return IsLoad(kMachFloat64, value_matcher,
-                  IsIntPtrConstant(HeapNumberValueOffset()), graph()->start(),
-                  control_matcher);
+                  IsIntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag),
+                  graph()->start(), control_matcher);
   }
   Matcher<Node*> IsIntPtrConstant(int value) {
     return Is32() ? IsInt32Constant(value) : IsInt64Constant(value);
   }
+  Matcher<Node*> IsSmiShiftBitsConstant() {
+    return IsIntPtrConstant(kSmiShiftSize + kSmiTagSize);
+  }
   Matcher<Node*> IsWordEqual(const Matcher<Node*>& lhs_matcher,
                              const Matcher<Node*>& rhs_matcher) {
     return Is32() ? IsWord32Equal(lhs_matcher, rhs_matcher)
@@ -115,51 +103,95 @@ class ChangeLoweringCommonTest
 
 
 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()));
+  Node* value = Parameter(Type::Boolean());
+  Reduction r =
+      Reduce(graph()->NewNode(simplified()->ChangeBitToBool(), value));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsSelect(kMachAnyTagged, value, 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()));
+  Node* value = Parameter(Type::Number());
+  Reduction r =
+      Reduce(graph()->NewNode(simplified()->ChangeBoolToBit(), value));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsWordEqual(value, 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();
+  Node* value = Parameter(Type::Number());
+  Reduction r =
+      Reduce(graph()->NewNode(simplified()->ChangeFloat64ToTagged(), value));
+  ASSERT_TRUE(r.Changed());
   Capture<Node*> heap_number;
   EXPECT_THAT(
-      finish,
+      r.replacement(),
       IsFinish(
           AllOf(CaptureEq(&heap_number),
-                IsAllocateHeapNumber(IsValueEffect(val), graph()->start())),
+                IsAllocateHeapNumber(IsValueEffect(value), graph()->start())),
           IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
                   CaptureEq(&heap_number),
-                  IsIntPtrConstant(HeapNumberValueOffset()), val,
-                  CaptureEq(&heap_number), graph()->start())));
+                  IsIntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag),
+                  value, CaptureEq(&heap_number), graph()->start())));
+}
+
+
+TARGET_TEST_P(ChangeLoweringCommonTest, ChangeInt32ToTaggedWithSignedSmall) {
+  Node* value = Parameter(Type::SignedSmall());
+  Reduction r =
+      Reduce(graph()->NewNode(simplified()->ChangeInt32ToTagged(), value));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsChangeInt32ToSmi(value));
 }
 
 
-TARGET_TEST_P(ChangeLoweringCommonTest, StringAdd) {
-  Node* node =
-      graph()->NewNode(simplified()->StringAdd(), Parameter(0), Parameter(1));
-  Reduction reduction = Reduce(node);
-  EXPECT_FALSE(reduction.Changed());
+TARGET_TEST_P(ChangeLoweringCommonTest, ChangeUint32ToTaggedWithUnsignedSmall) {
+  Node* value = Parameter(Type::UnsignedSmall());
+  Reduction r =
+      Reduce(graph()->NewNode(simplified()->ChangeUint32ToTagged(), value));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsChangeUint32ToSmi(value));
+}
+
+
+TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToInt32WithTaggedSigned) {
+  Node* value = Parameter(Type::TaggedSigned());
+  Reduction r =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(), value));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsChangeSmiToInt32(value));
+}
+
+
+TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToInt32WithTaggedPointer) {
+  Node* value = Parameter(Type::TaggedPointer());
+  Reduction r =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(), value));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsChangeFloat64ToInt32(
+                                   IsLoadHeapNumber(value, graph()->start())));
+}
+
+
+TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToUint32WithTaggedSigned) {
+  Node* value = Parameter(Type::TaggedSigned());
+  Reduction r =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(), value));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsChangeSmiToInt32(value));
+}
+
+
+TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToUint32WithTaggedPointer) {
+  Node* value = Parameter(Type::TaggedPointer());
+  Reduction r =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(), value));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsChangeFloat64ToUint32(
+                                   IsLoadHeapNumber(value, graph()->start())));
 }
 
 
@@ -179,26 +211,24 @@ class ChangeLowering32Test : public ChangeLoweringTest {
 
 
 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();
+  Node* value = Parameter(Type::Integral32());
+  Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), value);
+  Reduction r = Reduce(node);
+  ASSERT_TRUE(r.Changed());
   Capture<Node*> add, branch, heap_number, if_true;
   EXPECT_THAT(
-      phi,
+      r.replacement(),
       IsPhi(kMachAnyTagged,
             IsFinish(AllOf(CaptureEq(&heap_number),
                            IsAllocateHeapNumber(_, CaptureEq(&if_true))),
                      IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
                              CaptureEq(&heap_number),
-                             IsIntPtrConstant(HeapNumberValueOffset()),
-                             IsChangeInt32ToFloat64(val),
+                             IsIntPtrConstant(HeapNumber::kValueOffset -
+                                              kHeapObjectTag),
+                             IsChangeInt32ToFloat64(value),
                              CaptureEq(&heap_number), CaptureEq(&if_true))),
-            IsProjection(
-                0, AllOf(CaptureEq(&add), IsInt32AddWithOverflow(val, val))),
+            IsProjection(0, AllOf(CaptureEq(&add),
+                                  IsInt32AddWithOverflow(value, value))),
             IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
                     IsIfFalse(AllOf(CaptureEq(&branch),
                                     IsBranch(IsProjection(1, CaptureEq(&add)),
@@ -206,43 +236,27 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) {
 }
 
 
-TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTaggedSmall) {
-  Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
-  NodeProperties::SetBounds(val, Bounds(Type::None(), Type::Signed31()));
-  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();
+  Node* value = Parameter(Type::Number());
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), value);
+  Reduction r = Reduce(node);
+  ASSERT_TRUE(r.Changed());
   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)))));
+      r.replacement(),
+      IsPhi(kMachFloat64, IsLoadHeapNumber(value, CaptureEq(&if_true)),
+            IsChangeInt32ToFloat64(IsWord32Sar(
+                value, IsInt32Constant(kSmiTagSize + kSmiShiftSize))),
+            IsMerge(AllOf(CaptureEq(&if_true),
+                          IsIfTrue(AllOf(
+                              CaptureEq(&branch),
+                              IsBranch(IsWord32And(
+                                           value, IsInt32Constant(kSmiTagMask)),
+                                       graph()->start())))),
+                    IsIfFalse(CaptureEq(&branch)))));
 }
 
 
@@ -250,23 +264,22 @@ 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();
+  Node* value = Parameter(Type::Signed32());
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), value);
+  Reduction r = Reduce(node);
+  ASSERT_TRUE(r.Changed());
   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()))))));
+      r.replacement(),
+      IsPhi(
+          kMachInt32,
+          IsChangeFloat64ToInt32(IsLoadHeapNumber(value, CaptureEq(&if_true))),
+          IsWord32Sar(value, IsInt32Constant(kSmiTagSize + kSmiShiftSize)),
+          IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                  IsIfFalse(AllOf(
+                      CaptureEq(&branch),
+                      IsBranch(IsWord32And(value, IsInt32Constant(kSmiTagMask)),
+                               graph()->start()))))));
 }
 
 
@@ -274,23 +287,22 @@ 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();
+  Node* value = Parameter(Type::Unsigned32());
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), value);
+  Reduction r = Reduce(node);
+  ASSERT_TRUE(r.Changed());
   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()))))));
+      r.replacement(),
+      IsPhi(
+          kMachUint32,
+          IsChangeFloat64ToUint32(IsLoadHeapNumber(value, CaptureEq(&if_true))),
+          IsWord32Sar(value, IsInt32Constant(kSmiTagSize + kSmiShiftSize)),
+          IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                  IsIfFalse(AllOf(
+                      CaptureEq(&branch),
+                      IsBranch(IsWord32And(value, IsInt32Constant(kSmiTagMask)),
+                               graph()->start()))))));
 }
 
 
@@ -298,30 +310,30 @@ 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();
+  Node* value = Parameter(Type::Number());
+  Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), value);
+  Reduction r = Reduce(node);
+  ASSERT_TRUE(r.Changed());
   Capture<Node*> branch, heap_number, if_false;
   EXPECT_THAT(
-      phi,
+      r.replacement(),
       IsPhi(
-          kMachAnyTagged, IsWord32Shl(val, IsInt32Constant(SmiShiftAmount())),
+          kMachAnyTagged,
+          IsWord32Shl(value, IsInt32Constant(kSmiTagSize + kSmiShiftSize)),
           IsFinish(AllOf(CaptureEq(&heap_number),
                          IsAllocateHeapNumber(_, CaptureEq(&if_false))),
                    IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
                            CaptureEq(&heap_number),
-                           IsInt32Constant(HeapNumberValueOffset()),
-                           IsChangeUint32ToFloat64(val),
+                           IsInt32Constant(HeapNumber::kValueOffset -
+                                           kHeapObjectTag),
+                           IsChangeUint32ToFloat64(value),
                            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))))));
+          IsMerge(IsIfTrue(AllOf(
+                      CaptureEq(&branch),
+                      IsBranch(IsUint32LessThanOrEqual(
+                                   value, IsInt32Constant(Smi::kMaxValue)),
+                               graph()->start()))),
+                  AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
 }
 
 
@@ -337,14 +349,11 @@ class ChangeLowering64Test : public ChangeLoweringTest {
 
 
 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())));
+  Node* value = Parameter(Type::Signed32());
+  Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), value);
+  Reduction r = Reduce(node);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsChangeInt32ToSmi(value));
 }
 
 
@@ -352,26 +361,23 @@ 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();
+  Node* value = Parameter(Type::Number());
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), value);
+  Reduction r = Reduce(node);
+  ASSERT_TRUE(r.Changed());
   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)))));
+      r.replacement(),
+      IsPhi(kMachFloat64, IsLoadHeapNumber(value, CaptureEq(&if_true)),
+            IsChangeInt32ToFloat64(IsTruncateInt64ToInt32(IsWord64Sar(
+                value, IsInt64Constant(kSmiTagSize + kSmiShiftSize)))),
+            IsMerge(AllOf(CaptureEq(&if_true),
+                          IsIfTrue(AllOf(
+                              CaptureEq(&branch),
+                              IsBranch(IsWord64And(
+                                           value, IsInt64Constant(kSmiTagMask)),
+                                       graph()->start())))),
+                    IsIfFalse(CaptureEq(&branch)))));
 }
 
 
@@ -379,24 +385,23 @@ 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();
+  Node* value = Parameter(Type::Signed32());
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), value);
+  Reduction r = Reduce(node);
+  ASSERT_TRUE(r.Changed());
   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()))))));
+      r.replacement(),
+      IsPhi(
+          kMachInt32,
+          IsChangeFloat64ToInt32(IsLoadHeapNumber(value, CaptureEq(&if_true))),
+          IsTruncateInt64ToInt32(
+              IsWord64Sar(value, IsInt64Constant(kSmiTagSize + kSmiShiftSize))),
+          IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                  IsIfFalse(AllOf(
+                      CaptureEq(&branch),
+                      IsBranch(IsWord64And(value, IsInt64Constant(kSmiTagMask)),
+                               graph()->start()))))));
 }
 
 
@@ -404,24 +409,23 @@ 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();
+  Node* value = Parameter(Type::Unsigned32());
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), value);
+  Reduction r = Reduce(node);
+  ASSERT_TRUE(r.Changed());
   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()))))));
+      r.replacement(),
+      IsPhi(
+          kMachUint32,
+          IsChangeFloat64ToUint32(IsLoadHeapNumber(value, CaptureEq(&if_true))),
+          IsTruncateInt64ToInt32(
+              IsWord64Sar(value, IsInt64Constant(kSmiTagSize + kSmiShiftSize))),
+          IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                  IsIfFalse(AllOf(
+                      CaptureEq(&branch),
+                      IsBranch(IsWord64And(value, IsInt64Constant(kSmiTagMask)),
+                               graph()->start()))))));
 }
 
 
@@ -429,31 +433,31 @@ 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();
+  Node* value = Parameter(Type::Number());
+  Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), value);
+  Reduction r = Reduce(node);
+  ASSERT_TRUE(r.Changed());
   Capture<Node*> branch, heap_number, if_false;
   EXPECT_THAT(
-      phi,
+      r.replacement(),
       IsPhi(
-          kMachAnyTagged, IsWord64Shl(IsChangeUint32ToUint64(val),
-                                      IsInt64Constant(SmiShiftAmount())),
+          kMachAnyTagged,
+          IsWord64Shl(IsChangeUint32ToUint64(value),
+                      IsInt64Constant(kSmiTagSize + kSmiShiftSize)),
           IsFinish(AllOf(CaptureEq(&heap_number),
                          IsAllocateHeapNumber(_, CaptureEq(&if_false))),
                    IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
                            CaptureEq(&heap_number),
-                           IsInt64Constant(HeapNumberValueOffset()),
-                           IsChangeUint32ToFloat64(val),
+                           IsInt64Constant(HeapNumber::kValueOffset -
+                                           kHeapObjectTag),
+                           IsChangeUint32ToFloat64(value),
                            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))))));
+          IsMerge(IsIfTrue(AllOf(
+                      CaptureEq(&branch),
+                      IsBranch(IsUint32LessThanOrEqual(
+                                   value, IsInt32Constant(Smi::kMaxValue)),
+                               graph()->start()))),
+                  AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
 }
 
 }  // namespace compiler
index 1f6044b..3b60e5b 100644 (file)
@@ -4,9 +4,13 @@
 
 #include "src/compiler/common-operator.h"
 #include "src/compiler/common-operator-reducer.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/machine-operator.h"
 #include "src/compiler/machine-type.h"
 #include "src/compiler/operator.h"
 #include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
 
 namespace v8 {
 namespace internal {
@@ -15,14 +19,23 @@ namespace compiler {
 class CommonOperatorReducerTest : public GraphTest {
  public:
   explicit CommonOperatorReducerTest(int num_parameters = 1)
-      : GraphTest(num_parameters) {}
+      : GraphTest(num_parameters), machine_(zone()) {}
   ~CommonOperatorReducerTest() OVERRIDE {}
 
  protected:
-  Reduction Reduce(Node* node) {
-    CommonOperatorReducer reducer;
+  Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
+                                   MachineOperatorBuilder::kNoFlags) {
+    JSOperatorBuilder javascript(zone());
+    MachineOperatorBuilder machine(zone(), kMachPtr, flags);
+    JSGraph jsgraph(isolate(), graph(), common(), &javascript, &machine);
+    CommonOperatorReducer reducer(&jsgraph);
     return reducer.Reduce(node);
   }
+
+  MachineOperatorBuilder* machine() { return &machine_; }
+
+ private:
+  MachineOperatorBuilder machine_;
 };
 
 
@@ -78,9 +91,14 @@ TEST_F(CommonOperatorReducerTest, RedundantPhi) {
     int const value_input_count = input_count - 1;
     TRACED_FOREACH(MachineType, type, kMachineTypes) {
       for (int i = 0; i < value_input_count; ++i) {
+        inputs[i] = graph()->start();
+      }
+      Node* merge = graph()->NewNode(common()->Merge(value_input_count),
+                                     value_input_count, inputs);
+      for (int i = 0; i < value_input_count; ++i) {
         inputs[i] = input;
       }
-      inputs[value_input_count] = graph()->start();
+      inputs[value_input_count] = merge;
       Reduction r = Reduce(graph()->NewNode(
           common()->Phi(type, value_input_count), input_count, inputs));
       ASSERT_TRUE(r.Changed());
@@ -90,6 +108,27 @@ TEST_F(CommonOperatorReducerTest, RedundantPhi) {
 }
 
 
+TEST_F(CommonOperatorReducerTest, PhiToFloat64MaxOrFloat64Min) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Node* check = graph()->NewNode(machine()->Float64LessThan(), p0, p1);
+  Node* branch = graph()->NewNode(common()->Branch(), check, graph()->start());
+  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);
+  Reduction r1 =
+      Reduce(graph()->NewNode(common()->Phi(kMachFloat64, 2), p1, p0, merge),
+             MachineOperatorBuilder::kFloat64Max);
+  ASSERT_TRUE(r1.Changed());
+  EXPECT_THAT(r1.replacement(), IsFloat64Max(p1, p0));
+  Reduction r2 =
+      Reduce(graph()->NewNode(common()->Phi(kMachFloat64, 2), p0, p1, merge),
+             MachineOperatorBuilder::kFloat64Min);
+  ASSERT_TRUE(r2.Changed());
+  EXPECT_THAT(r2.replacement(), IsFloat64Min(p0, p1));
+}
+
+
 // -----------------------------------------------------------------------------
 // Select
 
@@ -106,6 +145,23 @@ TEST_F(CommonOperatorReducerTest, RedundantSelect) {
   }
 }
 
+
+TEST_F(CommonOperatorReducerTest, SelectToFloat64MaxOrFloat64Min) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Node* check = graph()->NewNode(machine()->Float64LessThan(), p0, p1);
+  Reduction r1 =
+      Reduce(graph()->NewNode(common()->Select(kMachFloat64), check, p1, p0),
+             MachineOperatorBuilder::kFloat64Max);
+  ASSERT_TRUE(r1.Changed());
+  EXPECT_THAT(r1.replacement(), IsFloat64Max(p1, p0));
+  Reduction r2 =
+      Reduce(graph()->NewNode(common()->Select(kMachFloat64), check, p0, p1),
+             MachineOperatorBuilder::kFloat64Min);
+  ASSERT_TRUE(r2.Changed());
+  EXPECT_THAT(r2.replacement(), IsFloat64Min(p0, p1));
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 6e60cfd..c0d25ea 100644 (file)
@@ -53,6 +53,8 @@ const SharedOperator kSharedOperators[] = {
     SHARED(End, Operator::kKontrol, 0, 0, 1, 0, 0, 0),
     SHARED(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1),
     SHARED(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1),
+    SHARED(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1),
+    SHARED(IfException, Operator::kKontrol, 0, 0, 1, 0, 0, 1),
     SHARED(Throw, Operator::kFoldable, 1, 1, 1, 0, 0, 1),
     SHARED(Return, Operator::kNoThrow, 1, 1, 1, 0, 0, 1)
 #undef SHARED
index 17716ab..515bd06 100644 (file)
@@ -17,7 +17,7 @@ namespace compiler {
   do {                                                    \
     Node* __n[] = {__VA_ARGS__};                          \
     ASSERT_TRUE(IsEquivalenceClass(arraysize(__n), __n)); \
-  } while (false);
+  } while (false)
 
 class ControlEquivalenceTest : public GraphTest {
  public:
index c083d4b..f300d07 100644 (file)
@@ -21,25 +21,32 @@ namespace compiler {
 class ControlFlowOptimizerTest : public GraphTest {
  public:
   explicit ControlFlowOptimizerTest(int num_parameters = 3)
-      : GraphTest(num_parameters), machine_(zone()) {}
+      : GraphTest(num_parameters),
+        machine_(zone()),
+        javascript_(zone()),
+        jsgraph_(isolate(), graph(), common(), javascript(), machine()) {}
   ~ControlFlowOptimizerTest() OVERRIDE {}
 
  protected:
   void Optimize() {
-    JSOperatorBuilder javascript(zone());
-    JSGraph jsgraph(isolate(), graph(), common(), &javascript, machine());
-    ControlFlowOptimizer optimizer(&jsgraph, zone());
+    ControlFlowOptimizer optimizer(jsgraph(), zone());
     optimizer.Optimize();
   }
 
+  Node* EmptyFrameState() { return jsgraph()->EmptyFrameState(); }
+
+  JSGraph* jsgraph() { return &jsgraph_; }
+  JSOperatorBuilder* javascript() { return &javascript_; }
   MachineOperatorBuilder* machine() { return &machine_; }
 
  private:
   MachineOperatorBuilder machine_;
+  JSOperatorBuilder javascript_;
+  JSGraph jsgraph_;
 };
 
 
-TEST_F(ControlFlowOptimizerTest, Switch) {
+TEST_F(ControlFlowOptimizerTest, BuildSwitch1) {
   Node* index = Parameter(0);
   Node* branch0 = graph()->NewNode(
       common()->Branch(),
@@ -65,6 +72,69 @@ TEST_F(ControlFlowOptimizerTest, Switch) {
                                               IsSwitch(index, start()))))));
 }
 
+
+TEST_F(ControlFlowOptimizerTest, BuildSwitch2) {
+  Node* input = Parameter(0);
+  Node* context = Parameter(1);
+  Node* index = FLAG_turbo_deoptimization
+                    ? graph()->NewNode(javascript()->ToNumber(), input, context,
+                                       EmptyFrameState(), start(), start())
+                    : graph()->NewNode(javascript()->ToNumber(), input, context,
+                                       start(), start());
+  Node* if_success = graph()->NewNode(common()->IfSuccess(), index);
+  Node* branch0 = graph()->NewNode(
+      common()->Branch(),
+      graph()->NewNode(machine()->Word32Equal(), index, Int32Constant(0)),
+      if_success);
+  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
+  Node* branch1 = graph()->NewNode(
+      common()->Branch(),
+      graph()->NewNode(machine()->Word32Equal(), index, Int32Constant(1)),
+      if_false0);
+  Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+  Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+  Node* merge =
+      graph()->NewNode(common()->Merge(3), if_true0, if_true1, if_false1);
+  graph()->SetEnd(graph()->NewNode(common()->End(), merge));
+  Optimize();
+  Capture<Node*> switch_capture;
+  EXPECT_THAT(
+      end(),
+      IsEnd(IsMerge(IsIfValue(0, CaptureEq(&switch_capture)),
+                    IsIfValue(1, CaptureEq(&switch_capture)),
+                    IsIfDefault(AllOf(CaptureEq(&switch_capture),
+                                      IsSwitch(index, IsIfSuccess(index)))))));
+}
+
+
+TEST_F(ControlFlowOptimizerTest, CloneBranch) {
+  Node* cond0 = Parameter(0);
+  Node* cond1 = Parameter(1);
+  Node* cond2 = Parameter(2);
+  Node* branch0 = graph()->NewNode(common()->Branch(), cond0, start());
+  Node* control1 = graph()->NewNode(common()->IfTrue(), branch0);
+  Node* control2 = graph()->NewNode(common()->IfFalse(), branch0);
+  Node* merge0 = graph()->NewNode(common()->Merge(2), control1, control2);
+  Node* phi0 =
+      graph()->NewNode(common()->Phi(kRepBit, 2), cond1, cond2, merge0);
+  Node* branch = graph()->NewNode(common()->Branch(), phi0, merge0);
+  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);
+  graph()->SetEnd(graph()->NewNode(common()->End(), merge));
+  Optimize();
+  Capture<Node*> branch1_capture, branch2_capture;
+  EXPECT_THAT(
+      end(),
+      IsEnd(IsMerge(IsMerge(IsIfTrue(CaptureEq(&branch1_capture)),
+                            IsIfTrue(CaptureEq(&branch2_capture))),
+                    IsMerge(IsIfFalse(AllOf(CaptureEq(&branch1_capture),
+                                            IsBranch(cond1, control1))),
+                            IsIfFalse(AllOf(CaptureEq(&branch2_capture),
+                                            IsBranch(cond2, control2)))))));
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index afa1e94..9138ab2 100644 (file)
@@ -11,9 +11,9 @@ 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};
+const int32_t kImmediates[] = {kMinInt, -42, -1,   0,      1,          2,
+                               3,       4,   5,    6,      7,          8,
+                               16,      42,  0xff, 0xffff, 0x0f0f0f0f, kMaxInt};
 
 }  // namespace
 
@@ -666,6 +666,44 @@ TEST_F(InstructionSelectorTest, Float64BinopArithmetic) {
   }
 }
 
+
+// -----------------------------------------------------------------------------
+// Miscellaneous.
+
+
+TEST_F(InstructionSelectorTest, Uint32LessThanWithLoadAndLoadStackPointer) {
+  StreamBuilder m(this, kMachBool);
+  Node* const sl = m.Load(
+      kMachPtr,
+      m.ExternalConstant(ExternalReference::address_of_stack_limit(isolate())));
+  Node* const sp = m.LoadStackPointer();
+  Node* const n = m.Uint32LessThan(sl, sp);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kIA32StackCheck, s[0]->arch_opcode());
+  ASSERT_EQ(0U, s[0]->InputCount());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kUnsignedGreaterThan, s[0]->flags_condition());
+}
+
+
+TEST_F(InstructionSelectorTest, Word32Clz) {
+  StreamBuilder m(this, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Word32Clz(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kIA32Lzcnt, 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()));
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index d3e00c6..e52580d 100644 (file)
@@ -4,7 +4,8 @@
 
 #include "test/unittests/compiler/instruction-selector-unittest.h"
 
-#include "src/compiler/graph-inl.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/schedule.h"
 #include "src/flags.h"
 #include "test/unittests/compiler/compiler-test-utils.h"
 
@@ -346,9 +347,13 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
   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));
+  ZoneVector<MachineType> int32_type(1, kMachInt32, zone());
+  ZoneVector<MachineType> empty_types(zone());
+
+  Node* parameters =
+      m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(1));
+  Node* locals = m.NewNode(m.common()->TypedStateValues(&empty_types));
+  Node* stack = m.NewNode(m.common()->TypedStateValues(&empty_types));
   Node* context_dummy = m.Int32Constant(0);
 
   Node* state_node = m.NewNode(
@@ -386,10 +391,17 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
   Node* receiver = m.Parameter(1);
   Node* context = m.Int32Constant(1);  // Context is ignored.
 
+  ZoneVector<MachineType> int32_type(1, kMachInt32, zone());
+  ZoneVector<MachineType> float64_type(1, kMachFloat64, zone());
+  ZoneVector<MachineType> tagged_type(1, kMachAnyTagged, zone());
+
   // 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* parameters =
+      m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(43));
+  Node* locals = m.NewNode(m.common()->TypedStateValues(&float64_type),
+                           m.Float64Constant(0.5));
+  Node* stack = m.NewNode(m.common()->TypedStateValues(&tagged_type),
+                          m.UndefinedConstant());
 
   Node* context_sentinel = m.Int32Constant(0);
   Node* frame_state_before = m.NewNode(
@@ -472,10 +484,17 @@ TARGET_TEST_F(InstructionSelectorTest,
   Node* receiver = m.Parameter(1);
   Node* context = m.Int32Constant(66);
 
+  ZoneVector<MachineType> int32_type(1, kMachInt32, zone());
+  ZoneVector<MachineType> int32x2_type(2, kMachInt32, zone());
+  ZoneVector<MachineType> float64_type(1, kMachFloat64, zone());
+
   // 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* parameters =
+      m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(63));
+  Node* locals =
+      m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(64));
+  Node* stack =
+      m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(65));
   Node* frame_state_parent =
       m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_parent,
                                        OutputFrameStateCombine::Ignore()),
@@ -483,11 +502,11 @@ TARGET_TEST_F(InstructionSelectorTest,
 
   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));
+      m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(43));
+  Node* locals2 = m.NewNode(m.common()->TypedStateValues(&float64_type),
+                            m.Float64Constant(0.25));
+  Node* stack2 = m.NewNode(m.common()->TypedStateValues(&int32x2_type),
+                           m.Int32Constant(44), m.Int32Constant(45));
   Node* frame_state_before =
       m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before,
                                        OutputFrameStateCombine::Push()),
index 001fb11..c2e626f 100644 (file)
@@ -40,7 +40,6 @@ InstructionSequenceTest::InstructionSequenceTest()
       num_general_registers_(kDefaultNRegs),
       num_double_registers_(kDefaultNRegs),
       instruction_blocks_(zone()),
-      current_instruction_index_(-1),
       current_block_(nullptr),
       block_returns_(false) {
   InitializeRegisterNames();
@@ -100,8 +99,8 @@ void InstructionSequenceTest::StartBlock() {
 }
 
 
-int InstructionSequenceTest::EndBlock(BlockCompletion completion) {
-  int instruction_index = kMinInt;
+Instruction* InstructionSequenceTest::EndBlock(BlockCompletion completion) {
+  Instruction* result = nullptr;
   if (block_returns_) {
     CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough);
     completion.type_ = kBlockEnd;
@@ -110,22 +109,22 @@ int InstructionSequenceTest::EndBlock(BlockCompletion completion) {
     case kBlockEnd:
       break;
     case kFallThrough:
-      instruction_index = EmitFallThrough();
+      result = EmitFallThrough();
       break;
     case kJump:
       CHECK(!block_returns_);
-      instruction_index = EmitJump();
+      result = EmitJump();
       break;
     case kBranch:
       CHECK(!block_returns_);
-      instruction_index = EmitBranch(completion.op_);
+      result = EmitBranch(completion.op_);
       break;
   }
   completions_.push_back(completion);
   CHECK(current_block_ != nullptr);
   sequence()->EndBlock(current_block_->rpo_number());
   current_block_ = nullptr;
-  return instruction_index;
+  return result;
 }
 
 
@@ -139,15 +138,15 @@ InstructionSequenceTest::VReg InstructionSequenceTest::Define(
     TestOperand output_op) {
   VReg vreg = NewReg();
   InstructionOperand outputs[1]{ConvertOutputOp(vreg, output_op)};
-  Emit(vreg.value_, kArchNop, 1, outputs);
+  Emit(kArchNop, 1, outputs);
   return vreg;
 }
 
 
-int InstructionSequenceTest::Return(TestOperand input_op_0) {
+Instruction* InstructionSequenceTest::Return(TestOperand input_op_0) {
   block_returns_ = true;
   InstructionOperand inputs[1]{ConvertInputOp(input_op_0)};
-  return Emit(NewIndex(), kArchRet, 0, nullptr, 1, inputs);
+  return Emit(kArchRet, 0, nullptr, 1, inputs);
 }
 
 
@@ -192,12 +191,12 @@ InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant(
   VReg vreg = NewReg();
   sequence()->AddConstant(vreg.value_, Constant(imm));
   InstructionOperand outputs[1]{ConstantOperand(vreg.value_)};
-  Emit(vreg.value_, kArchNop, 1, outputs);
+  Emit(kArchNop, 1, outputs);
   return vreg;
 }
 
 
-int InstructionSequenceTest::EmitNop() { return Emit(NewIndex(), kArchNop); }
+Instruction* InstructionSequenceTest::EmitNop() { return Emit(kArchNop); }
 
 
 static size_t CountInputs(size_t size,
@@ -210,16 +209,17 @@ static size_t CountInputs(size_t size,
 }
 
 
-int InstructionSequenceTest::EmitI(size_t input_size, TestOperand* inputs) {
+Instruction* 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);
+  return Emit(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) {
+Instruction* 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);
 }
@@ -230,7 +230,7 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
   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);
+  Emit(kArchNop, 1, outputs, input_size, mapped_inputs);
   return output_vreg;
 }
 
@@ -243,14 +243,36 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
 }
 
 
+InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI(
+    TestOperand output_op_0, TestOperand output_op_1, size_t input_size,
+    TestOperand* inputs) {
+  VRegPair output_vregs = std::make_pair(NewReg(), NewReg());
+  InstructionOperand outputs[2]{
+      ConvertOutputOp(output_vregs.first, output_op_0),
+      ConvertOutputOp(output_vregs.second, output_op_1)};
+  InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
+  Emit(kArchNop, 2, outputs, input_size, mapped_inputs);
+  return output_vregs;
+}
+
+
+InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI(
+    TestOperand output_op_0, TestOperand output_op_1, 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 EmitOOI(output_op_0, output_op_1,
+                 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);
+  Emit(kArchCallCodeObject, 1, outputs, input_size, mapped_inputs, 0, nullptr,
+       true);
   return output_vreg;
 }
 
@@ -263,36 +285,26 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
 }
 
 
-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) {
+Instruction* 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);
+  auto instruction = NewInstruction(opcode, 0, nullptr, 4, inputs);
+  return AddInstruction(instruction);
 }
 
 
-int InstructionSequenceTest::EmitFallThrough() {
-  auto instruction = NewInstruction(kArchNop, 0, nullptr)->MarkAsControl();
-  return AddInstruction(NewIndex(), instruction);
+Instruction* InstructionSequenceTest::EmitFallThrough() {
+  auto instruction = NewInstruction(kArchNop, 0, nullptr);
+  return AddInstruction(instruction);
 }
 
 
-int InstructionSequenceTest::EmitJump() {
+Instruction* InstructionSequenceTest::EmitJump() {
   InstructionOperand inputs[1]{ConvertInputOp(Imm())};
-  auto instruction =
-      NewInstruction(kArchJmp, 0, nullptr, 1, inputs)->MarkAsControl();
-  return AddInstruction(NewIndex(), instruction);
+  auto instruction = NewInstruction(kArchJmp, 0, nullptr, 1, inputs);
+  return AddInstruction(instruction);
 }
 
 
@@ -359,6 +371,9 @@ InstructionOperand InstructionSequenceTest::ConvertInputOp(TestOperand op) {
     case kRegister:
       return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER,
                          UnallocatedOperand::USED_AT_START);
+    case kSlot:
+      return Unallocated(op, UnallocatedOperand::MUST_HAVE_SLOT,
+                         UnallocatedOperand::USED_AT_START);
     case kFixedRegister:
       CHECK(0 <= op.value_ && op.value_ < num_general_registers_);
       return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_);
@@ -396,15 +411,14 @@ InstructionOperand InstructionSequenceTest::ConvertOutputOp(VReg vreg,
 
 InstructionBlock* InstructionSequenceTest::NewBlock() {
   CHECK(current_block_ == nullptr);
-  auto block_id = BasicBlock::Id::FromSize(instruction_blocks_.size());
-  Rpo rpo = Rpo::FromInt(block_id.ToInt());
+  Rpo rpo = Rpo::FromInt(static_cast<int>(instruction_blocks_.size()));
   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_end = Rpo::FromInt(rpo.ToInt() + loop_data.expected_blocks_);
       loop_data.expected_blocks_--;
       loop_data.loop_header_ = rpo;
     } else {
@@ -416,8 +430,8 @@ InstructionBlock* InstructionSequenceTest::NewBlock() {
     }
   }
   // Construct instruction block.
-  auto instruction_block = new (zone())
-      InstructionBlock(zone(), block_id, rpo, loop_header, loop_end, false);
+  auto instruction_block =
+      new (zone()) InstructionBlock(zone(), rpo, loop_header, loop_end, false);
   instruction_blocks_.push_back(instruction_block);
   current_block_ = instruction_block;
   sequence()->StartBlock(rpo);
@@ -458,23 +472,20 @@ void InstructionSequenceTest::WireBlock(size_t block_offset, int jump_offset) {
 }
 
 
-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) {
+Instruction* InstructionSequenceTest::Emit(
+    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);
+  return AddInstruction(instruction);
 }
 
 
-int InstructionSequenceTest::AddInstruction(int instruction_index,
-                                            Instruction* instruction) {
+Instruction* InstructionSequenceTest::AddInstruction(Instruction* instruction) {
   sequence()->AddInstruction(instruction);
-  return instruction_index;
+  return instruction;
 }
 
 }  // namespace compiler
index 613e258..2d75da7 100644 (file)
@@ -18,7 +18,7 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
   static const int kDefaultNRegs = 4;
   static const int kNoValue = kMinInt;
 
-  typedef BasicBlock::RpoNumber Rpo;
+  typedef RpoNumber Rpo;
 
   struct VReg {
     VReg() : value_(kNoValue) {}
@@ -27,6 +27,8 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
     int value_;
   };
 
+  typedef std::pair<VReg, VReg> VRegPair;
+
   enum TestOperandType {
     kInvalid,
     kSameAsFirst,
@@ -125,14 +127,14 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
   void StartLoop(int loop_blocks);
   void EndLoop();
   void StartBlock();
-  int EndBlock(BlockCompletion completion = FallThrough());
+  Instruction* 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)); }
+  Instruction* Return(TestOperand input_op_0);
+  Instruction* Return(VReg vreg) { return Return(Reg(vreg, 0)); }
 
   PhiInstruction* Phi(VReg incoming_vreg_0 = VReg(),
                       VReg incoming_vreg_1 = VReg(),
@@ -142,27 +144,30 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
   void SetInput(PhiInstruction* phi, size_t input, 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());
+  Instruction* EmitNop();
+  Instruction* EmitI(size_t input_size, TestOperand* inputs);
+  Instruction* 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());
+  VRegPair EmitOOI(TestOperand output_op_0, TestOperand output_op_1,
+                   size_t input_size, TestOperand* inputs);
+  VRegPair EmitOOI(TestOperand output_op_0, TestOperand output_op_1,
+                   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_; }
@@ -172,13 +177,12 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
 
  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* EmitBranch(TestOperand input_op);
+  Instruction* EmitFallThrough();
+  Instruction* EmitJump();
   Instruction* NewInstruction(InstructionCode code, size_t outputs_size,
                               InstructionOperand* outputs,
                               size_t inputs_size = 0,
@@ -202,12 +206,13 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
   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);
+  Instruction* Emit(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);
+  Instruction* AddInstruction(Instruction* instruction);
 
   struct LoopData {
     Rpo loop_header_;
@@ -226,7 +231,6 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
   // Block building state.
   InstructionBlocks instruction_blocks_;
   Instructions instructions_;
-  int current_instruction_index_;
   Completions completions_;
   LoopBlocks loop_blocks_;
   InstructionBlock* current_block_;
index b5c688e..5c508a5 100644 (file)
@@ -62,58 +62,6 @@ Type* const kNumberTypes[] = {
 
 
 // -----------------------------------------------------------------------------
-// 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
 
 
@@ -223,79 +171,6 @@ TEST_F(JSBuiltinReducerTest, MathFround) {
   }
 }
 
-
-// -----------------------------------------------------------------------------
-// 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
index 20d5c06..8adbc54 100644 (file)
@@ -27,8 +27,9 @@ class JSIntrinsicLoweringTest : public GraphTest {
   ~JSIntrinsicLoweringTest() OVERRIDE {}
 
  protected:
-  Reduction Reduce(Node* node) {
-    MachineOperatorBuilder machine(zone());
+  Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
+                                   MachineOperatorBuilder::kNoFlags) {
+    MachineOperatorBuilder machine(zone(), kMachPtr, flags);
     JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine);
     JSIntrinsicLowering reducer(&jsgraph);
     return reducer.Reduce(node);
@@ -42,6 +43,61 @@ class JSIntrinsicLoweringTest : public GraphTest {
 
 
 // -----------------------------------------------------------------------------
+// %_ConstructDouble
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineOptimizedConstructDouble) {
+  Node* const input0 = Parameter(0);
+  Node* const input1 = Parameter(1);
+  Node* const context = Parameter(2);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(graph()->NewNode(
+      javascript()->CallRuntime(Runtime::kInlineConstructDouble, 2), input0,
+      input1, context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat64InsertHighWord32(
+                                   IsFloat64InsertLowWord32(
+                                       IsNumberConstant(BitEq(0.0)), input1),
+                                   input0));
+}
+
+
+// -----------------------------------------------------------------------------
+// %_DoubleLo
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleLo) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(
+      graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleLo, 1),
+                       input, context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat64ExtractLowWord32(input));
+}
+
+
+// -----------------------------------------------------------------------------
+// %_DoubleHi
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleHi) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(
+      graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleHi, 1),
+                       input, context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat64ExtractHighWord32(input));
+}
+
+
+// -----------------------------------------------------------------------------
 // %_IsSmi
 
 
@@ -169,6 +225,94 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsRegExp) {
 
 
 // -----------------------------------------------------------------------------
+// %_JSValueGetValue
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineJSValueGetValue) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(graph()->NewNode(
+      javascript()->CallRuntime(Runtime::kInlineJSValueGetValue, 1), input,
+      context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(),
+              IsLoadField(AccessBuilder::ForValue(), input, effect, control));
+}
+
+
+// -----------------------------------------------------------------------------
+// %_MathFloor
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineMathFloor) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(
+      graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathFloor, 1),
+                       input, context, effect, control),
+      MachineOperatorBuilder::kFloat64RoundDown);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat64RoundDown(input));
+}
+
+
+// -----------------------------------------------------------------------------
+// %_MathSqrt
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineMathSqrt) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(
+      graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathSqrt, 1),
+                       input, context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat64Sqrt(input));
+}
+
+
+// -----------------------------------------------------------------------------
+// %_StringGetLength
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineStringGetLength) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(graph()->NewNode(
+      javascript()->CallRuntime(Runtime::kInlineStringGetLength, 1), input,
+      context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsLoadField(AccessBuilder::ForStringLength(),
+                                           input, effect, control));
+}
+
+
+// -----------------------------------------------------------------------------
+// %_MathClz32
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineMathClz32) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(
+      graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathClz32, 1),
+                       input, context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsWord32Clz(input));
+}
+
+
+// -----------------------------------------------------------------------------
 // %_ValueOf
 
 
index 8f4622a..7ecaed0 100644 (file)
@@ -28,6 +28,7 @@ struct SharedOperator {
   int control_input_count;
   int value_output_count;
   int effect_output_count;
+  int control_output_count;
 };
 
 
@@ -39,48 +40,48 @@ std::ostream& operator<<(std::ostream& os, const SharedOperator& sop) {
 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)                                          \
+               effect_output_count, control_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         \
+        control_input_count, value_output_count, effect_output_count,        \
+        control_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, 1, 1, 1, 1, 1),
-    SHARED(ToString, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
-    SHARED(ToName, Operator::kNoProperties, 1, 1, 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, 1, 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)
+    SHARED(Equal, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
+    SHARED(NotEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
+    SHARED(StrictEqual, Operator::kPure, 2, 0, 0, 0, 1, 0, 0),
+    SHARED(StrictNotEqual, Operator::kPure, 2, 0, 0, 0, 1, 0, 0),
+    SHARED(LessThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
+    SHARED(GreaterThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
+    SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
+    SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
+    SHARED(BitwiseOr, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
+    SHARED(BitwiseXor, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
+    SHARED(BitwiseAnd, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
+    SHARED(ShiftLeft, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
+    SHARED(ShiftRight, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
+    SHARED(ShiftRightLogical, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
+    SHARED(Add, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
+    SHARED(Subtract, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
+    SHARED(Multiply, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
+    SHARED(Divide, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
+    SHARED(Modulus, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
+    SHARED(UnaryNot, Operator::kPure, 1, 0, 0, 0, 1, 0, 0),
+    SHARED(ToBoolean, Operator::kPure, 1, 0, 0, 0, 1, 0, 0),
+    SHARED(ToNumber, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2),
+    SHARED(ToString, Operator::kNoProperties, 1, 0, 1, 1, 1, 1, 2),
+    SHARED(ToName, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2),
+    SHARED(ToObject, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2),
+    SHARED(Yield, Operator::kNoProperties, 1, 0, 1, 1, 1, 1, 2),
+    SHARED(Create, Operator::kEliminatable, 0, 0, 1, 0, 1, 1, 0),
+    SHARED(HasProperty, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
+    SHARED(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0, 0),
+    SHARED(InstanceOf, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
+    SHARED(CreateFunctionContext, Operator::kNoProperties, 1, 0, 1, 1, 1, 1, 2),
+    SHARED(CreateWithContext, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
+    SHARED(CreateBlockContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1, 2),
+    SHARED(CreateModuleContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1, 2),
+    SHARED(CreateScriptContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1, 2)
 #undef SHARED
 };
 
@@ -122,7 +123,7 @@ TEST_P(JSSharedOperatorTest, NumberOfInputsAndOutputs) {
 
   EXPECT_EQ(sop.value_output_count, op->ValueOutputCount());
   EXPECT_EQ(sop.effect_output_count, op->EffectOutputCount());
-  EXPECT_EQ(0, op->ControlOutputCount());
+  EXPECT_EQ(sop.control_output_count, op->ControlOutputCount());
 }
 
 
@@ -169,7 +170,7 @@ TEST_P(JSStorePropertyOperatorTest, NumberOfInputsAndOutputs) {
   const Operator* op = javascript.StoreProperty(mode);
 
   // TODO(jarin): Get rid of this hack.
-  const int frame_state_input_count = FLAG_turbo_deoptimization ? 1 : 0;
+  const int frame_state_input_count = FLAG_turbo_deoptimization ? 2 : 0;
   EXPECT_EQ(3, op->ValueInputCount());
   EXPECT_EQ(1, OperatorProperties::GetContextInputCount(op));
   EXPECT_EQ(frame_state_input_count,
@@ -181,7 +182,7 @@ TEST_P(JSStorePropertyOperatorTest, NumberOfInputsAndOutputs) {
 
   EXPECT_EQ(0, op->ValueOutputCount());
   EXPECT_EQ(1, op->EffectOutputCount());
-  EXPECT_EQ(0, op->ControlOutputCount());
+  EXPECT_EQ(2, op->ControlOutputCount());
 }
 
 
index d61a181..d347c41 100644 (file)
@@ -8,6 +8,7 @@
 #include "src/compiler/js-typed-lowering.h"
 #include "src/compiler/machine-operator.h"
 #include "src/compiler/node-properties.h"
+#include "src/compiler/operator-properties.h"
 #include "test/unittests/compiler/compiler-test-utils.h"
 #include "test/unittests/compiler/graph-unittest.h"
 #include "test/unittests/compiler/node-test-utils.h"
@@ -119,6 +120,16 @@ TEST_F(JSTypedLoweringTest, JSUnaryNotWithBoolean) {
 }
 
 
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithOrderedNumber) {
+  Node* input = Parameter(Type::OrderedNumber(), 0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsNumberEqual(input, IsNumberConstant(0)));
+}
+
+
 TEST_F(JSTypedLoweringTest, JSUnaryNotWithFalsish) {
   Node* input = Parameter(
       Type::Union(
@@ -173,13 +184,25 @@ TEST_F(JSTypedLoweringTest, JSUnaryNotWithNonZeroPlainNumber) {
 }
 
 
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithString) {
+  Node* input = Parameter(Type::String(), 0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(),
+              IsNumberEqual(IsLoadField(AccessBuilder::ForStringLength(), input,
+                                        graph()->start(), graph()->start()),
+                            IsNumberConstant(0.0)));
+}
+
+
 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)));
+  ASSERT_FALSE(r.Changed());
 }
 
 
@@ -349,13 +372,37 @@ TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) {
 }
 
 
+TEST_F(JSTypedLoweringTest, JSToBooleanWithOrderedNumber) {
+  Node* input = Parameter(Type::OrderedNumber(), 0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(),
+              IsBooleanNot(IsNumberEqual(input, IsNumberConstant(0.0))));
+}
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithString) {
+  Node* input = Parameter(Type::String(), 0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(
+      r.replacement(),
+      IsNumberLessThan(IsNumberConstant(0.0),
+                       IsLoadField(AccessBuilder::ForStringLength(), input,
+                                   graph()->start(), graph()->start())));
+}
+
+
 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));
+  ASSERT_FALSE(r.Changed());
 }
 
 
@@ -681,8 +728,9 @@ TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) {
       Node* control = graph()->start();
       Node* node = graph()->NewNode(javascript()->StoreProperty(language_mode),
                                     base, key, value, context);
-      if (FLAG_turbo_deoptimization) {
-        node->AppendInput(zone(), UndefinedConstant());
+      for (int i = 0;
+           i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) {
+        node->AppendInput(zone(), EmptyFrameState());
       }
       node->AppendInput(zone(), effect);
       node->AppendInput(zone(), control);
@@ -726,8 +774,9 @@ TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithConversion) {
       Node* control = graph()->start();
       Node* node = graph()->NewNode(javascript()->StoreProperty(language_mode),
                                     base, key, value, context);
-      if (FLAG_turbo_deoptimization) {
-        node->AppendInput(zone(), UndefinedConstant());
+      for (int i = 0;
+           i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) {
+        node->AppendInput(zone(), EmptyFrameState());
       }
       node->AppendInput(zone(), effect);
       node->AppendInput(zone(), control);
@@ -784,8 +833,9 @@ TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithSafeKey) {
       Node* control = graph()->start();
       Node* node = graph()->NewNode(javascript()->StoreProperty(language_mode),
                                     base, key, value, context);
-      if (FLAG_turbo_deoptimization) {
-        node->AppendInput(zone(), UndefinedConstant());
+      for (int i = 0;
+           i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) {
+        node->AppendInput(zone(), EmptyFrameState());
       }
       node->AppendInput(zone(), effect);
       node->AppendInput(zone(), control);
diff --git a/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc b/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc
new file mode 100644 (file)
index 0000000..f7d0db3
--- /dev/null
@@ -0,0 +1,373 @@
+// Copyright 2014 the V8 project 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-graph.h"
+#include "src/compiler/linkage.h"
+#include "src/compiler/liveness-analyzer.h"
+#include "src/compiler/node-matchers.h"
+#include "src/compiler/state-values-utils.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+
+using testing::MakeMatcher;
+using testing::MatcherInterface;
+using testing::MatchResultListener;
+using testing::StringMatchResultListener;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class LivenessAnalysisTest : public GraphTest {
+ public:
+  explicit LivenessAnalysisTest(int locals_count = 4)
+      : locals_count_(locals_count),
+        machine_(zone(), kRepWord32),
+        javascript_(zone()),
+        jsgraph_(isolate(), graph(), common(), &javascript_, &machine_),
+        analyzer_(locals_count, zone()),
+        empty_values_(graph()->NewNode(common()->StateValues(0), 0, nullptr)),
+        next_checkpoint_id_(0),
+        current_block_(nullptr) {}
+
+
+ protected:
+  JSGraph* jsgraph() { return &jsgraph_; }
+
+  LivenessAnalyzer* analyzer() { return &analyzer_; }
+  void Run() {
+    StateValuesCache cache(jsgraph());
+    NonLiveFrameStateSlotReplacer replacer(&cache,
+                                           jsgraph()->UndefinedConstant(),
+                                           analyzer()->local_count(), zone());
+    analyzer()->Run(&replacer);
+  }
+
+  Node* Checkpoint() {
+    int ast_num = next_checkpoint_id_++;
+    int first_const = intconst_from_bailout_id(ast_num, locals_count_);
+
+    const Operator* locals_op = common()->StateValues(locals_count_);
+
+    ZoneVector<Node*> local_inputs(locals_count_, nullptr, zone());
+    for (int i = 0; i < locals_count_; i++) {
+      local_inputs[i] = jsgraph()->Int32Constant(i + first_const);
+    }
+    Node* locals =
+        graph()->NewNode(locals_op, locals_count_, &local_inputs.front());
+
+    const Operator* op = common()->FrameState(
+        JS_FRAME, BailoutId(ast_num), OutputFrameStateCombine::Ignore());
+    Node* result = graph()->NewNode(op, empty_values_, locals, empty_values_,
+                                    jsgraph()->UndefinedConstant(),
+                                    jsgraph()->UndefinedConstant());
+
+    current_block_->Checkpoint(result);
+    return result;
+  }
+
+  void Bind(int var) { current_block()->Bind(var); }
+  void Lookup(int var) { current_block()->Lookup(var); }
+
+  class CheckpointMatcher : public MatcherInterface<Node*> {
+   public:
+    explicit CheckpointMatcher(const char* liveness, Node* empty_values,
+                               int locals_count, Node* replacement)
+        : liveness_(liveness),
+          empty_values_(empty_values),
+          locals_count_(locals_count),
+          replacement_(replacement) {}
+
+    void DescribeTo(std::ostream* os) const OVERRIDE {
+      *os << "is a frame state with '" << liveness_
+          << "' liveness, empty "
+             "parameters and empty expression stack";
+    }
+
+    bool MatchAndExplain(Node* frame_state,
+                         MatchResultListener* listener) const OVERRIDE {
+      if (frame_state == NULL) {
+        *listener << "which is NULL";
+        return false;
+      }
+      DCHECK(frame_state->opcode() == IrOpcode::kFrameState);
+
+      FrameStateCallInfo state_info =
+          OpParameter<FrameStateCallInfo>(frame_state);
+      int ast_num = state_info.bailout_id().ToInt();
+      int first_const = intconst_from_bailout_id(ast_num, locals_count_);
+
+      if (empty_values_ != frame_state->InputAt(0)) {
+        *listener << "whose parameters are " << frame_state->InputAt(0)
+                  << " but should have been " << empty_values_ << " (empty)";
+        return false;
+      }
+      if (empty_values_ != frame_state->InputAt(2)) {
+        *listener << "whose expression stack is " << frame_state->InputAt(2)
+                  << " but should have been " << empty_values_ << " (empty)";
+        return false;
+      }
+      StateValuesAccess locals(frame_state->InputAt(1));
+      if (locals_count_ != static_cast<int>(locals.size())) {
+        *listener << "whose number of locals is " << locals.size()
+                  << " but should have been " << locals_count_;
+        return false;
+      }
+      int i = 0;
+      for (StateValuesAccess::TypedNode value : locals) {
+        if (liveness_[i] == 'L') {
+          StringMatchResultListener value_listener;
+          if (value.node == replacement_) {
+            *listener << "whose local #" << i << " was " << value.node->opcode()
+                      << " but should have been 'undefined'";
+            return false;
+          } else if (!IsInt32Constant(first_const + i)
+                          .MatchAndExplain(value.node, &value_listener)) {
+            *listener << "whose local #" << i << " does not match";
+            if (value_listener.str() != "") {
+              *listener << ", " << value_listener.str();
+            }
+            return false;
+          }
+        } else if (liveness_[i] == '.') {
+          if (value.node != replacement_) {
+            *listener << "whose local #" << i << " is " << value.node
+                      << " but should have been " << replacement_
+                      << " (undefined)";
+            return false;
+          }
+        } else {
+          UNREACHABLE();
+        }
+        i++;
+      }
+      return true;
+    }
+
+   private:
+    const char* liveness_;
+    Node* empty_values_;
+    int locals_count_;
+    Node* replacement_;
+  };
+
+  Matcher<Node*> IsCheckpointModuloLiveness(const char* liveness) {
+    return MakeMatcher(new CheckpointMatcher(liveness, empty_values_,
+                                             locals_count_,
+                                             jsgraph()->UndefinedConstant()));
+  }
+
+  LivenessAnalyzerBlock* current_block() { return current_block_; }
+  void set_current_block(LivenessAnalyzerBlock* block) {
+    current_block_ = block;
+  }
+
+ private:
+  static int intconst_from_bailout_id(int ast_num, int locals_count) {
+    return (locals_count + 1) * ast_num + 1;
+  }
+
+  int locals_count_;
+  MachineOperatorBuilder machine_;
+  JSOperatorBuilder javascript_;
+  JSGraph jsgraph_;
+  LivenessAnalyzer analyzer_;
+  Node* empty_values_;
+  int next_checkpoint_id_;
+  LivenessAnalyzerBlock* current_block_;
+};
+
+
+TEST_F(LivenessAnalysisTest, EmptyBlock) {
+  set_current_block(analyzer()->NewBlock());
+
+  Node* c1 = Checkpoint();
+
+  Run();
+
+  // Nothing is live.
+  EXPECT_THAT(c1, IsCheckpointModuloLiveness("...."));
+}
+
+
+TEST_F(LivenessAnalysisTest, SimpleLookup) {
+  set_current_block(analyzer()->NewBlock());
+
+  Node* c1 = Checkpoint();
+  Lookup(1);
+  Node* c2 = Checkpoint();
+
+  Run();
+
+  EXPECT_THAT(c1, IsCheckpointModuloLiveness(".L.."));
+  EXPECT_THAT(c2, IsCheckpointModuloLiveness("...."));
+}
+
+
+TEST_F(LivenessAnalysisTest, DiamondLookups) {
+  // Start block.
+  LivenessAnalyzerBlock* start = analyzer()->NewBlock();
+  set_current_block(start);
+  Node* c1_start = Checkpoint();
+
+  // First branch.
+  LivenessAnalyzerBlock* b1 = analyzer()->NewBlock(start);
+  set_current_block(b1);
+
+  Node* c1_b1 = Checkpoint();
+  Lookup(1);
+  Node* c2_b1 = Checkpoint();
+  Lookup(3);
+  Node* c3_b1 = Checkpoint();
+
+  // Second branch.
+  LivenessAnalyzerBlock* b2 = analyzer()->NewBlock(start);
+  set_current_block(b2);
+
+  Node* c1_b2 = Checkpoint();
+  Lookup(3);
+  Node* c2_b2 = Checkpoint();
+  Lookup(2);
+  Node* c3_b2 = Checkpoint();
+
+  // Merge block.
+  LivenessAnalyzerBlock* m = analyzer()->NewBlock(b1);
+  m->AddPredecessor(b2);
+  set_current_block(m);
+  Node* c1_m = Checkpoint();
+  Lookup(0);
+  Node* c2_m = Checkpoint();
+
+  Run();
+
+  EXPECT_THAT(c1_start, IsCheckpointModuloLiveness("LLLL"));
+
+  EXPECT_THAT(c1_b1, IsCheckpointModuloLiveness("LL.L"));
+  EXPECT_THAT(c2_b1, IsCheckpointModuloLiveness("L..L"));
+  EXPECT_THAT(c3_b1, IsCheckpointModuloLiveness("L..."));
+
+  EXPECT_THAT(c1_b2, IsCheckpointModuloLiveness("L.LL"));
+  EXPECT_THAT(c2_b2, IsCheckpointModuloLiveness("L.L."));
+  EXPECT_THAT(c3_b2, IsCheckpointModuloLiveness("L..."));
+
+  EXPECT_THAT(c1_m, IsCheckpointModuloLiveness("L..."));
+  EXPECT_THAT(c2_m, IsCheckpointModuloLiveness("...."));
+}
+
+
+TEST_F(LivenessAnalysisTest, DiamondLookupsAndBinds) {
+  // Start block.
+  LivenessAnalyzerBlock* start = analyzer()->NewBlock();
+  set_current_block(start);
+  Node* c1_start = Checkpoint();
+  Bind(0);
+  Node* c2_start = Checkpoint();
+
+  // First branch.
+  LivenessAnalyzerBlock* b1 = analyzer()->NewBlock(start);
+  set_current_block(b1);
+
+  Node* c1_b1 = Checkpoint();
+  Bind(2);
+  Bind(1);
+  Node* c2_b1 = Checkpoint();
+  Bind(3);
+  Node* c3_b1 = Checkpoint();
+
+  // Second branch.
+  LivenessAnalyzerBlock* b2 = analyzer()->NewBlock(start);
+  set_current_block(b2);
+
+  Node* c1_b2 = Checkpoint();
+  Lookup(2);
+  Node* c2_b2 = Checkpoint();
+  Bind(2);
+  Bind(3);
+  Node* c3_b2 = Checkpoint();
+
+  // Merge block.
+  LivenessAnalyzerBlock* m = analyzer()->NewBlock(b1);
+  m->AddPredecessor(b2);
+  set_current_block(m);
+  Node* c1_m = Checkpoint();
+  Lookup(0);
+  Lookup(1);
+  Lookup(2);
+  Lookup(3);
+  Node* c2_m = Checkpoint();
+
+  Run();
+
+  EXPECT_THAT(c1_start, IsCheckpointModuloLiveness(".LL."));
+  EXPECT_THAT(c2_start, IsCheckpointModuloLiveness("LLL."));
+
+  EXPECT_THAT(c1_b1, IsCheckpointModuloLiveness("L..."));
+  EXPECT_THAT(c2_b1, IsCheckpointModuloLiveness("LLL."));
+  EXPECT_THAT(c3_b1, IsCheckpointModuloLiveness("LLLL"));
+
+  EXPECT_THAT(c1_b2, IsCheckpointModuloLiveness("LLL."));
+  EXPECT_THAT(c2_b2, IsCheckpointModuloLiveness("LL.."));
+  EXPECT_THAT(c3_b2, IsCheckpointModuloLiveness("LLLL"));
+
+  EXPECT_THAT(c1_m, IsCheckpointModuloLiveness("LLLL"));
+  EXPECT_THAT(c2_m, IsCheckpointModuloLiveness("...."));
+}
+
+
+TEST_F(LivenessAnalysisTest, SimpleLoop) {
+  // Start block.
+  LivenessAnalyzerBlock* start = analyzer()->NewBlock();
+  set_current_block(start);
+  Node* c1_start = Checkpoint();
+  Bind(0);
+  Bind(1);
+  Bind(2);
+  Bind(3);
+  Node* c2_start = Checkpoint();
+
+  // Loop header block.
+  LivenessAnalyzerBlock* header = analyzer()->NewBlock(start);
+  set_current_block(header);
+  Node* c1_header = Checkpoint();
+  Lookup(0);
+  Bind(2);
+  Node* c2_header = Checkpoint();
+
+  // Inside-loop block.
+  LivenessAnalyzerBlock* in_loop = analyzer()->NewBlock(header);
+  set_current_block(in_loop);
+  Node* c1_in_loop = Checkpoint();
+  Bind(0);
+  Lookup(3);
+  Node* c2_in_loop = Checkpoint();
+
+  // Add back edge.
+  header->AddPredecessor(in_loop);
+
+  // After-loop block.
+  LivenessAnalyzerBlock* end = analyzer()->NewBlock(header);
+  set_current_block(end);
+  Node* c1_end = Checkpoint();
+  Lookup(1);
+  Lookup(2);
+  Node* c2_end = Checkpoint();
+
+  Run();
+
+  EXPECT_THAT(c1_start, IsCheckpointModuloLiveness("...."));
+  EXPECT_THAT(c2_start, IsCheckpointModuloLiveness("LL.L"));
+
+  EXPECT_THAT(c1_header, IsCheckpointModuloLiveness("LL.L"));
+  EXPECT_THAT(c2_header, IsCheckpointModuloLiveness(".LLL"));
+
+  EXPECT_THAT(c1_in_loop, IsCheckpointModuloLiveness(".L.L"));
+  EXPECT_THAT(c2_in_loop, IsCheckpointModuloLiveness("LL.L"));
+
+  EXPECT_THAT(c1_end, IsCheckpointModuloLiveness(".LL."));
+  EXPECT_THAT(c2_end, IsCheckpointModuloLiveness("...."));
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
index f63e70d..11c679c 100644 (file)
@@ -233,6 +233,27 @@ const uint32_t kUint32Values[] = {
     0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff, 0x0000ffff, 0x00007fff,
     0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff};
 
+
+struct ComparisonBinaryOperator {
+  const Operator* (MachineOperatorBuilder::*constructor)();
+  const char* constructor_name;
+};
+
+
+std::ostream& operator<<(std::ostream& os,
+                         ComparisonBinaryOperator const& cbop) {
+  return os << cbop.constructor_name;
+}
+
+
+const ComparisonBinaryOperator kComparisonBinaryOperators[] = {
+#define OPCODE(Opcode)                         \
+  { &MachineOperatorBuilder::Opcode, #Opcode } \
+  ,
+    MACHINE_COMPARE_BINOP_LIST(OPCODE)
+#undef OPCODE
+};
+
 }  // namespace
 
 
@@ -595,6 +616,33 @@ TEST_F(MachineOperatorReducerTest, Word32AndWithInt32AddAndConstant) {
 }
 
 
+TEST_F(MachineOperatorReducerTest, Word32AndWithInt32MulAndConstant) {
+  Node* const p0 = Parameter(0);
+
+  TRACED_FORRANGE(int32_t, l, 1, 31) {
+    TRACED_FOREACH(int32_t, k, kInt32Values) {
+      if ((k << l) == 0) continue;
+
+      // (x * (K << L)) & (-1 << L) => x * (K << L)
+      Reduction const r1 = Reduce(graph()->NewNode(
+          machine()->Word32And(),
+          graph()->NewNode(machine()->Int32Mul(), p0, Int32Constant(k << l)),
+          Int32Constant(-1 << l)));
+      ASSERT_TRUE(r1.Changed());
+      EXPECT_THAT(r1.replacement(), IsInt32Mul(p0, IsInt32Constant(k << l)));
+
+      // ((K << L) * x) & (-1 << L) => x * (K << L)
+      Reduction const r2 = Reduce(graph()->NewNode(
+          machine()->Word32And(),
+          graph()->NewNode(machine()->Int32Mul(), Int32Constant(k << l), p0),
+          Int32Constant(-1 << l)));
+      ASSERT_TRUE(r2.Changed());
+      EXPECT_THAT(r2.replacement(), IsInt32Mul(p0, IsInt32Constant(k << l)));
+    }
+  }
+}
+
+
 TEST_F(MachineOperatorReducerTest,
        Word32AndWithInt32AddAndInt32MulAndConstant) {
   Node* const p0 = Parameter(0);
@@ -632,6 +680,27 @@ TEST_F(MachineOperatorReducerTest,
 }
 
 
+TEST_F(MachineOperatorReducerTest, Word32AndWithComparisonAndConstantOne) {
+  Node* const p0 = Parameter(0);
+  Node* const p1 = Parameter(1);
+  TRACED_FOREACH(ComparisonBinaryOperator, cbop, kComparisonBinaryOperators) {
+    Node* cmp = graph()->NewNode((machine()->*cbop.constructor)(), p0, p1);
+
+    // cmp & 1 => cmp
+    Reduction const r1 =
+        Reduce(graph()->NewNode(machine()->Word32And(), cmp, Int32Constant(1)));
+    ASSERT_TRUE(r1.Changed());
+    EXPECT_EQ(cmp, r1.replacement());
+
+    // 1 & cmp => cmp
+    Reduction const r2 =
+        Reduce(graph()->NewNode(machine()->Word32And(), Int32Constant(1), cmp));
+    ASSERT_TRUE(r2.Changed());
+    EXPECT_EQ(cmp, r2.replacement());
+  }
+}
+
+
 // -----------------------------------------------------------------------------
 // Word32Xor
 
@@ -773,6 +842,24 @@ TEST_F(MachineOperatorReducerTest, Word32RorWithConstants) {
 // Word32Sar
 
 
+TEST_F(MachineOperatorReducerTest, Word32SarWithWord32ShlAndComparison) {
+  Node* const p0 = Parameter(0);
+  Node* const p1 = Parameter(1);
+
+  TRACED_FOREACH(ComparisonBinaryOperator, cbop, kComparisonBinaryOperators) {
+    Node* cmp = graph()->NewNode((machine()->*cbop.constructor)(), p0, p1);
+
+    // cmp << 31 >> 31 => 0 - cmp
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Word32Sar(),
+        graph()->NewNode(machine()->Word32Shl(), cmp, Int32Constant(31)),
+        Int32Constant(31)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Sub(IsInt32Constant(0), cmp));
+  }
+}
+
+
 TEST_F(MachineOperatorReducerTest, Word32SarWithWord32ShlAndLoad) {
   Node* const p0 = Parameter(0);
   Node* const p1 = Parameter(1);
@@ -1190,6 +1277,28 @@ TEST_F(MachineOperatorReducerTest, Uint32ModWithParameters) {
 
 
 // -----------------------------------------------------------------------------
+// Int32Add
+
+
+TEST_F(MachineOperatorReducerTest, Int32AddWithInt32SubWithConstantZero) {
+  Node* const p0 = Parameter(0);
+  Node* const p1 = Parameter(1);
+
+  Reduction const r1 = Reduce(graph()->NewNode(
+      machine()->Int32Add(),
+      graph()->NewNode(machine()->Int32Sub(), Int32Constant(0), p0), p1));
+  ASSERT_TRUE(r1.Changed());
+  EXPECT_THAT(r1.replacement(), IsInt32Sub(p1, p0));
+
+  Reduction const r2 = Reduce(graph()->NewNode(
+      machine()->Int32Add(), p0,
+      graph()->NewNode(machine()->Int32Sub(), Int32Constant(0), p1)));
+  ASSERT_TRUE(r2.Changed());
+  EXPECT_THAT(r2.replacement(), IsInt32Sub(p0, p1));
+}
+
+
+// -----------------------------------------------------------------------------
 // Int32AddWithOverflow
 
 
@@ -1327,6 +1436,46 @@ TEST_F(MachineOperatorReducerTest, Float64MulWithMinusOne) {
 
 
 // -----------------------------------------------------------------------------
+// Float64InsertLowWord32
+
+
+TEST_F(MachineOperatorReducerTest, Float64InsertLowWord32WithConstant) {
+  TRACED_FOREACH(double, x, kFloat64Values) {
+    TRACED_FOREACH(uint32_t, y, kUint32Values) {
+      Reduction const r =
+          Reduce(graph()->NewNode(machine()->Float64InsertLowWord32(),
+                                  Float64Constant(x), Uint32Constant(y)));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(
+          r.replacement(),
+          IsFloat64Constant(BitEq(bit_cast<double>(
+              (bit_cast<uint64_t>(x) & V8_UINT64_C(0xFFFFFFFF00000000)) | y))));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Float64InsertHighWord32
+
+
+TEST_F(MachineOperatorReducerTest, Float64InsertHighWord32WithConstant) {
+  TRACED_FOREACH(double, x, kFloat64Values) {
+    TRACED_FOREACH(uint32_t, y, kUint32Values) {
+      Reduction const r =
+          Reduce(graph()->NewNode(machine()->Float64InsertHighWord32(),
+                                  Float64Constant(x), Uint32Constant(y)));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsFloat64Constant(BitEq(bit_cast<double>(
+                      (bit_cast<uint64_t>(x) & V8_UINT64_C(0xFFFFFFFF)) |
+                      (static_cast<uint64_t>(y) << 32)))));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
 // Store
 
 
index 6e0df2a..71b3c0e 100644 (file)
@@ -180,24 +180,24 @@ const PureOperator kPureOperators[] = {
     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(Word32Equal, 2, 0, 1), PURE(Word32Clz, 1, 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),
@@ -205,8 +205,12 @@ const PureOperator kPureOperators[] = {
     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)
+    PURE(Float64RoundDown, 1, 0, 1), PURE(Float64RoundTruncate, 1, 0, 1),
+    PURE(Float64RoundTiesAway, 1, 0, 1), PURE(Float64ExtractLowWord32, 1, 0, 1),
+    PURE(Float64ExtractHighWord32, 1, 0, 1),
+    PURE(Float64InsertLowWord32, 2, 0, 1),
+    PURE(Float64InsertHighWord32, 2, 0, 1), PURE(Float64Max, 2, 0, 1),
+    PURE(Float64Min, 2, 0, 1)
 #undef PURE
 };
 
index efe26d2..bafa89d 100644 (file)
@@ -800,6 +800,21 @@ TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
   }
 }
 
+
+TEST_F(InstructionSelectorTest, Word32Clz) {
+  StreamBuilder m(this, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Word32Clz(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kMipsClz, 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()));
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 4145333..0953de8 100644 (file)
@@ -166,29 +166,28 @@ const IntCmp kCmpInstructions[] = {
     {{&RawMachineAssembler::WordNotEqual, "WordNotEqual", kMips64Cmp,
       kMachInt64},
      1U},
-    {{&RawMachineAssembler::Word32Equal, "Word32Equal", kMips64Cmp32,
-      kMachInt32},
+    {{&RawMachineAssembler::Word32Equal, "Word32Equal", kMips64Cmp, kMachInt32},
      1U},
-    {{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kMips64Cmp32,
+    {{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kMips64Cmp,
       kMachInt32},
      1U},
-    {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kMips64Cmp32,
+    {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kMips64Cmp,
       kMachInt32},
      1U},
     {{&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
-      kMips64Cmp32, kMachInt32},
+      kMips64Cmp, kMachInt32},
      1U},
-    {{&RawMachineAssembler::Int32GreaterThan, "Int32GreaterThan", kMips64Cmp32,
+    {{&RawMachineAssembler::Int32GreaterThan, "Int32GreaterThan", kMips64Cmp,
       kMachInt32},
      1U},
     {{&RawMachineAssembler::Int32GreaterThanOrEqual, "Int32GreaterThanOrEqual",
-      kMips64Cmp32, kMachInt32},
+      kMips64Cmp, kMachInt32},
      1U},
-    {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kMips64Cmp32,
+    {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kMips64Cmp,
       kMachUint32},
      1U},
     {{&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
-      kMips64Cmp32, kMachUint32},
+      kMips64Cmp, kMachUint32},
      1U}};
 
 
@@ -753,7 +752,7 @@ TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
     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(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());
@@ -765,7 +764,7 @@ TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
     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(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());
@@ -802,6 +801,21 @@ TEST_F(InstructionSelectorTest, Word64EqualWithZero) {
   }
 }
 
+
+TEST_F(InstructionSelectorTest, Word32Clz) {
+  StreamBuilder m(this, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Word32Clz(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kMips64Clz, 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()));
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index b8375fa..da887fe 100644 (file)
@@ -124,6 +124,59 @@ TEST_F(MoveOptimizerTest, SplitsConstants) {
   CHECK(Contains(move, Reg(0), Slot(2)));
 }
 
+
+TEST_F(MoveOptimizerTest, SimpleMerge) {
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 2));
+
+  StartBlock();
+  EndBlock(Jump(2));
+  AddMove(LastGap(), Reg(0), Reg(1));
+
+  StartBlock();
+  EndBlock(Jump(1));
+  AddMove(LastGap(), Reg(0), Reg(1));
+
+  StartBlock();
+  EndBlock(Last());
+
+  Optimize();
+
+  auto move = LastGap()->parallel_moves()[0];
+  CHECK_EQ(1, NonRedundantSize(move));
+  CHECK(Contains(move, Reg(0), Reg(1)));
+}
+
+
+TEST_F(MoveOptimizerTest, SimpleMergeCycle) {
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 2));
+
+  StartBlock();
+  EndBlock(Jump(2));
+  auto gap_0 = LastGap();
+  AddMove(gap_0, Reg(0), Reg(1));
+  AddMove(LastGap(), Reg(1), Reg(0));
+
+  StartBlock();
+  EndBlock(Jump(1));
+  auto gap_1 = LastGap();
+  AddMove(gap_1, Reg(0), Reg(1));
+  AddMove(gap_1, Reg(1), Reg(0));
+
+  StartBlock();
+  EndBlock(Last());
+
+  Optimize();
+
+  CHECK(gap_0->IsRedundant());
+  CHECK(gap_1->IsRedundant());
+  auto move = LastGap()->parallel_moves()[0];
+  CHECK_EQ(2, NonRedundantSize(move));
+  CHECK(Contains(move, Reg(0), Reg(1)));
+  CHECK(Contains(move, Reg(1), Reg(0)));
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index bb471bd..2bec4fa 100644 (file)
@@ -8,7 +8,9 @@
 #include "testing/gmock/include/gmock/gmock.h"
 
 using testing::AnyOf;
+using testing::ElementsAre;
 using testing::IsNull;
+using testing::UnorderedElementsAre;
 
 namespace v8 {
 namespace internal {
@@ -17,6 +19,64 @@ namespace compiler {
 typedef TestWithZone NodePropertiesTest;
 
 
+namespace {
+
+const Operator kMockOperator(IrOpcode::kDead, Operator::kNoProperties,
+                             "MockOperator", 0, 0, 0, 1, 0, 0);
+const Operator kMockOpEffect(IrOpcode::kDead, Operator::kNoProperties,
+                             "MockOpEffect", 0, 1, 0, 1, 1, 0);
+const Operator kMockOpControl(IrOpcode::kDead, Operator::kNoProperties,
+                              "MockOpControl", 0, 0, 1, 1, 0, 1);
+const Operator kMockCallOperator(IrOpcode::kCall, Operator::kNoProperties,
+                                 "MockCallOperator", 0, 0, 0, 0, 0, 2);
+
+}  // namespace
+
+
+TEST_F(NodePropertiesTest, ReplaceWithValue_ValueUse) {
+  CommonOperatorBuilder common(zone());
+  Node* node = Node::New(zone(), 0, &kMockOperator, 0, nullptr, false);
+  Node* use_value = Node::New(zone(), 0, common.Return(), 1, &node, false);
+  Node* replacement = Node::New(zone(), 0, &kMockOperator, 0, nullptr, false);
+  NodeProperties::ReplaceWithValue(node, replacement);
+  EXPECT_EQ(replacement, use_value->InputAt(0));
+  EXPECT_EQ(0, node->UseCount());
+  EXPECT_EQ(1, replacement->UseCount());
+  EXPECT_THAT(replacement->uses(), ElementsAre(use_value));
+}
+
+
+TEST_F(NodePropertiesTest, ReplaceWithValue_EffectUse) {
+  CommonOperatorBuilder common(zone());
+  Node* start = Node::New(zone(), 0, common.Start(1), 0, nullptr, false);
+  Node* node = Node::New(zone(), 0, &kMockOpEffect, 1, &start, false);
+  Node* use_effect = Node::New(zone(), 0, common.EffectPhi(1), 1, &node, false);
+  Node* replacement = Node::New(zone(), 0, &kMockOperator, 0, nullptr, false);
+  NodeProperties::ReplaceWithValue(node, replacement);
+  EXPECT_EQ(start, use_effect->InputAt(0));
+  EXPECT_EQ(0, node->UseCount());
+  EXPECT_EQ(2, start->UseCount());
+  EXPECT_EQ(0, replacement->UseCount());
+  EXPECT_THAT(start->uses(), UnorderedElementsAre(use_effect, node));
+}
+
+
+TEST_F(NodePropertiesTest, ReplaceWithValue_ControlUse) {
+  CommonOperatorBuilder common(zone());
+  Node* start = Node::New(zone(), 0, common.Start(1), 0, nullptr, false);
+  Node* node = Node::New(zone(), 0, &kMockOpControl, 1, &start, false);
+  Node* success = Node::New(zone(), 0, common.IfSuccess(), 1, &node, false);
+  Node* use_control = Node::New(zone(), 0, common.Merge(1), 1, &success, false);
+  Node* replacement = Node::New(zone(), 0, &kMockOperator, 0, nullptr, false);
+  NodeProperties::ReplaceWithValue(node, replacement);
+  EXPECT_EQ(start, use_control->InputAt(0));
+  EXPECT_EQ(0, node->UseCount());
+  EXPECT_EQ(2, start->UseCount());
+  EXPECT_EQ(0, replacement->UseCount());
+  EXPECT_THAT(start->uses(), UnorderedElementsAre(use_control, node));
+}
+
+
 TEST_F(NodePropertiesTest, FindProjection) {
   CommonOperatorBuilder common(zone());
   Node* start = Node::New(zone(), 0, common.Start(1), 0, nullptr, false);
@@ -41,6 +101,18 @@ TEST_F(NodePropertiesTest, CollectControlProjections_Branch) {
 }
 
 
+TEST_F(NodePropertiesTest, CollectControlProjections_Call) {
+  Node* result[2];
+  CommonOperatorBuilder common(zone());
+  Node* call = Node::New(zone(), 1, &kMockCallOperator, 0, nullptr, false);
+  Node* if_ex = Node::New(zone(), 2, common.IfException(), 1, &call, false);
+  Node* if_ok = Node::New(zone(), 3, common.IfSuccess(), 1, &call, false);
+  NodeProperties::CollectControlProjections(call, result, arraysize(result));
+  EXPECT_EQ(if_ok, result[0]);
+  EXPECT_EQ(if_ex, result[1]);
+}
+
+
 TEST_F(NodePropertiesTest, CollectControlProjections_Switch) {
   Node* result[3];
   CommonOperatorBuilder common(zone());
index eccc962..5890b49 100644 (file)
@@ -543,11 +543,23 @@ class IsEffectSetMatcher FINAL : public NodeMatcher {
   }
 
   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));
+    if (!NodeMatcher::MatchAndExplain(node, listener)) return false;
+
+    Node* effect0 = NodeProperties::GetEffectInput(node, 0);
+    Node* effect1 = NodeProperties::GetEffectInput(node, 1);
+
+    {
+      // Try matching in the reverse order first.
+      StringMatchResultListener value_listener;
+      if (effect0_matcher_.MatchAndExplain(effect1, &value_listener) &&
+          effect1_matcher_.MatchAndExplain(effect0, &value_listener)) {
+        return true;
+      }
+    }
+
+    return PrintMatchAndExplain(effect0, "effect0", effect0_matcher_,
+                                listener) &&
+           PrintMatchAndExplain(effect1, "effect1", effect1_matcher_, listener);
   }
 
  private:
@@ -1303,6 +1315,12 @@ Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher) {
 }
 
 
+Matcher<Node*> IsIfSuccess(const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(
+      new IsControl1Matcher(IrOpcode::kIfSuccess, control_matcher));
+}
+
+
 Matcher<Node*> IsSwitch(const Matcher<Node*>& value_matcher,
                         const Matcher<Node*>& control_matcher) {
   return MakeMatcher(new IsSwitchMatcher(value_matcher, control_matcher));
@@ -1584,7 +1602,11 @@ IS_BINOP_MATCHER(Int32MulHigh)
 IS_BINOP_MATCHER(Int32LessThan)
 IS_BINOP_MATCHER(Uint32LessThan)
 IS_BINOP_MATCHER(Uint32LessThanOrEqual)
+IS_BINOP_MATCHER(Float64Max)
+IS_BINOP_MATCHER(Float64Min)
 IS_BINOP_MATCHER(Float64Sub)
+IS_BINOP_MATCHER(Float64InsertLowWord32)
+IS_BINOP_MATCHER(Float64InsertHighWord32)
 #undef IS_BINOP_MATCHER
 
 
@@ -1592,7 +1614,6 @@ IS_BINOP_MATCHER(Float64Sub)
   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)
@@ -1604,14 +1625,16 @@ 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(Float64RoundDown)
 IS_UNOP_MATCHER(Float64RoundTruncate)
 IS_UNOP_MATCHER(Float64RoundTiesAway)
+IS_UNOP_MATCHER(Float64ExtractLowWord32)
+IS_UNOP_MATCHER(Float64ExtractHighWord32)
 IS_UNOP_MATCHER(NumberToInt32)
 IS_UNOP_MATCHER(NumberToUint32)
 IS_UNOP_MATCHER(ObjectIsSmi)
 IS_UNOP_MATCHER(ObjectIsNonNegativeSmi)
+IS_UNOP_MATCHER(Word32Clz)
 #undef IS_UNOP_MATCHER
 
 }  // namespace compiler
index 0301197..7c306a2 100644 (file)
@@ -47,6 +47,7 @@ Matcher<Node*> IsLoop(const Matcher<Node*>& control0_matcher,
                       const Matcher<Node*>& control2_matcher);
 Matcher<Node*> IsIfTrue(const Matcher<Node*>& control_matcher);
 Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsIfSuccess(const Matcher<Node*>& control_matcher);
 Matcher<Node*> IsSwitch(const Matcher<Node*>& value_matcher,
                         const Matcher<Node*>& control_matcher);
 Matcher<Node*> IsIfValue(const Matcher<int32_t>& value_matcher,
@@ -100,7 +101,6 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_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);
@@ -169,6 +169,7 @@ 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*> IsWord32Clz(const Matcher<Node*>& value_matcher);
 Matcher<Node*> IsWord64And(const Matcher<Node*>& lhs_matcher,
                            const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsWord64Shl(const Matcher<Node*>& lhs_matcher,
@@ -202,13 +203,22 @@ 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*> IsFloat64Max(const Matcher<Node*>& lhs_matcher,
+                            const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsFloat64Min(const Matcher<Node*>& lhs_matcher,
+                            const Matcher<Node*>& rhs_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*> IsFloat64RoundDown(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsFloat64RoundTruncate(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsFloat64RoundTiesAway(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64ExtractLowWord32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64ExtractHighWord32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64InsertLowWord32(const Matcher<Node*>& lhs_matcher,
+                                        const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsFloat64InsertHighWord32(const Matcher<Node*>& lhs_matcher,
+                                         const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher,
                           const Matcher<Node*>& context_matcher,
                           const Matcher<Node*>& effect_matcher,
index f56d7d6..1a6c1bd 100644 (file)
@@ -48,15 +48,15 @@ TEST_F(NodeTest, NewWithInputs) {
   EXPECT_EQ(0, n0->InputCount());
   Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
   EXPECT_EQ(1, n0->UseCount());
-  EXPECT_EQ(n1, n0->UseAt(0));
+  EXPECT_THAT(n0->uses(), UnorderedElementsAre(n1));
   EXPECT_EQ(0, n1->UseCount());
   EXPECT_EQ(1, n1->InputCount());
   EXPECT_EQ(n0, n1->InputAt(0));
   Node* n0_n1[] = {n0, n1};
   Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
   EXPECT_EQ(2, n0->UseCount());
-  EXPECT_EQ(n1, n0->UseAt(0));
-  EXPECT_EQ(n2, n0->UseAt(1));
+  EXPECT_THAT(n0->uses(), UnorderedElementsAre(n1, n2));
+  EXPECT_THAT(n1->uses(), UnorderedElementsAre(n2));
   EXPECT_EQ(2, n2->InputCount());
   EXPECT_EQ(n0, n2->InputAt(0));
   EXPECT_EQ(n1, n2->InputAt(1));
index ca79e8a..3bb65c2 100644 (file)
@@ -64,6 +64,21 @@ bool IsConstantOpcode(IrOpcode::Value opcode) {
 }
 
 
+bool IsComparisonOpcode(IrOpcode::Value opcode) {
+  switch (opcode) {
+#define OPCODE(Opcode)      \
+  case IrOpcode::k##Opcode: \
+    return true;
+    JS_COMPARE_BINOP_LIST(OPCODE)
+    SIMPLIFIED_COMPARE_BINOP_LIST(OPCODE)
+    MACHINE_COMPARE_BINOP_LIST(OPCODE)
+#undef OPCODE
+    default:
+      return false;
+  }
+}
+
+
 const IrOpcode::Value kInvalidOpcode = static_cast<IrOpcode::Value>(123456789);
 
 }  // namespace
@@ -109,6 +124,16 @@ TEST(IrOpcodeTest, IsConstantOpcode) {
 }
 
 
+TEST(IrOpcodeTest, IsComparisonOpcode) {
+  EXPECT_FALSE(IrOpcode::IsComparisonOpcode(kInvalidOpcode));
+#define OPCODE(Opcode)                               \
+  EXPECT_EQ(IsComparisonOpcode(IrOpcode::k##Opcode), \
+            IrOpcode::IsComparisonOpcode(IrOpcode::k##Opcode));
+  ALL_OP_LIST(OPCODE)
+#undef OPCODE
+}
+
+
 TEST(IrOpcodeTest, Mnemonic) {
   EXPECT_STREQ("UnknownOpcode", IrOpcode::Mnemonic(kInvalidOpcode));
 #define OPCODE(Opcode) \
diff --git a/deps/v8/test/unittests/compiler/ppc/OWNERS b/deps/v8/test/unittests/compiler/ppc/OWNERS
new file mode 100644 (file)
index 0000000..beecb3d
--- /dev/null
@@ -0,0 +1,3 @@
+joransiu@ca.ibm.com
+mbrandy@us.ibm.com
+michael_dawson@ca.ibm.com
index c82cc37..873b4ec 100644 (file)
@@ -301,6 +301,31 @@ TEST_F(RegisterAllocatorTest, SplitBeforeInstruction) {
 }
 
 
+TEST_F(RegisterAllocatorTest, SplitBeforeInstruction2) {
+  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] and [1] will be split in the second half of this instruction.
+  EmitOOI(Reg(0), Reg(1), Reg(p_0, 0), Reg(p_1, 1));
+  EmitI(Reg(values[0]), Reg(values[1]));
+  EndBlock(Last());
+
+  Allocate();
+}
+
+
 TEST_F(RegisterAllocatorTest, NestedDiamondPhiMerge) {
   // Outer diamond.
   StartBlock();
@@ -466,6 +491,87 @@ TEST_F(RegisterAllocatorTest, RegressionLoadConstantBeforeSpill) {
   Allocate();
 }
 
+
+namespace {
+
+enum class ParameterType { kFixedSlot, kSlot, kRegister, kFixedRegister };
+
+const ParameterType kParameterTypes[] = {
+    ParameterType::kFixedSlot, ParameterType::kSlot, ParameterType::kRegister,
+    ParameterType::kFixedRegister};
+
+class SlotConstraintTest : public RegisterAllocatorTest,
+                           public ::testing::WithParamInterface<
+                               ::testing::tuple<ParameterType, int>> {
+ public:
+  static const int kMaxVariant = 5;
+
+ protected:
+  ParameterType parameter_type() const {
+    return ::testing::get<0>(B::GetParam());
+  }
+  int variant() const { return ::testing::get<1>(B::GetParam()); }
+
+ private:
+  typedef ::testing::WithParamInterface<::testing::tuple<ParameterType, int>> B;
+};
+}
+
+
+#if GTEST_HAS_COMBINE
+
+TEST_P(SlotConstraintTest, SlotConstraint) {
+  StartBlock();
+  VReg p_0;
+  switch (parameter_type()) {
+    case ParameterType::kFixedSlot:
+      p_0 = Parameter(Slot(-1));
+      break;
+    case ParameterType::kSlot:
+      p_0 = Parameter(Slot(-1));
+      break;
+    case ParameterType::kRegister:
+      p_0 = Parameter(Reg());
+      break;
+    case ParameterType::kFixedRegister:
+      p_0 = Parameter(Reg(1));
+      break;
+  }
+  switch (variant()) {
+    case 0:
+      EmitI(Slot(p_0), Reg(p_0));
+      break;
+    case 1:
+      EmitI(Slot(p_0));
+      break;
+    case 2:
+      EmitI(Reg(p_0));
+      EmitI(Slot(p_0));
+      break;
+    case 3:
+      EmitI(Slot(p_0));
+      EmitI(Reg(p_0));
+      break;
+    case 4:
+      EmitI(Slot(p_0, -1), Slot(p_0), Reg(p_0), Reg(p_0, 1));
+      break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+  EndBlock(Last());
+
+  Allocate();
+}
+
+
+INSTANTIATE_TEST_CASE_P(
+    RegisterAllocatorTest, SlotConstraintTest,
+    ::testing::Combine(::testing::ValuesIn(kParameterTypes),
+                       ::testing::Range(0, SlotConstraintTest::kMaxVariant)));
+
+#endif  // GTEST_HAS_COMBINE
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 70fd4d5..bc82535 100644 (file)
@@ -73,8 +73,10 @@ typedef TestWithZone ScheduleTest;
 
 namespace {
 
+const Operator kCallOperator(IrOpcode::kCall, Operator::kNoProperties,
+                             "MockCall", 0, 0, 0, 0, 0, 0);
 const Operator kBranchOperator(IrOpcode::kBranch, Operator::kNoProperties,
-                               "Branch", 0, 0, 0, 0, 0, 0);
+                               "MockBranch", 0, 0, 0, 0, 0, 0);
 const Operator kDummyOperator(IrOpcode::kParameter, Operator::kNoProperties,
                               "Dummy", 0, 0, 0, 0, 0, 0);
 
@@ -135,6 +137,35 @@ TEST_F(ScheduleTest, AddGoto) {
 }
 
 
+TEST_F(ScheduleTest, AddCall) {
+  Schedule schedule(zone());
+  BasicBlock* start = schedule.start();
+
+  Node* call = Node::New(zone(), 0, &kCallOperator, 0, nullptr, false);
+  BasicBlock* sblock = schedule.NewBasicBlock();
+  BasicBlock* eblock = schedule.NewBasicBlock();
+  schedule.AddCall(start, call, sblock, eblock);
+
+  EXPECT_EQ(start, schedule.block(call));
+
+  EXPECT_EQ(0u, start->PredecessorCount());
+  EXPECT_EQ(2u, start->SuccessorCount());
+  EXPECT_EQ(sblock, start->SuccessorAt(0));
+  EXPECT_EQ(eblock, start->SuccessorAt(1));
+  EXPECT_THAT(start->successors(), ElementsAre(sblock, eblock));
+
+  EXPECT_EQ(1u, sblock->PredecessorCount());
+  EXPECT_EQ(0u, sblock->SuccessorCount());
+  EXPECT_EQ(start, sblock->PredecessorAt(0));
+  EXPECT_THAT(sblock->predecessors(), ElementsAre(start));
+
+  EXPECT_EQ(1u, eblock->PredecessorCount());
+  EXPECT_EQ(0u, eblock->SuccessorCount());
+  EXPECT_EQ(start, eblock->PredecessorAt(0));
+  EXPECT_THAT(eblock->predecessors(), ElementsAre(start));
+}
+
+
 TEST_F(ScheduleTest, AddBranch) {
   Schedule schedule(zone());
   BasicBlock* start = schedule.start();
index 860d5cd..eeb5bbc 100644 (file)
@@ -16,6 +16,9 @@
 #include "src/compiler/verifier.h"
 #include "test/unittests/compiler/compiler-test-utils.h"
 #include "test/unittests/test-utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::AnyOf;
 
 namespace v8 {
 namespace internal {
@@ -26,31 +29,31 @@ class SchedulerTest : public TestWithZone {
   SchedulerTest()
       : graph_(zone()), common_(zone()), simplified_(zone()), js_(zone()) {}
 
-  static Schedule* ComputeAndVerifySchedule(int expected, Graph* graph) {
+  Schedule* ComputeAndVerifySchedule(size_t expected) {
     if (FLAG_trace_turbo) {
       OFStream os(stdout);
-      os << AsDOT(*graph);
+      os << AsDOT(*graph());
     }
 
-    Schedule* schedule = Scheduler::ComputeSchedule(graph->zone(), graph,
-                                                    Scheduler::kSplitNodes);
+    Schedule* schedule =
+        Scheduler::ComputeSchedule(zone(), graph(), Scheduler::kSplitNodes);
 
     if (FLAG_trace_turbo_scheduler) {
       OFStream os(stdout);
       os << *schedule << std::endl;
     }
     ScheduleVerifier::Run(schedule);
-    CHECK_EQ(expected, GetScheduledNodeCount(schedule));
+    EXPECT_EQ(expected, GetScheduledNodeCount(schedule));
     return schedule;
   }
 
-  static int GetScheduledNodeCount(const Schedule* schedule) {
+  size_t GetScheduledNodeCount(const Schedule* schedule) {
     size_t node_count = 0;
     for (auto block : *schedule->rpo_order()) {
       node_count += block->NodeCount();
       if (block->control() != BasicBlock::kNone) ++node_count;
     }
-    return static_cast<int>(node_count);
+    return node_count;
   }
 
   Graph* graph() { return &graph_; }
@@ -71,8 +74,8 @@ class SchedulerRPOTest : public SchedulerTest {
   SchedulerRPOTest() {}
 
   // TODO(titzer): pull RPO tests out to their own file.
-  static void CheckRPONumbers(BasicBlockVector* order, size_t expected,
-                              bool loops_allowed) {
+  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);
@@ -83,8 +86,7 @@ class SchedulerRPOTest : public SchedulerTest {
     }
   }
 
-  static void CheckLoop(BasicBlockVector* order, BasicBlock** blocks,
-                        int body_size) {
+  void CheckLoop(BasicBlockVector* order, BasicBlock** blocks, int body_size) {
     BasicBlock* header = blocks[0];
     BasicBlock* end = header->loop_end();
     CHECK(end);
@@ -110,11 +112,9 @@ class SchedulerRPOTest : public SchedulerTest {
     BasicBlock* header() { return nodes[0]; }
     BasicBlock* last() { return nodes[count - 1]; }
     ~TestLoop() { delete[] nodes; }
-
-    void Check(BasicBlockVector* order) { CheckLoop(order, nodes, count); }
   };
 
-  static TestLoop* CreateLoop(Schedule* schedule, int count) {
+  TestLoop* CreateLoop(Schedule* schedule, int count) {
     TestLoop* loop = new TestLoop();
     loop->count = count;
     loop->nodes = new BasicBlock* [count];
@@ -130,75 +130,27 @@ class SchedulerRPOTest : public SchedulerTest {
 };
 
 
-class SchedulerTestWithIsolate : public SchedulerTest, public TestWithIsolate {
- public:
-  SchedulerTestWithIsolate() {}
-
-  Unique<HeapObject> GetUniqueUndefined() {
-    Handle<HeapObject> object =
-        Handle<HeapObject>(isolate()->heap()->undefined_value(), isolate());
-    return Unique<HeapObject>::CreateUninitialized(object);
-  }
-};
-
 namespace {
 
+const Operator kHeapConstant(IrOpcode::kHeapConstant, Operator::kPure,
+                             "HeapConstant", 0, 0, 0, 1, 0, 0);
 const Operator kIntAdd(IrOpcode::kInt32Add, Operator::kPure, "Int32Add", 2, 0,
                        0, 1, 0, 0);
+const Operator kMockCall(IrOpcode::kCall, Operator::kNoProperties, "MockCall",
+                         0, 0, 1, 1, 0, 2);
 
 }  // namespace
 
 
-TEST_F(SchedulerTest, BuildScheduleEmpty) {
-  graph()->SetStart(graph()->NewNode(common()->Start(0)));
-  graph()->SetEnd(graph()->NewNode(common()->End(), graph()->start()));
-  USE(Scheduler::ComputeSchedule(zone(), graph(), Scheduler::kNoFlags));
-}
-
-
-TEST_F(SchedulerTest, BuildScheduleOneParameter) {
-  graph()->SetStart(graph()->NewNode(common()->Start(0)));
-
-  Node* p1 = graph()->NewNode(common()->Parameter(0), graph()->start());
-  Node* ret = graph()->NewNode(common()->Return(), p1, graph()->start(),
-                               graph()->start());
-
-  graph()->SetEnd(graph()->NewNode(common()->End(), ret));
-
-  USE(Scheduler::ComputeSchedule(zone(), graph(), Scheduler::kNoFlags));
-}
-
-
-TEST_F(SchedulerTest, BuildScheduleIfSplit) {
-  graph()->SetStart(graph()->NewNode(common()->Start(3)));
-
-  Node* p1 = graph()->NewNode(common()->Parameter(0), graph()->start());
-  Node* p2 = graph()->NewNode(common()->Parameter(1), graph()->start());
-  Node* p3 = graph()->NewNode(common()->Parameter(2), graph()->start());
-  Node* p4 = graph()->NewNode(common()->Parameter(3), graph()->start());
-  Node* p5 = graph()->NewNode(common()->Parameter(4), graph()->start());
-  Node* cmp = graph()->NewNode(js()->LessThanOrEqual(), p1, p2, p3,
-                               graph()->start(), graph()->start());
-  Node* branch = graph()->NewNode(common()->Branch(), cmp, graph()->start());
-  Node* true_branch = graph()->NewNode(common()->IfTrue(), branch);
-  Node* false_branch = graph()->NewNode(common()->IfFalse(), branch);
-
-  Node* ret1 =
-      graph()->NewNode(common()->Return(), p4, graph()->start(), true_branch);
-  Node* ret2 =
-      graph()->NewNode(common()->Return(), p5, graph()->start(), false_branch);
-  Node* merge = graph()->NewNode(common()->Merge(2), ret1, ret2);
-  graph()->SetEnd(graph()->NewNode(common()->End(), merge));
-
-  ComputeAndVerifySchedule(13, graph());
-}
+// -----------------------------------------------------------------------------
+// Special reverse-post-order block ordering.
 
 
 TEST_F(SchedulerRPOTest, Degenerate1) {
   Schedule schedule(zone());
   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
   CheckRPONumbers(order, 1, false);
-  CHECK_EQ(schedule.start(), order->at(0));
+  EXPECT_EQ(schedule.start(), order->at(0));
 }
 
 
@@ -208,8 +160,8 @@ TEST_F(SchedulerRPOTest, Degenerate2) {
   schedule.AddGoto(schedule.start(), schedule.end());
   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
   CheckRPONumbers(order, 2, false);
-  CHECK_EQ(schedule.start(), order->at(0));
-  CHECK_EQ(schedule.end(), order->at(1));
+  EXPECT_EQ(schedule.start(), order->at(0));
+  EXPECT_EQ(schedule.end(), order->at(1));
 }
 
 
@@ -230,7 +182,7 @@ TEST_F(SchedulerRPOTest, Line) {
     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());
+        EXPECT_EQ(block->rpo_number() + 1, block->SuccessorAt(0)->rpo_number());
       }
     }
   }
@@ -265,7 +217,7 @@ TEST_F(SchedulerRPOTest, EndLoop) {
   schedule.AddSuccessorForTesting(schedule.start(), loop1->header());
   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
   CheckRPONumbers(order, 3, true);
-  loop1->Check(order);
+  CheckLoop(order, loop1->nodes, loop1->count);
 }
 
 
@@ -276,7 +228,7 @@ TEST_F(SchedulerRPOTest, EndLoopNested) {
   schedule.AddSuccessorForTesting(loop1->last(), schedule.start());
   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
   CheckRPONumbers(order, 3, true);
-  loop1->Check(order);
+  CheckLoop(order, loop1->nodes, loop1->count);
 }
 
 
@@ -296,10 +248,10 @@ TEST_F(SchedulerRPOTest, Diamond) {
   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(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());
+  EXPECT_EQ(0, A->rpo_number());
+  EXPECT_THAT(B->rpo_number(), AnyOf(1, 2));
+  EXPECT_THAT(C->rpo_number(), AnyOf(1, 2));
+  EXPECT_EQ(3, D->rpo_number());
 }
 
 
@@ -464,11 +416,9 @@ TEST_F(SchedulerRPOTest, LoopFollow1) {
 
   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
 
-  CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
-           static_cast<int>(order->size()));
-
-  loop1->Check(order);
-  loop2->Check(order);
+  EXPECT_EQ(schedule.BasicBlockCount(), order->size());
+  CheckLoop(order, loop1->nodes, loop1->count);
+  CheckLoop(order, loop2->nodes, loop2->count);
 }
 
 
@@ -489,10 +439,9 @@ TEST_F(SchedulerRPOTest, LoopFollow2) {
 
   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
 
-  CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
-           static_cast<int>(order->size()));
-  loop1->Check(order);
-  loop2->Check(order);
+  EXPECT_EQ(schedule.BasicBlockCount(), order->size());
+  CheckLoop(order, loop1->nodes, loop1->count);
+  CheckLoop(order, loop2->nodes, loop2->count);
 }
 
 
@@ -510,10 +459,9 @@ TEST_F(SchedulerRPOTest, LoopFollowN) {
       schedule.AddSuccessorForTesting(loop2->nodes[exit], E);
       BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
 
-      CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
-               static_cast<int>(order->size()));
-      loop1->Check(order);
-      loop2->Check(order);
+      EXPECT_EQ(schedule.BasicBlockCount(), order->size());
+      CheckLoop(order, loop1->nodes, loop1->count);
+      CheckLoop(order, loop2->nodes, loop2->count);
     }
   }
 }
@@ -539,10 +487,9 @@ TEST_F(SchedulerRPOTest, NestedLoopFollow1) {
 
   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
 
-  CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
-           static_cast<int>(order->size()));
-  loop1->Check(order);
-  loop2->Check(order);
+  EXPECT_EQ(schedule.BasicBlockCount(), order->size());
+  CheckLoop(order, loop1->nodes, loop1->count);
+  CheckLoop(order, loop2->nodes, loop2->count);
 
   BasicBlock* loop3[] = {B, loop1->nodes[0], loop2->nodes[0], C};
   CheckLoop(order, loop3, 4);
@@ -566,7 +513,7 @@ TEST_F(SchedulerRPOTest, LoopBackedges1) {
 
       BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
       CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-      loop1->Check(order);
+      CheckLoop(order, loop1->nodes, loop1->count);
     }
   }
 }
@@ -591,7 +538,7 @@ TEST_F(SchedulerRPOTest, LoopOutedges1) {
 
       BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
       CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-      loop1->Check(order);
+      CheckLoop(order, loop1->nodes, loop1->count);
     }
   }
 }
@@ -616,7 +563,7 @@ TEST_F(SchedulerRPOTest, LoopOutedges2) {
 
     BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
     CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-    loop1->Check(order);
+    CheckLoop(order, loop1->nodes, loop1->count);
   }
 }
 
@@ -640,10 +587,10 @@ TEST_F(SchedulerRPOTest, LoopOutloops1) {
 
     BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
     CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-    loop1->Check(order);
+    CheckLoop(order, loop1->nodes, loop1->count);
 
     for (int j = 0; j < size; j++) {
-      loopN[j]->Check(order);
+      CheckLoop(order, loopN[j]->nodes, loopN[j]->count);
       delete loopN[j];
     }
     delete[] loopN;
@@ -676,7 +623,58 @@ TEST_F(SchedulerRPOTest, LoopMultibackedge) {
 }
 
 
-TEST_F(SchedulerTestWithIsolate, BuildScheduleIfSplitWithEffects) {
+// -----------------------------------------------------------------------------
+// Graph end-to-end scheduling.
+
+
+TEST_F(SchedulerTest, BuildScheduleEmpty) {
+  graph()->SetStart(graph()->NewNode(common()->Start(0)));
+  graph()->SetEnd(graph()->NewNode(common()->End(), graph()->start()));
+  USE(Scheduler::ComputeSchedule(zone(), graph(), Scheduler::kNoFlags));
+}
+
+
+TEST_F(SchedulerTest, BuildScheduleOneParameter) {
+  graph()->SetStart(graph()->NewNode(common()->Start(0)));
+
+  Node* p1 = graph()->NewNode(common()->Parameter(0), graph()->start());
+  Node* ret = graph()->NewNode(common()->Return(), p1, graph()->start(),
+                               graph()->start());
+
+  graph()->SetEnd(graph()->NewNode(common()->End(), ret));
+
+  USE(Scheduler::ComputeSchedule(zone(), graph(), Scheduler::kNoFlags));
+}
+
+
+TEST_F(SchedulerTest, BuildScheduleIfSplit) {
+  graph()->SetStart(graph()->NewNode(common()->Start(3)));
+
+  Node* p1 = graph()->NewNode(common()->Parameter(0), graph()->start());
+  Node* p2 = graph()->NewNode(common()->Parameter(1), graph()->start());
+  Node* p3 = graph()->NewNode(common()->Parameter(2), graph()->start());
+  Node* p4 = graph()->NewNode(common()->Parameter(3), graph()->start());
+  Node* p5 = graph()->NewNode(common()->Parameter(4), graph()->start());
+  Node* cmp = graph()->NewNode(js()->LessThanOrEqual(), p1, p2, p3,
+                               graph()->start(), graph()->start());
+  Node* branch = graph()->NewNode(common()->Branch(), cmp, graph()->start());
+  Node* true_branch = graph()->NewNode(common()->IfTrue(), branch);
+  Node* false_branch = graph()->NewNode(common()->IfFalse(), branch);
+
+  Node* ret1 =
+      graph()->NewNode(common()->Return(), p4, graph()->start(), true_branch);
+  Node* ret2 =
+      graph()->NewNode(common()->Return(), p5, graph()->start(), false_branch);
+  Node* merge = graph()->NewNode(common()->Merge(2), ret1, ret2);
+  graph()->SetEnd(graph()->NewNode(common()->End(), merge));
+
+  ComputeAndVerifySchedule(13);
+}
+
+
+TEST_F(SchedulerTest, BuildScheduleIfSplitWithEffects) {
+  FLAG_turbo_deoptimization = false;
+
   const Operator* op;
 
   // Manually transcripted code for:
@@ -720,7 +718,7 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleIfSplitWithEffects) {
   Node* n3 = graph()->NewNode(op, n0);
   USE(n3);
   n11->ReplaceInput(1, n3);
-  op = common()->HeapConstant(GetUniqueUndefined());
+  op = &kHeapConstant;
   Node* n7 = graph()->NewNode(op);
   USE(n7);
   n11->ReplaceInput(2, n7);
@@ -808,11 +806,13 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleIfSplitWithEffects) {
   graph()->SetStart(n0);
   graph()->SetEnd(n23);
 
-  ComputeAndVerifySchedule(20, graph());
+  ComputeAndVerifySchedule(20);
 }
 
 
-TEST_F(SchedulerTestWithIsolate, BuildScheduleSimpleLoop) {
+TEST_F(SchedulerTest, BuildScheduleSimpleLoop) {
+  FLAG_turbo_deoptimization = false;
+
   const Operator* op;
 
   // Manually transcripted code for:
@@ -846,7 +846,7 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleSimpleLoop) {
   Node* n16 = graph()->NewNode(op, nil, nil, nil, nil);
   USE(n16);
   n16->ReplaceInput(0, n8);
-  op = common()->HeapConstant(GetUniqueUndefined());
+  op = &kHeapConstant;
   Node* n5 = graph()->NewNode(op);
   USE(n5);
   n16->ReplaceInput(1, n5);
@@ -911,11 +911,13 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleSimpleLoop) {
   graph()->SetStart(n0);
   graph()->SetEnd(n20);
 
-  ComputeAndVerifySchedule(19, graph());
+  ComputeAndVerifySchedule(19);
 }
 
 
-TEST_F(SchedulerTestWithIsolate, BuildScheduleComplexLoops) {
+TEST_F(SchedulerTest, BuildScheduleComplexLoops) {
+  FLAG_turbo_deoptimization = false;
+
   const Operator* op;
 
   // Manually transcripted code for:
@@ -961,7 +963,7 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleComplexLoops) {
   Node* n18 = graph()->NewNode(op, nil, nil, nil, nil);
   USE(n18);
   n18->ReplaceInput(0, n9);
-  op = common()->HeapConstant(GetUniqueUndefined());
+  op = &kHeapConstant;
   Node* n6 = graph()->NewNode(op);
   USE(n6);
   n18->ReplaceInput(1, n6);
@@ -1149,11 +1151,13 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleComplexLoops) {
   graph()->SetStart(n0);
   graph()->SetEnd(n46);
 
-  ComputeAndVerifySchedule(46, graph());
+  ComputeAndVerifySchedule(46);
 }
 
 
-TEST_F(SchedulerTestWithIsolate, BuildScheduleBreakAndContinue) {
+TEST_F(SchedulerTest, BuildScheduleBreakAndContinue) {
+  FLAG_turbo_deoptimization = false;
+
   const Operator* op;
 
   // Manually transcripted code for:
@@ -1201,7 +1205,7 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleBreakAndContinue) {
   Node* n20 = graph()->NewNode(op, nil, nil, nil, nil);
   USE(n20);
   n20->ReplaceInput(0, n10);
-  op = common()->HeapConstant(GetUniqueUndefined());
+  op = &kHeapConstant;
   Node* n6 = graph()->NewNode(op);
   USE(n6);
   n20->ReplaceInput(1, n6);
@@ -1469,11 +1473,13 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleBreakAndContinue) {
   graph()->SetStart(n0);
   graph()->SetEnd(n58);
 
-  ComputeAndVerifySchedule(62, graph());
+  ComputeAndVerifySchedule(62);
 }
 
 
-TEST_F(SchedulerTestWithIsolate, BuildScheduleSimpleLoopWithCodeMotion) {
+TEST_F(SchedulerTest, BuildScheduleSimpleLoopWithCodeMotion) {
+  FLAG_turbo_deoptimization = false;
+
   const Operator* op;
 
   // Manually transcripted code for:
@@ -1533,7 +1539,7 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleSimpleLoopWithCodeMotion) {
   USE(n14);
   n14->ReplaceInput(0, n9);
   n14->ReplaceInput(1, n10);
-  op = common()->HeapConstant(GetUniqueUndefined());
+  op = &kHeapConstant;
   Node* n6 = graph()->NewNode(op);
   USE(n6);
   n14->ReplaceInput(2, n6);
@@ -1583,10 +1589,7 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleSimpleLoopWithCodeMotion) {
   graph()->SetStart(n0);
   graph()->SetEnd(n22);
 
-  Schedule* schedule = ComputeAndVerifySchedule(19, graph());
-  // Make sure the integer-only add gets hoisted to a different block that the
-  // JSAdd.
-  CHECK(schedule->block(n19) != schedule->block(n20));
+  ComputeAndVerifySchedule(19);
 }
 
 
@@ -1617,7 +1620,7 @@ TARGET_TEST_F(SchedulerTest, FloatingDiamond1) {
 
   graph()->SetEnd(end);
 
-  ComputeAndVerifySchedule(13, graph());
+  ComputeAndVerifySchedule(13);
 }
 
 
@@ -1635,7 +1638,7 @@ TARGET_TEST_F(SchedulerTest, FloatingDiamond2) {
 
   graph()->SetEnd(end);
 
-  ComputeAndVerifySchedule(24, graph());
+  ComputeAndVerifySchedule(24);
 }
 
 
@@ -1654,7 +1657,7 @@ TARGET_TEST_F(SchedulerTest, FloatingDiamond3) {
 
   graph()->SetEnd(end);
 
-  ComputeAndVerifySchedule(33, graph());
+  ComputeAndVerifySchedule(33);
 }
 
 
@@ -1691,7 +1694,7 @@ TARGET_TEST_F(SchedulerTest, NestedFloatingDiamonds) {
 
   graph()->SetEnd(end);
 
-  ComputeAndVerifySchedule(23, graph());
+  ComputeAndVerifySchedule(23);
 }
 
 
@@ -1735,7 +1738,7 @@ TARGET_TEST_F(SchedulerTest, NestedFloatingDiamondWithChain) {
 
   graph()->SetEnd(end);
 
-  ComputeAndVerifySchedule(36, graph());
+  ComputeAndVerifySchedule(36);
 }
 
 
@@ -1769,7 +1772,7 @@ TARGET_TEST_F(SchedulerTest, NestedFloatingDiamondWithLoop) {
 
   graph()->SetEnd(end);
 
-  ComputeAndVerifySchedule(20, graph());
+  ComputeAndVerifySchedule(20);
 }
 
 
@@ -1802,7 +1805,7 @@ TARGET_TEST_F(SchedulerTest, LoopedFloatingDiamond1) {
 
   graph()->SetEnd(end);
 
-  ComputeAndVerifySchedule(20, graph());
+  ComputeAndVerifySchedule(20);
 }
 
 
@@ -1836,7 +1839,7 @@ TARGET_TEST_F(SchedulerTest, LoopedFloatingDiamond2) {
 
   graph()->SetEnd(end);
 
-  ComputeAndVerifySchedule(20, graph());
+  ComputeAndVerifySchedule(20);
 }
 
 
@@ -1882,7 +1885,7 @@ TARGET_TEST_F(SchedulerTest, LoopedFloatingDiamond3) {
 
   graph()->SetEnd(end);
 
-  ComputeAndVerifySchedule(28, graph());
+  ComputeAndVerifySchedule(28);
 }
 
 
@@ -1916,7 +1919,7 @@ TARGET_TEST_F(SchedulerTest, PhisPushedDownToDifferentBranches) {
 
   graph()->SetEnd(end);
 
-  ComputeAndVerifySchedule(24, graph());
+  ComputeAndVerifySchedule(24);
 }
 
 
@@ -1937,10 +1940,10 @@ TARGET_TEST_F(SchedulerTest, BranchHintTrue) {
 
   graph()->SetEnd(end);
 
-  Schedule* schedule = ComputeAndVerifySchedule(13, graph());
+  Schedule* schedule = ComputeAndVerifySchedule(13);
   // Make sure the false block is marked as deferred.
-  CHECK(!schedule->block(t)->deferred());
-  CHECK(schedule->block(f)->deferred());
+  EXPECT_FALSE(schedule->block(t)->deferred());
+  EXPECT_TRUE(schedule->block(f)->deferred());
 }
 
 
@@ -1961,10 +1964,38 @@ TARGET_TEST_F(SchedulerTest, BranchHintFalse) {
 
   graph()->SetEnd(end);
 
-  Schedule* schedule = ComputeAndVerifySchedule(13, graph());
+  Schedule* schedule = ComputeAndVerifySchedule(13);
   // Make sure the true block is marked as deferred.
-  CHECK(schedule->block(t)->deferred());
-  CHECK(!schedule->block(f)->deferred());
+  EXPECT_TRUE(schedule->block(t)->deferred());
+  EXPECT_FALSE(schedule->block(f)->deferred());
+}
+
+
+TARGET_TEST_F(SchedulerTest, CallException) {
+  Node* start = graph()->NewNode(common()->Start(1));
+  graph()->SetStart(start);
+
+  Node* p0 = graph()->NewNode(common()->Parameter(0), start);
+  Node* c1 = graph()->NewNode(&kMockCall, start);
+  Node* ok1 = graph()->NewNode(common()->IfSuccess(), c1);
+  Node* ex1 = graph()->NewNode(common()->IfException(), c1);
+  Node* c2 = graph()->NewNode(&kMockCall, ok1);
+  Node* ok2 = graph()->NewNode(common()->IfSuccess(), c2);
+  Node* ex2 = graph()->NewNode(common()->IfException(), c2);
+  Node* hdl = graph()->NewNode(common()->Merge(2), ex1, ex2);
+  Node* m = graph()->NewNode(common()->Merge(2), ok2, hdl);
+  Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), c2, p0, m);
+  Node* ret = graph()->NewNode(common()->Return(), phi, start, m);
+  Node* end = graph()->NewNode(common()->End(), ret);
+
+  graph()->SetEnd(end);
+
+  Schedule* schedule = ComputeAndVerifySchedule(17);
+  // Make sure the exception blocks as well as the handler are deferred.
+  EXPECT_TRUE(schedule->block(ex1)->deferred());
+  EXPECT_TRUE(schedule->block(ex2)->deferred());
+  EXPECT_TRUE(schedule->block(hdl)->deferred());
+  EXPECT_FALSE(schedule->block(m)->deferred());
 }
 
 
@@ -1987,7 +2018,7 @@ TARGET_TEST_F(SchedulerTest, Switch) {
 
   graph()->SetEnd(end);
 
-  ComputeAndVerifySchedule(16, graph());
+  ComputeAndVerifySchedule(16);
 }
 
 
@@ -2010,7 +2041,7 @@ TARGET_TEST_F(SchedulerTest, FloatingSwitch) {
 
   graph()->SetEnd(end);
 
-  ComputeAndVerifySchedule(16, graph());
+  ComputeAndVerifySchedule(16);
 }
 
 }  // namespace compiler
index 3892412..f8f9561 100644 (file)
@@ -119,39 +119,6 @@ const double kNaNs[] = {-std::numeric_limits<double>::quiet_NaN(),
 
 
 // -----------------------------------------------------------------------------
-// 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
 
 
index 6807930..a5dad5a 100644 (file)
@@ -38,7 +38,6 @@ const PureOperator kPureOperators[] = {
     &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),
diff --git a/deps/v8/test/unittests/compiler/state-values-utils-unittest.cc b/deps/v8/test/unittests/compiler/state-values-utils-unittest.cc
new file mode 100644 (file)
index 0000000..e6f4701
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright 2014 the V8 project 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/state-values-utils.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "test/unittests/test-utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class StateValuesIteratorTest : public GraphTest {
+ public:
+  StateValuesIteratorTest() : GraphTest(3) {}
+
+  Node* StateValuesFromVector(NodeVector* nodes) {
+    int count = static_cast<int>(nodes->size());
+    return graph()->NewNode(common()->StateValues(count), count,
+                            count == 0 ? nullptr : &(nodes->front()));
+  }
+};
+
+
+TEST_F(StateValuesIteratorTest, SimpleIteration) {
+  NodeVector inputs(zone());
+  const int count = 10;
+  for (int i = 0; i < count; i++) {
+    inputs.push_back(Int32Constant(i));
+  }
+  Node* state_values = StateValuesFromVector(&inputs);
+  int i = 0;
+  for (StateValuesAccess::TypedNode node : StateValuesAccess(state_values)) {
+    EXPECT_THAT(node.node, IsInt32Constant(i));
+    i++;
+  }
+  EXPECT_EQ(count, i);
+}
+
+
+TEST_F(StateValuesIteratorTest, EmptyIteration) {
+  NodeVector inputs(zone());
+  Node* state_values = StateValuesFromVector(&inputs);
+  for (auto node : StateValuesAccess(state_values)) {
+    USE(node);
+    FAIL();
+  }
+}
+
+
+TEST_F(StateValuesIteratorTest, NestedIteration) {
+  NodeVector inputs(zone());
+  int count = 0;
+  for (int i = 0; i < 8; i++) {
+    if (i == 2) {
+      // Single nested in index 2.
+      NodeVector nested_inputs(zone());
+      for (int j = 0; j < 8; j++) {
+        nested_inputs.push_back(Int32Constant(count++));
+      }
+      inputs.push_back(StateValuesFromVector(&nested_inputs));
+    } else if (i == 5) {
+      // Double nested at index 5.
+      NodeVector nested_inputs(zone());
+      for (int j = 0; j < 8; j++) {
+        if (j == 7) {
+          NodeVector doubly_nested_inputs(zone());
+          for (int k = 0; k < 2; k++) {
+            doubly_nested_inputs.push_back(Int32Constant(count++));
+          }
+          nested_inputs.push_back(StateValuesFromVector(&doubly_nested_inputs));
+        } else {
+          nested_inputs.push_back(Int32Constant(count++));
+        }
+      }
+      inputs.push_back(StateValuesFromVector(&nested_inputs));
+    } else {
+      inputs.push_back(Int32Constant(count++));
+    }
+  }
+  Node* state_values = StateValuesFromVector(&inputs);
+  int i = 0;
+  for (StateValuesAccess::TypedNode node : StateValuesAccess(state_values)) {
+    EXPECT_THAT(node.node, IsInt32Constant(i));
+    i++;
+  }
+  EXPECT_EQ(count, i);
+}
+
+
+TEST_F(StateValuesIteratorTest, TreeFromVector) {
+  int sizes[] = {0, 1, 2, 100, 5000, 30000};
+  TRACED_FOREACH(int, count, sizes) {
+    JSOperatorBuilder javascript(zone());
+    MachineOperatorBuilder machine(zone());
+    JSGraph jsgraph(isolate(), graph(), common(), &javascript, &machine);
+
+    // Generate the input vector.
+    NodeVector inputs(zone());
+    for (int i = 0; i < count; i++) {
+      inputs.push_back(Int32Constant(i));
+    }
+
+    // Build the tree.
+    StateValuesCache builder(&jsgraph);
+    Node* values_node = builder.GetNodeForValues(
+        inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size());
+
+    // Check the tree contents with vector.
+    int i = 0;
+    for (StateValuesAccess::TypedNode node : StateValuesAccess(values_node)) {
+      EXPECT_THAT(node.node, IsInt32Constant(i));
+      i++;
+    }
+    EXPECT_EQ(inputs.size(), static_cast<size_t>(i));
+  }
+}
+
+
+TEST_F(StateValuesIteratorTest, BuildTreeIdentical) {
+  int sizes[] = {0, 1, 2, 100, 5000, 30000};
+  TRACED_FOREACH(int, count, sizes) {
+    JSOperatorBuilder javascript(zone());
+    MachineOperatorBuilder machine(zone());
+    JSGraph jsgraph(isolate(), graph(), common(), &javascript, &machine);
+
+    // Generate the input vector.
+    NodeVector inputs(zone());
+    for (int i = 0; i < count; i++) {
+      inputs.push_back(Int32Constant(i));
+    }
+
+    // Build two trees from the same data.
+    StateValuesCache builder(&jsgraph);
+    Node* node1 = builder.GetNodeForValues(
+        inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size());
+    Node* node2 = builder.GetNodeForValues(
+        inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size());
+
+    // The trees should be equal since the data was the same.
+    EXPECT_EQ(node1, node2);
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
index 1f374c0..a83deaf 100644 (file)
@@ -1030,6 +1030,25 @@ TEST_F(InstructionSelectorTest, Float64BinopArithmetic) {
 // Miscellaneous.
 
 
+TEST_F(InstructionSelectorTest, Uint64LessThanWithLoadAndLoadStackPointer) {
+  StreamBuilder m(this, kMachBool);
+  Node* const sl = m.Load(
+      kMachPtr,
+      m.ExternalConstant(ExternalReference::address_of_stack_limit(isolate())));
+  Node* const sp = m.LoadStackPointer();
+  Node* const n = m.Uint64LessThan(sl, sp);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64StackCheck, s[0]->arch_opcode());
+  ASSERT_EQ(0U, s[0]->InputCount());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kUnsignedGreaterThan, s[0]->flags_condition());
+}
+
+
 TEST_F(InstructionSelectorTest, Word64ShlWithChangeInt32ToInt64) {
   TRACED_FORRANGE(int64_t, x, 32, 63) {
     StreamBuilder m(this, kMachInt64, kMachInt32);
@@ -1127,6 +1146,21 @@ TEST_F(InstructionSelectorTest, Word32AndWith0xffff) {
   }
 }
 
+
+TEST_F(InstructionSelectorTest, Word32Clz) {
+  StreamBuilder m(this, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Word32Clz(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lzcnt32, 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()));
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 2076e60..ed33259 100644 (file)
@@ -168,7 +168,7 @@ TEST_F(GCIdleTimeHandlerTest, DoScavengeHighScavengeSpeed) {
 
 
 TEST_F(GCIdleTimeHandlerTest, ShouldDoMarkCompact) {
-  size_t idle_time_in_ms = 16;
+  size_t idle_time_in_ms = GCIdleTimeHandler::kMaxScheduledIdleTime;
   EXPECT_TRUE(GCIdleTimeHandler::ShouldDoMarkCompact(idle_time_in_ms, 0, 0));
 }
 
@@ -440,5 +440,55 @@ TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeDoNothingButStartIdleRound) {
   EXPECT_EQ(DO_NOTHING, action.type);
 }
 
+
+TEST_F(GCIdleTimeHandlerTest, KeepDoingDoNothingWithZeroIdleTime) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  for (int i = 0; i < GCIdleTimeHandler::kMaxNoProgressIdleTimesPerIdleRound;
+       i++) {
+    GCIdleTimeAction action = handler()->Compute(0, heap_state);
+    EXPECT_EQ(DO_NOTHING, action.type);
+  }
+  // Should still return DO_NOTHING if we have been given 0 deadline yet.
+  GCIdleTimeAction action = handler()->Compute(0, heap_state);
+  EXPECT_EQ(DO_NOTHING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnSweeping) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+
+  // Simulate sweeping being in-progress but not complete.
+  heap_state.incremental_marking_stopped = true;
+  heap_state.can_start_incremental_marking = false;
+  heap_state.sweeping_in_progress = true;
+  double idle_time_ms = 10.0;
+  for (int i = 0; i < GCIdleTimeHandler::kMaxNoProgressIdleTimesPerIdleRound;
+       i++) {
+    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+    EXPECT_EQ(DO_NOTHING, action.type);
+  }
+  // We should return DONE after not making progress for some time.
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DONE, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnIncrementalMarking) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+
+  // Simulate incremental marking stopped and not eligible to start.
+  heap_state.incremental_marking_stopped = true;
+  heap_state.can_start_incremental_marking = false;
+  double idle_time_ms = 10.0;
+  for (int i = 0; i < GCIdleTimeHandler::kMaxNoProgressIdleTimesPerIdleRound;
+       i++) {
+    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+    EXPECT_EQ(DO_NOTHING, action.type);
+  }
+  // We should return DONE after not making progress for some time.
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DONE, action.type);
+}
+
 }  // namespace internal
 }  // namespace v8
index a12d5e7..2ed05b8 100644 (file)
@@ -57,6 +57,7 @@
         'compiler/js-intrinsic-lowering-unittest.cc',
         'compiler/js-operator-unittest.cc',
         'compiler/js-typed-lowering-unittest.cc',
+        'compiler/liveness-analyzer-unittest.cc',
         'compiler/load-elimination-unittest.cc',
         'compiler/loop-peeling-unittest.cc',
         'compiler/machine-operator-reducer-unittest.cc',
@@ -74,6 +75,7 @@
         'compiler/scheduler-unittest.cc',
         'compiler/simplified-operator-reducer-unittest.cc',
         'compiler/simplified-operator-unittest.cc',
+        'compiler/state-values-utils-unittest.cc',
         'compiler/typer-unittest.cc',
         'compiler/value-numbering-reducer-unittest.cc',
         'compiler/zone-pool-unittest.cc',
index 7c4c2e2..5cf2bd5 100644 (file)
@@ -39,7 +39,7 @@ PASS Array.prototype.length is 6
 PASS Function.prototype.length is 0
 PASS String.prototype.length is 0
 PASS delete Array.prototype.length is false
-PASS delete Function.prototype.length is false
+PASS delete Function.prototype.length is true
 PASS delete String.prototype.length is false
 PASS foundArrayPrototypeLength is false
 PASS foundFunctionPrototypeLength is false
index 4eb888c..4835700 100644 (file)
@@ -43,7 +43,7 @@ shouldBe("String.prototype.length","0");
 
 // check DontDelete
 shouldBe("delete Array.prototype.length","false");
-shouldBe("delete Function.prototype.length","false");
+shouldBe("delete Function.prototype.length","true");
 shouldBe("delete String.prototype.length","false");
 
 // check DontEnum
index fb8d77d..d8c6864 100644 (file)
 ['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.
+['dcheck_always_on == True and (arch == arm or arch == arm64)', {
+  # Doesn't work with gcc 4.6 on arm or arm64 for some reason.
   'reentrant-caching': [SKIP],
-}],  # 'dcheck_always_on == True and arch == arm64'
+}],  # 'dcheck_always_on == True and (arch == arm or arch == arm64)'
 
 
 ##############################################################################
diff --git a/deps/v8/testing/commit_queue/OWNERS b/deps/v8/testing/commit_queue/OWNERS
new file mode 100644 (file)
index 0000000..1d89078
--- /dev/null
@@ -0,0 +1 @@
+sergiyb@chromium.org
diff --git a/deps/v8/testing/commit_queue/config.json b/deps/v8/testing/commit_queue/config.json
new file mode 100644 (file)
index 0000000..aeb3803
--- /dev/null
@@ -0,0 +1,74 @@
+{
+    "commit_burst_delay": 60,
+    "commit_user": "commit-bot@chromium.org",
+    "committer_project": "v8",
+    "cq_status_url": "https://chromium-cq-status.appspot.com",
+    "git_repo_url": "https://chromium.googlesource.com/v8/v8",
+    "hide_ref_in_committed_msg": true,
+    "max_commit_burst": 1,
+    "project_bases_legacy_from_git_repo_url": true,
+    "remote_branch": "refs/pending/heads/master",
+    "rietveld_url": "https://codereview.chromium.org",
+    "rietveld_user": "commit-bot@chromium.org",
+    "skip_throttle_users": [
+        "commit-bot@chromium.org"
+    ],
+    "tree_status_url": "https://v8-status.appspot.com",
+    "verifiers_no_patch": {
+        "experimental_try_job_verifier": {},
+        "reviewer_lgtm_verifier": {},
+        "tree_status_verifier": {},
+        "try_job_verifier": {
+            "launched": {
+                "tryserver.v8": {
+                    "v8_android_arm_compile_rel": [
+                        "defaulttests"
+                    ],
+                    "v8_linux64_asan_rel": [
+                        "defaulttests"
+                    ],
+                    "v8_linux64_rel": [
+                        "defaulttests"
+                    ],
+                    "v8_linux_arm64_rel": [
+                        "defaulttests"
+                    ],
+                    "v8_linux_arm_rel": [
+                        "defaulttests"
+                    ],
+                    "v8_linux_chromium_gn_rel": [
+                        "defaulttests"
+                    ],
+                    "v8_linux_dbg": [
+                        "defaulttests"
+                    ],
+                    "v8_linux_gcc_compile_rel": [
+                        "defaulttests"
+                    ],
+                    "v8_linux_nodcheck_rel": [
+                        "defaulttests"
+                    ],
+                    "v8_linux_rel": [
+                        "defaulttests"
+                    ],
+                    "v8_mac_rel": [
+                        "defaulttests"
+                    ],
+                    "v8_presubmit": [
+                        "defaulttests"
+                    ],
+                    "v8_win64_rel": [
+                        "defaulttests"
+                    ],
+                    "v8_win_compile_dbg": [
+                        "defaulttests"
+                    ],
+                    "v8_win_rel": [
+                        "defaulttests"
+                    ]
+                }
+            },
+            "triggered": {}
+        }
+    }
+}
index 89a7dee..fcc70a5 100755 (executable)
@@ -11,7 +11,6 @@ import sys
 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):
@@ -32,7 +31,7 @@ def FindLists(filename):
     for line in f:
       if mode == "SEARCHING":
         match = LISTHEAD.match(line)
-        if match and match.group(1) not in BLACKLIST:
+        if match:
           mode = "APPENDING"
           current_list.append(line)
       else:
index 8e8a243..0597d09 100755 (executable)
@@ -31,7 +31,7 @@ single_core() {
 
 all_cores() {
   echo "Reactivating all CPU cores"
-  for (( i=2; i<=$MAXID; i++ )); do
+  for (( i=1; i<=$MAXID; i++ )); do
     echo 1 > $CPUPATH/cpu$i/online
   done
 }
index 386d4a9..bced8d4 100644 (file)
@@ -8,7 +8,7 @@ import os
 import sys
 
 DECLARE_FILE = "src/assembler.h"
-REGISTER_FILE = "src/serialize.cc"
+REGISTER_FILE = "src/snapshot/serialize.cc"
 DECLARE_RE = re.compile("\s*static ExternalReference ([^(]+)\(")
 REGISTER_RE = re.compile("\s*Add\(ExternalReference::([^(]+)\(")
 
index 7f08ee2..effec7b 100644 (file)
       'sources': [
         '<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
         '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
-        '../../src/snapshot-empty.cc',
+        '../../src/snapshot/snapshot-empty.cc',
       ],
       'conditions': [
         ['want_separate_host_toolset==1', {
             '../..',
           ],
           'sources': [
-            '../../src/natives-external.cc',
-            '../../src/snapshot-external.cc',
+            '../../src/snapshot/natives-external.cc',
+            '../../src/snapshot/snapshot-external.cc',
           ],
           'actions': [
             {
         '../../src/compiler/frame.h',
         '../../src/compiler/gap-resolver.cc',
         '../../src/compiler/gap-resolver.h',
-        '../../src/compiler/generic-algorithm.h',
         '../../src/compiler/graph-builder.h',
-        '../../src/compiler/graph-inl.h',
         '../../src/compiler/graph-reducer.cc',
         '../../src/compiler/graph-reducer.h',
         '../../src/compiler/graph-replay.cc',
         '../../src/compiler/js-intrinsic-lowering.h',
         '../../src/compiler/js-operator.cc',
         '../../src/compiler/js-operator.h',
+        '../../src/compiler/js-type-feedback.cc',
+        '../../src/compiler/js-type-feedback.h',
         '../../src/compiler/js-typed-lowering.cc',
         '../../src/compiler/js-typed-lowering.h',
         '../../src/compiler/jump-threading.cc',
         '../../src/compiler/linkage-impl.h',
         '../../src/compiler/linkage.cc',
         '../../src/compiler/linkage.h',
+        '../../src/compiler/liveness-analyzer.cc',
+        '../../src/compiler/liveness-analyzer.h',
         '../../src/compiler/load-elimination.cc',
         '../../src/compiler/load-elimination.h',
         '../../src/compiler/loop-analysis.cc',
         '../../src/compiler/node-cache.h',
         '../../src/compiler/node-marker.cc',
         '../../src/compiler/node-marker.h',
+        '../../src/compiler/node-matchers.cc',
         '../../src/compiler/node-matchers.h',
         '../../src/compiler/node-properties.cc',
         '../../src/compiler/node-properties.h',
         '../../src/compiler/simplified-operator.h',
         '../../src/compiler/source-position.cc',
         '../../src/compiler/source-position.h',
+        '../../src/compiler/state-values-utils.cc',
+        '../../src/compiler/state-values-utils.h',
         '../../src/compiler/typer.cc',
         '../../src/compiler/typer.h',
         '../../src/compiler/value-numbering-reducer.cc',
         '../../src/modules.cc',
         '../../src/modules.h',
         '../../src/msan.h',
-        '../../src/natives.h',
         '../../src/objects-debug.cc',
         '../../src/objects-inl.h',
         '../../src/objects-printer.cc',
         '../../src/ostreams.h',
         '../../src/parser.cc',
         '../../src/parser.h',
+        '../../src/pending-compilation-error-handler.cc',
+        '../../src/pending-compilation-error-handler.h',
         '../../src/perf-jit.cc',
         '../../src/perf-jit.h',
         '../../src/preparse-data-format.h',
         '../../src/scopeinfo.h',
         '../../src/scopes.cc',
         '../../src/scopes.h',
-        '../../src/serialize.cc',
-        '../../src/serialize.h',
         '../../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/snapshot/natives.h',
+        '../../src/snapshot/serialize.cc',
+        '../../src/snapshot/serialize.h',
+        '../../src/snapshot/snapshot.h',
+        '../../src/snapshot/snapshot-common.cc',
+        '../../src/snapshot/snapshot-source-sink.cc',
+        '../../src/snapshot/snapshot-source-sink.h',
         '../../src/string-builder.cc',
         '../../src/string-builder.h',
         '../../src/string-search.cc',
         '../../src/string-search.h',
         '../../src/string-stream.cc',
         '../../src/string-stream.h',
+        '../../src/strings-storage.cc',
+        '../../src/strings-storage.h',
         '../../src/strtod.cc',
         '../../src/strtod.h',
         '../../src/ic/stub-cache.cc',
               ['nacl_target_arch=="none"', {
                 'link_settings': {
                   'libraries': [
+                    '-ldl',
                     '-lrt'
                   ],
                 },
             'sources': [
               '../../src/base/platform/platform-posix.cc'
             ],
+            'link_settings': {
+              'libraries': [
+                '-ldl'
+              ]
+            },
             'conditions': [
               ['host_os=="mac"', {
                 'target_conditions': [
           '../../src/array.js',
           '../../src/string.js',
           '../../src/uri.js',
-          '../../src/third_party/fdlibm/fdlibm.js',
           '../../src/math.js',
+          '../../src/third_party/fdlibm/fdlibm.js',
           '../../src/date.js',
           '../../src/regexp.js',
           '../../src/arraybuffer.js',
           '../../src/debug-debugger.js',
           '../../src/mirror-debugger.js',
           '../../src/liveedit-debugger.js',
+          '../../src/templates.js',
           '../../src/macros.py',
         ],
         'experimental_library_files': [
           '../../src/macros.py',
           '../../src/proxy.js',
           '../../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-templates.js',
-          '../../src/harmony-regexp.js'
+          '../../src/harmony-regexp.js',
+          '../../src/harmony-reflect.js'
         ],
         'libraries_bin_file': '<(SHARED_INTERMEDIATE_DIR)/libraries.bin',
         'libraries_experimental_bin_file': '<(SHARED_INTERMEDIATE_DIR)/libraries-experimental.bin',
         '../..',
       ],
       'sources': [
-        '../../src/mksnapshot.cc',
+        '../../src/snapshot/mksnapshot.cc',
       ],
       'conditions': [
         ['v8_enable_i18n_support==1', {
index 621ed5a..327e7d9 100755 (executable)
@@ -247,7 +247,7 @@ HEADER_TEMPLATE = """\
 // javascript source files or the GYP script.
 
 #include "src/v8.h"
-#include "src/natives.h"
+#include "src/snapshot/natives.h"
 #include "src/utils.h"
 
 namespace v8 {
index 409b396..f9bea4a 100755 (executable)
@@ -711,6 +711,23 @@ class LibraryRepo(object):
     self.names = set()
     self.ticks = {}
 
+
+  def HasDynamicSymbols(self, filename):
+    if filename.endswith(".ko"): return False
+    process = subprocess.Popen(
+      "%s -h %s" % (OBJDUMP_BIN, filename),
+      shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    pipe = process.stdout
+    try:
+      for line in pipe:
+        match = OBJDUMP_SECTION_HEADER_RE.match(line)
+        if match and match.group(1) == 'dynsym': return True
+    finally:
+      pipe.close()
+    assert process.wait() == 0, "Failed to objdump -h %s" % filename
+    return False
+
+
   def Load(self, mmap_info, code_map, options):
     # Skip kernel mmaps when requested using the fact that their tid
     # is 0.
@@ -730,10 +747,10 @@ class LibraryRepo(object):
     # Unfortunately, section headers span two lines, so we have to
     # keep the just seen section name (from the first line in each
     # section header) in the after_section variable.
-    if mmap_info.filename.endswith(".ko"):
-      dynamic_symbols = ""
-    else:
+    if self.HasDynamicSymbols(mmap_info.filename):
       dynamic_symbols = "-T"
+    else:
+      dynamic_symbols = ""
     process = subprocess.Popen(
       "%s -h -t %s -C %s" % (OBJDUMP_BIN, dynamic_symbols, mmap_info.filename),
       shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
index 3e41bf9..3fe7359 100644 (file)
@@ -88,14 +88,16 @@ std::pair<v8::base::TimeDelta, v8::base::TimeDelta> RunBaselineParser(
   i::ScriptData* cached_data_impl = NULL;
   // First round of parsing (produce data to cache).
   {
-    CompilationInfoWithZone info(script);
-    info.MarkAsGlobal();
-    info.SetCachedData(&cached_data_impl,
-                       v8::ScriptCompiler::kProduceParserCache);
+    Zone zone;
+    ParseInfo info(&zone, script);
+    info.set_global();
+    info.set_cached_data(&cached_data_impl);
+    info.set_compile_options(v8::ScriptCompiler::kProduceParserCache);
     v8::base::ElapsedTimer timer;
     timer.Start();
     // Allow lazy parsing; otherwise we won't produce cached data.
-    bool success = Parser::ParseStatic(&info, true);
+    info.set_allow_lazy_parsing();
+    bool success = Parser::ParseStatic(&info);
     parse_time1 = timer.Elapsed();
     if (!success) {
       fprintf(stderr, "Parsing failed\n");
@@ -104,14 +106,16 @@ std::pair<v8::base::TimeDelta, v8::base::TimeDelta> RunBaselineParser(
   }
   // Second round of parsing (consume cached data).
   {
-    CompilationInfoWithZone info(script);
-    info.MarkAsGlobal();
-    info.SetCachedData(&cached_data_impl,
-                       v8::ScriptCompiler::kConsumeParserCache);
+    Zone zone;
+    ParseInfo info(&zone, script);
+    info.set_global();
+    info.set_cached_data(&cached_data_impl);
+    info.set_compile_options(v8::ScriptCompiler::kConsumeParserCache);
     v8::base::ElapsedTimer timer;
     timer.Start();
     // Allow lazy parsing; otherwise cached data won't help.
-    bool success = Parser::ParseStatic(&info, true);
+    info.set_allow_lazy_parsing();
+    bool success = Parser::ParseStatic(&info);
     parse_time2 = timer.Elapsed();
     if (!success) {
       fprintf(stderr, "Parsing failed\n");
diff --git a/deps/v8/tools/perf-to-html.py b/deps/v8/tools/perf-to-html.py
new file mode 100755 (executable)
index 0000000..63faeb1
--- /dev/null
@@ -0,0 +1,378 @@
+#!/usr/bin/env python
+# 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.
+'''
+python %prog
+
+Convert a perf trybot JSON file into a pleasing HTML page. It can read
+from standard input or via the --filename option. Examples:
+
+  cat results.json | %prog --title "ia32 results"
+  %prog -f results.json -t "ia32 results" -o results.html
+'''
+
+import commands
+import json
+import math
+from optparse import OptionParser
+import os
+import shutil
+import sys
+import tempfile
+
+PERCENT_CONSIDERED_SIGNIFICANT = 0.5
+PROBABILITY_CONSIDERED_SIGNIFICANT = 0.02
+PROBABILITY_CONSIDERED_MEANINGLESS = 0.05
+
+
+def ComputeZ(baseline_avg, baseline_sigma, mean, n):
+  if baseline_sigma == 0:
+    return 1000.0;
+  return abs((mean - baseline_avg) / (baseline_sigma / math.sqrt(n)))
+
+
+# Values from http://www.fourmilab.ch/rpkp/experiments/analysis/zCalc.html
+def ComputeProbability(z):
+  if z > 2.575829: # p 0.005: two sided < 0.01
+    return 0
+  if z > 2.326348: # p 0.010
+    return 0.01
+  if z > 2.170091: # p 0.015
+    return 0.02
+  if z > 2.053749: # p 0.020
+    return 0.03
+  if z > 1.959964: # p 0.025: two sided < 0.05
+    return 0.04
+  if z > 1.880793: # p 0.030
+    return 0.05
+  if z > 1.811910: # p 0.035
+    return 0.06
+  if z > 1.750686: # p 0.040
+    return 0.07
+  if z > 1.695397: # p 0.045
+    return 0.08
+  if z > 1.644853: # p 0.050: two sided < 0.10
+    return 0.09
+  if z > 1.281551: # p 0.100: two sided < 0.20
+    return 0.10
+  return 0.20 # two sided p >= 0.20
+
+
+class Result:
+  def __init__(self, test_name, count, hasScoreUnits, result, sigma,
+               master_result, master_sigma):
+    self.result_ = float(result)
+    self.sigma_ = float(sigma)
+    self.master_result_ = float(master_result)
+    self.master_sigma_ = float(master_sigma)
+    self.significant_ = False
+    self.notable_ = 0
+    self.percentage_string_ = ""
+    # compute notability and significance.
+    if hasScoreUnits:
+      compare_num = 100*self.result_/self.master_result_ - 100
+    else:
+      compare_num = 100*self.master_result_/self.result_ - 100
+    if abs(compare_num) > 0.1:
+      self.percentage_string_ = "%3.1f" % (compare_num)
+      z = ComputeZ(self.master_result_, self.master_sigma_, self.result_, count)
+      p = ComputeProbability(z)
+      if p < PROBABILITY_CONSIDERED_SIGNIFICANT:
+        self.significant_ = True
+      if compare_num >= PERCENT_CONSIDERED_SIGNIFICANT:
+        self.notable_ = 1
+      elif compare_num <= -PERCENT_CONSIDERED_SIGNIFICANT:
+        self.notable_ = -1
+
+  def result(self):
+    return self.result_
+
+  def sigma(self):
+    return self.sigma_
+
+  def master_result(self):
+    return self.master_result_
+
+  def master_sigma(self):
+    return self.master_sigma_
+
+  def percentage_string(self):
+    return self.percentage_string_;
+
+  def isSignificant(self):
+    return self.significant_
+
+  def isNotablyPositive(self):
+    return self.notable_ > 0
+
+  def isNotablyNegative(self):
+    return self.notable_ < 0
+
+
+class Benchmark:
+  def __init__(self, name, data):
+    self.name_ = name
+    self.tests_ = {}
+    for test in data:
+      # strip off "<name>/" prefix
+      test_name = test.split("/")[1]
+      self.appendResult(test_name, data[test])
+
+  # tests is a dictionary of Results
+  def tests(self):
+    return self.tests_
+
+  def SortedTestKeys(self):
+    keys = self.tests_.keys()
+    keys.sort()
+    t = "Total"
+    if t in keys:
+      keys.remove(t)
+      keys.append(t)
+    return keys
+
+  def name(self):
+    return self.name_
+
+  def appendResult(self, test_name, test_data):
+    with_string = test_data["result with patch   "]
+    data = with_string.split()
+    master_string = test_data["result without patch"]
+    master_data = master_string.split()
+    runs = int(test_data["runs"])
+    units = test_data["units"]
+    hasScoreUnits = units == "score"
+    self.tests_[test_name] = Result(test_name,
+                                    runs,
+                                    hasScoreUnits,
+                                    data[0], data[2],
+                                    master_data[0], master_data[2])
+
+
+class BenchmarkRenderer:
+  def __init__(self, output_file):
+    self.print_output_ = []
+    self.output_file_ = output_file
+
+  def Print(self, str_data):
+    self.print_output_.append(str_data)
+
+  def FlushOutput(self):
+    string_data = "\n".join(self.print_output_)
+    print_output = []
+    if self.output_file_:
+      # create a file
+      with open(self.output_file_, "w") as text_file:
+        text_file.write(string_data)
+    else:
+      print(string_data)
+
+  def RenderOneBenchmark(self, benchmark):
+    self.Print("<h2>")
+    self.Print("<a name=\"" + benchmark.name() + "\">")
+    self.Print(benchmark.name() + "</a> <a href=\"#top\">(top)</a>")
+    self.Print("</h2>");
+    self.Print("<table class=\"benchmark\">")
+    self.Print("<thead>")
+    self.Print("  <th>Test</th>")
+    self.Print("  <th>Result</th>")
+    self.Print("  <th>Master</th>")
+    self.Print("  <th>%</th>")
+    self.Print("</thead>")
+    self.Print("<tbody>")
+    tests = benchmark.tests()
+    for test in benchmark.SortedTestKeys():
+      t = tests[test]
+      self.Print("  <tr>")
+      self.Print("    <td>" + test + "</td>")
+      self.Print("    <td>" + str(t.result()) + "</td>")
+      self.Print("    <td>" + str(t.master_result()) + "</td>")
+      t = tests[test]
+      res = t.percentage_string()
+      if t.isSignificant():
+        res = self.bold(res)
+      if t.isNotablyPositive():
+        res = self.green(res)
+      elif t.isNotablyNegative():
+        res = self.red(res)
+      self.Print("    <td>" + res + "</td>")
+      self.Print("  </tr>")
+    self.Print("</tbody>")
+    self.Print("</table>")
+
+  def ProcessJSONData(self, data, title):
+    self.Print("<h1>" + title + "</h1>")
+    self.Print("<ul>")
+    for benchmark in data:
+     if benchmark != "errors":
+       self.Print("<li><a href=\"#" + benchmark + "\">" + benchmark + "</a></li>")
+    self.Print("</ul>")
+    for benchmark in data:
+      if benchmark != "errors":
+        benchmark_object = Benchmark(benchmark, data[benchmark])
+        self.RenderOneBenchmark(benchmark_object)
+
+  def bold(self, data):
+    return "<b>" + data + "</b>"
+
+  def red(self, data):
+    return "<font color=\"red\">" + data + "</font>"
+
+
+  def green(self, data):
+    return "<font color=\"green\">" + data + "</font>"
+
+  def PrintHeader(self):
+    data = """<html>
+<head>
+<title>Output</title>
+<style type="text/css">
+/*
+Style inspired by Andy Ferra's gist at https://gist.github.com/andyferra/2554919
+*/
+body {
+  font-family: Helvetica, arial, sans-serif;
+  font-size: 14px;
+  line-height: 1.6;
+  padding-top: 10px;
+  padding-bottom: 10px;
+  background-color: white;
+  padding: 30px;
+}
+h1, h2, h3, h4, h5, h6 {
+  margin: 20px 0 10px;
+  padding: 0;
+  font-weight: bold;
+  -webkit-font-smoothing: antialiased;
+  cursor: text;
+  position: relative;
+}
+h1 {
+  font-size: 28px;
+  color: black;
+}
+
+h2 {
+  font-size: 24px;
+  border-bottom: 1px solid #cccccc;
+  color: black;
+}
+
+h3 {
+  font-size: 18px;
+}
+
+h4 {
+  font-size: 16px;
+}
+
+h5 {
+  font-size: 14px;
+}
+
+h6 {
+  color: #777777;
+  font-size: 14px;
+}
+
+p, blockquote, ul, ol, dl, li, table, pre {
+  margin: 15px 0;
+}
+
+li p.first {
+  display: inline-block;
+}
+
+ul, ol {
+  padding-left: 30px;
+}
+
+ul :first-child, ol :first-child {
+  margin-top: 0;
+}
+
+ul :last-child, ol :last-child {
+  margin-bottom: 0;
+}
+
+table {
+  padding: 0;
+}
+
+table tr {
+  border-top: 1px solid #cccccc;
+  background-color: white;
+  margin: 0;
+  padding: 0;
+}
+
+table tr:nth-child(2n) {
+  background-color: #f8f8f8;
+}
+
+table tr th {
+  font-weight: bold;
+  border: 1px solid #cccccc;
+  text-align: left;
+  margin: 0;
+  padding: 6px 13px;
+}
+table tr td {
+  border: 1px solid #cccccc;
+  text-align: left;
+  margin: 0;
+  padding: 6px 13px;
+}
+table tr th :first-child, table tr td :first-child {
+  margin-top: 0;
+}
+table tr th :last-child, table tr td :last-child {
+  margin-bottom: 0;
+}
+</style>
+</head>
+<body>
+"""
+    self.Print(data)
+
+  def PrintFooter(self):
+    data = """</body>
+</html>
+"""
+    self.Print(data)
+
+
+def Render(opts, args):
+  if opts.filename:
+    with open(opts.filename) as json_data:
+      data = json.load(json_data)
+  else:
+    # load data from stdin
+    data = json.load(sys.stdin)
+
+  if opts.title:
+    title = opts.title
+  elif opts.filename:
+    title = opts.filename
+  else:
+    title = "Benchmark results"
+  renderer = BenchmarkRenderer(opts.output)
+  renderer.PrintHeader()
+  renderer.ProcessJSONData(data, title)
+  renderer.PrintFooter()
+  renderer.FlushOutput()
+
+
+if __name__ == '__main__':
+  parser = OptionParser(usage=__doc__)
+  parser.add_option("-f", "--filename", dest="filename",
+                    help="Specifies the filename for the JSON results "
+                         "rather than reading from stdin.")
+  parser.add_option("-t", "--title", dest="title",
+                    help="Optional title of the web page.")
+  parser.add_option("-o", "--output", dest="output",
+                    help="Write html output to this file rather than stdout.")
+
+  (opts, args) = parser.parse_args()
+  Render(opts, args)
index 121288f..aba5cba 100755 (executable)
@@ -34,15 +34,15 @@ import sys
 import urllib
 
 from common_includes import *
-import push_to_candidates
+import create_release
 
 
 class Preparation(Step):
   MESSAGE = "Preparation."
 
   def RunStep(self):
-    self.InitialEnvironmentChecks(self.default_cwd)
-    self.CommonPrepare()
+    # Fetch unfetched revisions.
+    self.vc.Fetch()
 
 
 class FetchCandidate(Step):
@@ -67,11 +67,11 @@ class LastReleaseBailout(Step):
       return True
 
 
-class PushToCandidates(Step):
-  MESSAGE = "Pushing to candidates if specified."
+class CreateRelease(Step):
+  MESSAGE = "Creating release if specified."
 
   def RunStep(self):
-    print "Pushing candidate %s to candidates." % self["candidate"]
+    print "Creating release for %s." % self["candidate"]
 
     args = [
       "--author", self._options.author,
@@ -83,16 +83,15 @@ class PushToCandidates(Step):
     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_candidates.PushToCandidates().Run, args)
+          create_release.CreateRelease().Run, args)
 
 
 class AutoPush(ScriptsBase):
   def _PrepareOptions(self, parser):
     parser.add_argument("-p", "--push",
-                        help="Push to candidates. Dry run if unspecified.",
+                        help="Create release. Dry run if unspecified.",
                         default=False, action="store_true")
 
   def _ProcessOptions(self, options):
@@ -112,7 +111,7 @@ class AutoPush(ScriptsBase):
       Preparation,
       FetchCandidate,
       LastReleaseBailout,
-      PushToCandidates,
+      CreateRelease,
     ]
 
 
index 315a4bc..f7692cf 100755 (executable)
@@ -42,8 +42,11 @@ class DetectLastRoll(Step):
   MESSAGE = "Detect commit ID of the last Chromium roll."
 
   def RunStep(self):
-    # The revision that should be rolled.
-    latest_release = self.GetLatestRelease()
+    # The revision that should be rolled. Check for the latest of the most
+    # recent releases based on commit timestamp.
+    revisions = self.GetRecentReleases(
+        max_age=self._options.max_age * DAY_IN_SECONDS)
+    assert revisions, "Didn't find any recent release."
 
     # Interpret the DEPS file to retrieve the v8 revision.
     # TODO(machenbach): This should be part or the roll-deps api of
@@ -53,39 +56,27 @@ class DetectLastRoll(Step):
 
     # The revision rolled last.
     self["last_roll"] = vars['v8_revision']
-
-    # TODO(machenbach): It is possible that the auto-push script made a new
-    # fast-forward release (e.g. 4.2.3) while somebody patches the last
-    # candidate (e.g. 4.2.2.1). In this case, the auto-roller would pick
-    # the fast-forward release. Should there be a way to prioritize the
-    # patched version?
-
-    if latest_release == self["last_roll"]:
-      # We always try to roll if the latest revision is not the revision in
-      # chromium.
+    last_version = self.GetVersionTag(self["last_roll"])
+    assert last_version, "The last rolled v8 revision is not tagged."
+
+    # There must be some progress between the last roll and the new candidate
+    # revision (i.e. we don't go backwards). The revisions are ordered newest
+    # to oldest. It is possible that the newest timestamp has no progress
+    # compared to the last roll, i.e. if the newest release is a cherry-pick
+    # on a release branch. Then we look further.
+    for revision in revisions:
+      version = self.GetVersionTag(revision)
+      assert version, "Internal error. All recent releases should have a tag"
+
+      if SortingKey(last_version) < SortingKey(version):
+        self["roll"] = revision
+        break
+    else:
       print("There is no newer v8 revision than the one in Chromium (%s)."
             % self["last_roll"])
       return True
 
 
-class CheckClusterFuzz(Step):
-  MESSAGE = "Check ClusterFuzz api for new problems."
-
-  def RunStep(self):
-    if not os.path.exists(self.Config("CLUSTERFUZZ_API_KEY_FILE")):
-      print "Skipping ClusterFuzz check. No api key file found."
-      return False
-    api_key = FileToText(self.Config("CLUSTERFUZZ_API_KEY_FILE"))
-    # Check for open, reproducible issues that have no associated bug.
-    result = self._side_effect_handler.ReadClusterFuzzAPI(
-        api_key, job_type="linux_asan_d8_dbg", reproducible="True",
-        open="True", bug_information="",
-        revision_greater_or_equal=str(self["last_push"]))
-    if result:
-      print "Stop due to pending ClusterFuzz issues."
-      return True
-
-
 class RollChromium(Step):
   MESSAGE = "Roll V8 into Chromium."
 
@@ -97,12 +88,12 @@ class RollChromium(Step):
         "--chromium", self._options.chromium,
         "--last-roll", self["last_roll"],
         "--use-commit-queue",
+        self["roll"],
       ]
       if self._options.sheriff:
-        args.extend([
-            "--sheriff", "--googlers-mapping", self._options.googlers_mapping])
+        args.append("--sheriff")
       if self._options.dry_run:
-        args.extend(["--dry-run"])
+        args.append("--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)
@@ -113,6 +104,8 @@ class AutoRoll(ScriptsBase):
     parser.add_argument("-c", "--chromium", required=True,
                         help=("The path to your Chromium src/ "
                               "directory to automate the V8 roll."))
+    parser.add_argument("--max-age", default=3, type=int,
+                        help="Maximum age in days of the latest release.")
     parser.add_argument("--roll", help="Call Chromium roll script.",
                         default=False, action="store_true")
 
@@ -128,14 +121,12 @@ class AutoRoll(ScriptsBase):
   def _Config(self):
     return {
       "PERSISTFILE_BASENAME": "/tmp/v8-auto-roll-tempfile",
-      "CLUSTERFUZZ_API_KEY_FILE": ".cf_api_key",
     }
 
   def _Steps(self):
     return [
       CheckActiveRoll,
       DetectLastRoll,
-      CheckClusterFuzz,
       RollChromium,
     ]
 
index 8a3ff4a..de0a569 100755 (executable)
@@ -14,36 +14,31 @@ ROLL_SUMMARY = ("Summary of changes available at:\n"
                 "https://chromium.googlesource.com/v8/v8/+log/%s..%s")
 
 
+ISSUE_MSG = (
+"""Please follow these instructions for assigning/CC'ing issues:
+https://code.google.com/p/v8-wiki/wiki/TriagingIssues""")
+
 class Preparation(Step):
   MESSAGE = "Preparation."
 
   def RunStep(self):
     # Update v8 remote tracking branches.
     self.GitFetchOrigin()
+    self.Git("fetch origin +refs/tags/*:refs/tags/*")
 
 
-class DetectLastPush(Step):
-  MESSAGE = "Detect commit ID of last release."
+class PrepareRollCandidate(Step):
+  MESSAGE = "Robustness checks of the roll candidate."
 
   def RunStep(self):
-    # The revision that should be rolled.
-    self["last_push"] = self._options.last_push or self.GetLatestRelease()
-    self["push_title"] = self.GitLog(n=1, format="%s",
-                                     git_hash=self["last_push"])
-
-    # The master revision this release is based on.
-    self["push_base"] = self.GetLatestReleaseBase()
+    self["roll_title"] = self.GitLog(n=1, format="%s",
+                                     git_hash=self._options.roll)
 
-    # FIXME(machenbach): Manually specifying a revision doesn't work at the
-    # moment. Needs more complicated logic to find the correct push_base above.
-    # Maybe delete that parameter entirely?
-    assert not self._options.last_push
-
-    # Determine the master revision of the last roll.
+    # Make sure the last roll and the roll candidate are releases.
+    version = self.GetVersionTag(self._options.roll)
+    assert version, "The revision to roll is not tagged."
     version = self.GetVersionTag(self._options.last_roll)
-    assert version
-    self["last_rolled_base"] = self.GetLatestReleaseBase(version=version)
-    assert self["last_rolled_base"]
+    assert version, "The revision used as last roll is not tagged."
 
 
 class SwitchChromium(Step):
@@ -73,7 +68,7 @@ class UpdateChromiumCheckout(Step):
     # Update v8 remotes.
     self.GitFetchOrigin()
 
-    self.GitCreateBranch("v8-roll-%s" % self["last_push"],
+    self.GitCreateBranch("v8-roll-%s" % self._options.roll,
                          cwd=self._options.chromium)
 
 
@@ -83,19 +78,18 @@ class UploadCL(Step):
   def RunStep(self):
     # Patch DEPS file.
     if self.Command(
-        "roll-dep", "v8 %s" % self["last_push"],
+        "roll-dep", "v8 %s" % self._options.roll,
         cwd=self._options.chromium) is None:
-      self.Die("Failed to create deps for %s" % self["last_push"])
+      self.Die("Failed to create deps for %s" % self._options.roll)
 
     message = []
-    message.append("Update V8 to %s." % self["push_title"].lower())
+    message.append("Update V8 to %s." % self["roll_title"].lower())
 
     message.append(
-        ROLL_SUMMARY % (self["last_rolled_base"][:8], self["push_base"][:8]))
+        ROLL_SUMMARY % (self._options.last_roll[:8], self._options.roll[:8]))
+
+    message.append(ISSUE_MSG)
 
-    if self["sheriff"]:
-      message.append("Please reply to the V8 sheriff %s in case of problems."
-          % self["sheriff"])
     message.append("TBR=%s" % self._options.reviewer)
     self.GitCommit("\n\n".join(message),
                    author=self._options.author,
@@ -108,7 +102,7 @@ class UploadCL(Step):
       print "CL uploaded."
     else:
       self.GitCheckout("master", cwd=self._options.chromium)
-      self.GitDeleteBranch("v8-roll-%s" % self["last_push"],
+      self.GitDeleteBranch("v8-roll-%s" % self._options.roll,
                            cwd=self._options.chromium)
       print "Dry run - don't upload."
 
@@ -127,8 +121,8 @@ class CleanUp(Step):
 
   def RunStep(self):
     print("Congratulations, you have successfully rolled %s into "
-          "Chromium. Please don't forget to update the v8rel spreadsheet."
-          % self["last_push"])
+          "Chromium."
+          % self._options.roll)
 
     # Clean up all temporary files.
     Command("rm", "-f %s*" % self._config["PERSISTFILE_BASENAME"])
@@ -139,10 +133,9 @@ class ChromiumRoll(ScriptsBase):
     parser.add_argument("-c", "--chromium", required=True,
                         help=("The path to your Chromium src/ "
                               "directory to automate the V8 roll."))
-    parser.add_argument("-l", "--last-push",
-                        help="The git commit ID of the last candidates push.")
     parser.add_argument("--last-roll", required=True,
                         help="The git commit ID of the last rolled version.")
+    parser.add_argument("roll", nargs=1, help="Revision to roll."),
     parser.add_argument("--use-commit-queue",
                         help="Check the CQ bit on upload.",
                         default=False, action="store_true")
@@ -155,6 +148,7 @@ class ChromiumRoll(ScriptsBase):
     options.requires_editor = False
     options.force = True
     options.manual = False
+    options.roll = options.roll[0]
     return True
 
   def _Config(self):
@@ -165,7 +159,7 @@ class ChromiumRoll(ScriptsBase):
   def _Steps(self):
     return [
       Preparation,
-      DetectLastPush,
+      PrepareRollCandidate,
       DetermineV8Sheriff,
       SwitchChromium,
       UpdateChromiumCheckout,
index bae05bc..19841a3 100644 (file)
@@ -46,9 +46,10 @@ from git_recipes import GitRecipesMixin
 from git_recipes import GitFailedException
 
 CHANGELOG_FILE = "ChangeLog"
+DAY_IN_SECONDS = 24 * 60 * 60
 PUSH_MSG_GIT_RE = re.compile(r".* \(based on (?P<git_rev>[a-fA-F0-9]+)\)$")
 PUSH_MSG_NEW_RE = re.compile(r"^Version \d+\.\d+\.\d+$")
-VERSION_FILE = os.path.join("src", "version.cc")
+VERSION_FILE = os.path.join("include", "v8-version.h")
 VERSION_RE = re.compile(r"^\d+\.\d+\.\d+(?:\.\d+)?$")
 
 # V8 base directory.
@@ -510,12 +511,12 @@ class Step(GitRecipesMixin):
     answer = self.ReadLine(default="Y")
     return answer == "" or answer == "Y" or answer == "y"
 
-  def DeleteBranch(self, name):
-    for line in self.GitBranch().splitlines():
+  def DeleteBranch(self, name, cwd=None):
+    for line in self.GitBranch(cwd=cwd).splitlines():
       if re.match(r"\*?\s*%s$" % re.escape(name), line):
         msg = "Branch %s exists, do you want to delete it?" % name
         if self.Confirm(msg):
-          self.GitDeleteBranch(name)
+          self.GitDeleteBranch(name, cwd=cwd)
           print "Branch %s deleted." % name
         else:
           msg = "Can't continue. Please delete branch %s and try again." % name
@@ -537,8 +538,8 @@ class Step(GitRecipesMixin):
     if not self.GitIsWorkdirClean():  # pragma: no cover
       self.Die("Workspace is not clean. Please commit or undo your changes.")
 
-    # Persist current branch.
-    self["current_branch"] = self.GitCurrentBranch()
+    # Checkout master in case the script was left on a work branch.
+    self.GitCheckout('origin/master')
 
     # Fetch unfetched revisions.
     self.vc.Fetch()
@@ -548,12 +549,8 @@ class Step(GitRecipesMixin):
     self.DeleteBranch(self._config["BRANCHNAME"])
 
   def CommonCleanup(self):
-    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"])
+    self.GitCheckout('origin/master')
+    self.GitDeleteBranch(self._config["BRANCHNAME"])
 
     # Clean up all temporary files.
     for f in glob.iglob("%s*" % self._config["PERSISTFILE_BASENAME"]):
@@ -569,10 +566,10 @@ class Step(GitRecipesMixin):
         value = match.group(1)
         self["%s%s" % (prefix, var_name)] = value
     for line in LinesInFile(os.path.join(self.default_cwd, VERSION_FILE)):
-      for (var_name, def_name) in [("major", "MAJOR_VERSION"),
-                                   ("minor", "MINOR_VERSION"),
-                                   ("build", "BUILD_NUMBER"),
-                                   ("patch", "PATCH_LEVEL")]:
+      for (var_name, def_name) in [("major", "V8_MAJOR_VERSION"),
+                                   ("minor", "V8_MINOR_VERSION"),
+                                   ("build", "V8_BUILD_NUMBER"),
+                                   ("patch", "V8_PATCH_LEVEL")]:
         ReadAndPersist(var_name, def_name)
 
   def WaitForLGTM(self):
@@ -701,16 +698,16 @@ class Step(GitRecipesMixin):
   def SetVersion(self, version_file, prefix):
     output = ""
     for line in FileToText(version_file).splitlines():
-      if line.startswith("#define MAJOR_VERSION"):
+      if line.startswith("#define V8_MAJOR_VERSION"):
         line = re.sub("\d+$", self[prefix + "major"], line)
-      elif line.startswith("#define MINOR_VERSION"):
+      elif line.startswith("#define V8_MINOR_VERSION"):
         line = re.sub("\d+$", self[prefix + "minor"], line)
-      elif line.startswith("#define BUILD_NUMBER"):
+      elif line.startswith("#define V8_BUILD_NUMBER"):
         line = re.sub("\d+$", self[prefix + "build"], line)
-      elif line.startswith("#define PATCH_LEVEL"):
+      elif line.startswith("#define V8_PATCH_LEVEL"):
         line = re.sub("\d+$", self[prefix + "patch"], line)
       elif (self[prefix + "candidate"] and
-            line.startswith("#define IS_CANDIDATE_VERSION")):
+            line.startswith("#define V8_IS_CANDIDATE_VERSION")):
         line = re.sub("\d+$", self[prefix + "candidate"], line)
       output += "%s\n" % line
     TextToFile(output, version_file)
@@ -753,16 +750,6 @@ class DetermineV8Sheriff(Step):
     if not self._options.sheriff:  # pragma: no cover
       return
 
-    try:
-      # The googlers mapping maps @google.com accounts to @chromium.org
-      # accounts.
-      googlers = imp.load_source('googlers_mapping',
-                                 self._options.googlers_mapping)
-      googlers = googlers.list_to_dict(googlers.get_list())
-    except:  # pragma: no cover
-      print "Skip determining sheriff without googler mapping."
-      return
-
     # The sheriff determined by the rotation on the waterfall has a
     # @google.com account.
     url = "https://chromium-build.appspot.com/p/chromium/sheriff_v8.js"
@@ -771,9 +758,11 @@ class DetermineV8Sheriff(Step):
     # If "channel is sheriff", we can't match an account.
     if match:
       g_name = match.group(1)
-      self["sheriff"] = googlers.get(g_name + "@google.com",
-                                     g_name + "@chromium.org")
-      self._options.reviewer = self["sheriff"]
+      # Optimistically assume that google and chromium account name are the
+      # same.
+      self["sheriff"] = g_name + "@chromium.org"
+      self._options.reviewer = ("%s,%s" %
+                                (self["sheriff"], self._options.reviewer))
       print "Found active sheriff: %s" % self["sheriff"]
     else:
       print "No active sheriff found."
@@ -825,8 +814,6 @@ class ScriptsBase(object):
                         help="The author email used for rietveld.")
     parser.add_argument("--dry-run", default=False, action="store_true",
                         help="Perform only read-only actions.")
-    parser.add_argument("-g", "--googlers-mapping",
-                        help="Path to the script mapping google accounts.")
     parser.add_argument("-r", "--reviewer", default="",
                         help="The account name to be used for reviews.")
     parser.add_argument("--sheriff", default=False, action="store_true",
@@ -851,10 +838,6 @@ class ScriptsBase(object):
       print "Bad step number %d" % options.step
       parser.print_help()
       return None
-    if options.sheriff and not options.googlers_mapping:  # pragma: no cover
-      print "To determine the current sheriff, requires the googler mapping"
-      parser.print_help()
-      return None
 
     # Defaults for options, common to all scripts.
     options.manual = getattr(options, "manual", True)
index 44c10d9..3bbb50e 100755 (executable)
@@ -30,23 +30,10 @@ class PrepareBranchRevision(Step):
   MESSAGE = "Check from which revision to branch off."
 
   def RunStep(self):
-    if self._options.revision:
-      self["push_hash"], tree_object = self.GitLog(
-          n=1, format="\"%H %T\"", git_hash=self._options.revision).split(" ")
-    else:
-      self["push_hash"], tree_object = self.GitLog(
-          n=1, format="\"%H %T\"", branch="origin/master").split(" ")
-    print "Release revision %s" % self["push_hash"]
+    self["push_hash"] = (self._options.revision or
+                         self.GitLog(n=1, format="%H", branch="origin/master"))
     assert self["push_hash"]
-
-    pending_tuples = self.GitLog(
-        n=200, format="\"%H %T\"", branch="refs/pending/heads/master")
-    for hsh, tree in map(lambda s: s.split(" "), pending_tuples.splitlines()):
-      if tree == tree_object:
-        self["pending_hash"] = hsh
-        break
-    print "Pending release revision %s" % self["pending_hash"]
-    assert self["pending_hash"]
+    print "Release revision %s" % self["push_hash"]
 
 
 class IncrementVersion(Step):
@@ -174,7 +161,7 @@ class MakeBranch(Step):
 
   def RunStep(self):
     self.Git("reset --hard origin/master")
-    self.Git("checkout -b work-branch %s" % self["pending_hash"])
+    self.Git("checkout -b work-branch %s" % self["push_hash"])
     self.GitCheckoutFile(CHANGELOG_FILE, self["latest_version"])
     self.GitCheckoutFile(VERSION_FILE, self["latest_version"])
 
@@ -229,8 +216,7 @@ class PushBranch(Step):
   def RunStep(self):
     pushspecs = [
       "refs/heads/work-branch:refs/pending/heads/%s" % self["version"],
-      "%s:refs/pending-tags/heads/%s" %
-      (self["pending_hash"], self["version"]),
+      "%s:refs/pending-tags/heads/%s" % (self["push_hash"], self["version"]),
       "%s:refs/heads/%s" % (self["push_hash"], self["version"]),
     ]
     cmd = "push origin %s" % " ".join(pushspecs)
index 7aa9fb6..5fe3ba4 100755 (executable)
@@ -169,12 +169,12 @@ class IncrementVersion(Step):
     if self._options.revert_master:
       return
     new_patch = str(int(self["patch"]) + 1)
-    if self.Confirm("Automatically increment PATCH_LEVEL? (Saying 'n' will "
+    if self.Confirm("Automatically increment V8_PATCH_LEVEL? (Saying 'n' will "
                     "fire up your EDITOR on %s so you can make arbitrary "
                     "changes. When you're done, save the file and exit your "
                     "EDITOR.)" % VERSION_FILE):
       text = FileToText(os.path.join(self.default_cwd, VERSION_FILE))
-      text = MSub(r"(?<=#define PATCH_LEVEL)(?P<space>\s+)\d*$",
+      text = MSub(r"(?<=#define V8_PATCH_LEVEL)(?P<space>\s+)\d*$",
                   r"\g<space>%s" % new_patch,
                   text)
       TextToFile(text, os.path.join(self.default_cwd, VERSION_FILE))
index 0f35e7c..9ff6e9b 100755 (executable)
@@ -294,7 +294,7 @@ class RetrieveV8Releases(Step):
     releases = []
     if self._options.branch == 'recent':
       # List every release from the last 7 days.
-      revisions = self.GetRecentReleases(max_age=7 * 24 * 60 * 60)
+      revisions = self.GetRecentReleases(max_age=7 * DAY_IN_SECONDS)
       for revision in revisions:
         releases += self.GetReleaseFromRevision(revision)
     elif self._options.branch == 'all':  # pragma: no cover
@@ -334,6 +334,7 @@ class UpdateChromiumCheckout(Step):
     cwd = self._options.chromium
     self.GitCheckout("master", cwd=cwd)
     self.GitPull(cwd=cwd)
+    self.DeleteBranch(self.Config("BRANCHNAME"), cwd=cwd)
     self.GitCreateBranch(self.Config("BRANCHNAME"), cwd=cwd)
 
 
@@ -488,6 +489,7 @@ class Releases(ScriptsBase):
     parser.add_argument("--json", help="Path to a JSON file for export.")
 
   def _ProcessOptions(self, options):  # pragma: no cover
+    options.force_readline_defaults = True
     return True
 
   def _Config(self):
index 3beddfd..291ca38 100644 (file)
@@ -64,7 +64,6 @@ TEST_CONFIG = {
   "ALREADY_MERGING_SENTINEL_FILE":
       "/tmp/test-merge-to-branch-tempfile-already-merging",
   "TEMPORARY_PATCH_FILE": "/tmp/test-merge-to-branch-tempfile-temporary-patch",
-  "CLUSTERFUZZ_API_KEY_FILE": "/tmp/test-fake-cf-api-key",
 }
 
 
@@ -361,12 +360,12 @@ class ScriptTest(unittest.TestCase):
     with open(version_file, "w") as f:
       f.write("  // Some line...\n")
       f.write("\n")
-      f.write("#define MAJOR_VERSION    %s\n" % major)
-      f.write("#define MINOR_VERSION    %s\n" % minor)
-      f.write("#define BUILD_NUMBER     %s\n" % build)
-      f.write("#define PATCH_LEVEL      %s\n" % patch)
+      f.write("#define V8_MAJOR_VERSION    %s\n" % major)
+      f.write("#define V8_MINOR_VERSION    %s\n" % minor)
+      f.write("#define V8_BUILD_NUMBER     %s\n" % build)
+      f.write("#define V8_PATCH_LEVEL      %s\n" % patch)
       f.write("  // Some line...\n")
-      f.write("#define IS_CANDIDATE_VERSION 0\n")
+      f.write("#define V8_IS_CANDIDATE_VERSION 0\n")
 
   def MakeStep(self):
     """Convenience wrapper."""
@@ -397,11 +396,6 @@ class ScriptTest(unittest.TestCase):
     else:
       return self._mock.Call("readurl", url)
 
-  def ReadClusterFuzzAPI(self, api_key, **params):
-    # TODO(machenbach): Use a mock for this and add a test that stops rolling
-    # due to clustefuzz results.
-    return []
-
   def Sleep(self, seconds):
     pass
 
@@ -443,7 +437,7 @@ class ScriptTest(unittest.TestCase):
   def testCommonPrepareDefault(self):
     self.Expect([
       Cmd("git status -s -uno", ""),
-      Cmd("git status -s -b -uno", "## some_branch"),
+      Cmd("git checkout -f origin/master", ""),
       Cmd("git fetch", ""),
       Cmd("git branch", "  branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
       RL("Y"),
@@ -451,24 +445,22 @@ class ScriptTest(unittest.TestCase):
     ])
     self.MakeStep().CommonPrepare()
     self.MakeStep().PrepareBranch()
-    self.assertEquals("some_branch", self._state["current_branch"])
 
   def testCommonPrepareNoConfirm(self):
     self.Expect([
       Cmd("git status -s -uno", ""),
-      Cmd("git status -s -b -uno", "## some_branch"),
+      Cmd("git checkout -f origin/master", ""),
       Cmd("git fetch", ""),
       Cmd("git branch", "  branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
       RL("n"),
     ])
     self.MakeStep().CommonPrepare()
     self.assertRaises(Exception, self.MakeStep().PrepareBranch)
-    self.assertEquals("some_branch", self._state["current_branch"])
 
   def testCommonPrepareDeleteBranchFailure(self):
     self.Expect([
       Cmd("git status -s -uno", ""),
-      Cmd("git status -s -b -uno", "## some_branch"),
+      Cmd("git checkout -f origin/master", ""),
       Cmd("git fetch", ""),
       Cmd("git branch", "  branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
       RL("Y"),
@@ -476,7 +468,6 @@ class ScriptTest(unittest.TestCase):
     ])
     self.MakeStep().CommonPrepare()
     self.assertRaises(Exception, self.MakeStep().PrepareBranch)
-    self.assertEquals("some_branch", self._state["current_branch"])
 
   def testInitialEnvironmentChecks(self):
     TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
@@ -528,10 +519,10 @@ class ScriptTest(unittest.TestCase):
                      "        too much\n"
                      "        trailing", cl)
 
-    self.assertEqual("//\n#define BUILD_NUMBER  3\n",
-                     MSub(r"(?<=#define BUILD_NUMBER)(?P<space>\s+)\d*$",
+    self.assertEqual("//\n#define V8_BUILD_NUMBER  3\n",
+                     MSub(r"(?<=#define V8_BUILD_NUMBER)(?P<space>\s+)\d*$",
                           r"\g<space>3",
-                          "//\n#define BUILD_NUMBER  321\n"))
+                          "//\n#define V8_BUILD_NUMBER  321\n"))
 
   def testPreparePushRevision(self):
     # Tests the default push hash used when the --revision option is not set.
@@ -629,7 +620,7 @@ test_tag
     self.Expect([
       Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
       Cmd("git tag", self.TAGS),
-      Cmd("git checkout -f origin/master -- src/version.cc",
+      Cmd("git checkout -f origin/master -- include/v8-version.h",
           "", cb=lambda: self.WriteFakeVersionFile(3, 22, 6)),
     ])
 
@@ -750,11 +741,12 @@ Performance and stability improvements on all platforms."""
       self.assertEquals(commit_msg, commit)
       version = FileToText(
           os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE))
-      self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version))
-      self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version))
-      self.assertFalse(re.search(r"#define BUILD_NUMBER\s+6", version))
-      self.assertTrue(re.search(r"#define PATCH_LEVEL\s+0", version))
-      self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version))
+      self.assertTrue(re.search(r"#define V8_MINOR_VERSION\s+22", version))
+      self.assertTrue(re.search(r"#define V8_BUILD_NUMBER\s+5", version))
+      self.assertFalse(re.search(r"#define V8_BUILD_NUMBER\s+6", version))
+      self.assertTrue(re.search(r"#define V8_PATCH_LEVEL\s+0", version))
+      self.assertTrue(
+          re.search(r"#define V8_IS_CANDIDATE_VERSION\s+0", version))
 
       # Check that the change log on the candidates branch got correctly
       # modified.
@@ -779,7 +771,7 @@ Performance and stability improvements on all platforms."""
       expectations.append(Cmd("which vi", "/usr/bin/vi"))
     expectations += [
       Cmd("git status -s -uno", ""),
-      Cmd("git status -s -b -uno", "## some_branch\n"),
+      Cmd("git checkout -f origin/master", ""),
       Cmd("git fetch", ""),
       Cmd("git branch", "  branch1\n* branch2\n"),
       Cmd("git branch", "  branch1\n* branch2\n"),
@@ -787,7 +779,7 @@ Performance and stability improvements on all platforms."""
            TEST_CONFIG["BRANCHNAME"]), ""),
       Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
       Cmd("git tag", self.TAGS),
-      Cmd("git checkout -f origin/master -- src/version.cc",
+      Cmd("git checkout -f origin/master -- include/v8-version.h",
           "", cb=self.WriteFakeVersionFile),
       Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"),
       Cmd("git log -1 --format=%s release_hash",
@@ -811,7 +803,7 @@ Performance and stability improvements on all platforms."""
       Cmd("git apply --index --reject \"%s\"" % TEST_CONFIG["PATCH_FILE"], ""),
       Cmd("git checkout -f origin/candidates -- ChangeLog", "",
           cb=ResetChangeLog),
-      Cmd("git checkout -f origin/candidates -- src/version.cc", "",
+      Cmd("git checkout -f origin/candidates -- include/v8-version.h", "",
           cb=self.WriteFakeVersionFile),
       Cmd("git commit -am \"%s\"" % commit_msg_squashed, ""),
     ]
@@ -833,7 +825,7 @@ Performance and stability improvements on all platforms."""
           " 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 checkout -f origin/master", ""),
       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
       Cmd("git branch -D %s" % TEST_CONFIG["CANDIDATESBRANCH"], ""),
     ]
@@ -891,11 +883,12 @@ Performance and stability improvements on all platforms."""
       self.assertEquals(commit_msg, commit)
       version = FileToText(
           os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE))
-      self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version))
-      self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version))
-      self.assertFalse(re.search(r"#define BUILD_NUMBER\s+6", version))
-      self.assertTrue(re.search(r"#define PATCH_LEVEL\s+0", version))
-      self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version))
+      self.assertTrue(re.search(r"#define V8_MINOR_VERSION\s+22", version))
+      self.assertTrue(re.search(r"#define V8_BUILD_NUMBER\s+5", version))
+      self.assertFalse(re.search(r"#define V8_BUILD_NUMBER\s+6", version))
+      self.assertTrue(re.search(r"#define V8_PATCH_LEVEL\s+0", version))
+      self.assertTrue(
+          re.search(r"#define V8_IS_CANDIDATE_VERSION\s+0", version))
 
       # Check that the change log on the candidates branch got correctly
       # modified.
@@ -921,12 +914,9 @@ Performance and stability improvements on all platforms."""
           "+refs/pending-tags/*:refs/pending-tags/*", ""),
       Cmd("git checkout -f origin/master", ""),
       Cmd("git branch", ""),
-      Cmd("git log -1 --format=\"%H %T\" push_hash", "push_hash tree_hash"),
-      Cmd("git log -200 --format=\"%H %T\" refs/pending/heads/master",
-          "not_right wrong\npending_hash tree_hash\nsome other\n"),
       Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
       Cmd("git tag", self.TAGS),
-      Cmd("git checkout -f origin/master -- src/version.cc",
+      Cmd("git checkout -f origin/master -- include/v8-version.h",
           "", cb=self.WriteFakeVersionFile),
       Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"),
       Cmd("git log -1 --format=%s release_hash", "Version 3.22.4\n"),
@@ -936,15 +926,15 @@ Performance and stability improvements on all platforms."""
       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"),
       Cmd("git reset --hard origin/master", ""),
-      Cmd("git checkout -b work-branch pending_hash", ""),
+      Cmd("git checkout -b work-branch push_hash", ""),
       Cmd("git checkout -f 3.22.4 -- ChangeLog", "", cb=ResetChangeLog),
-      Cmd("git checkout -f 3.22.4 -- src/version.cc", "",
+      Cmd("git checkout -f 3.22.4 -- include/v8-version.h", "",
           cb=self.WriteFakeVersionFile),
       Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], "",
           cb=CheckVersionCommit),
       Cmd("git push origin "
           "refs/heads/work-branch:refs/pending/heads/3.22.5 "
-          "pending_hash:refs/pending-tags/heads/3.22.5 "
+          "push_hash:refs/pending-tags/heads/3.22.5 "
           "push_hash:refs/heads/3.22.5", ""),
       Cmd("git fetch", ""),
       Cmd("git log -1 --format=%H --grep="
@@ -989,15 +979,17 @@ git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@123456 123
 
 """
 
-  def testChromiumRoll(self):
-    googlers_mapping_py = "%s-mapping.py" % TEST_CONFIG["PERSISTFILE_BASENAME"]
-    with open(googlers_mapping_py, "w") as f:
-      f.write("""
-def list_to_dict(entries):
-  return {"g_name@google.com": "c_name@chromium.org"}
-def get_list():
-  pass""")
+  ROLL_COMMIT_MSG = """Update V8 to version 3.22.4 (based on abc).
+
+Summary of changes available at:
+https://chromium.googlesource.com/v8/v8/+log/last_rol..roll_hsh
+
+Please follow these instructions for assigning/CC'ing issues:
+https://code.google.com/p/v8-wiki/wiki/TriagingIssues
 
+TBR=g_name@chromium.org,reviewer@chromium.org"""
+
+  def testChromiumRoll(self):
     # Setup fake directory structures.
     TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
     TextToFile("", os.path.join(TEST_CONFIG["CHROMIUM"], ".git"))
@@ -1014,18 +1006,10 @@ def get_list():
     expectations = [
       Cmd("git fetch origin", ""),
       Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
-      Cmd("git tag", self.TAGS),
-      Cmd("git log -1 --format=%H 3.22.4", "push_hash\n"),
-      Cmd("git log -1 --format=%s push_hash",
+      Cmd("git log -1 --format=%s roll_hsh",
           "Version 3.22.4 (based on abc)\n"),
-      Cmd("git log -1 --format=%H 3.22.4", "push_hash\n"),
-      Cmd("git log -1 --format=%s push_hash",
-          "Version 3.22.4 (based on abc)"),
+      Cmd("git describe --tags roll_hsh", "3.22.4"),
       Cmd("git describe --tags last_roll_hsh", "3.22.2.1"),
-      Cmd("git log -1 --format=%H 3.22.2", "last_roll_base_hash"),
-      Cmd("git log -1 --format=%s last_roll_base_hash", "Version 3.22.2"),
-      Cmd("git log -1 --format=%H last_roll_base_hash^",
-          "last_roll_master_hash"),
       URL("https://chromium-build.appspot.com/p/chromium/sheriff_v8.js",
           "document.write('g_name')"),
       Cmd("git status -s -uno", "", cwd=chrome_dir),
@@ -1033,15 +1017,11 @@ def get_list():
       Cmd("gclient sync --nohooks", "syncing...", cwd=chrome_dir),
       Cmd("git pull", "", cwd=chrome_dir),
       Cmd("git fetch origin", ""),
-      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.4 "
-           "(based on abc).\n\n"
-           "Summary of changes available at:\n"
-           "https://chromium.googlesource.com/v8/v8/+log/last_rol..abc\n\n"
-           "Please reply to the V8 sheriff c_name@chromium.org in "
-           "case of problems.\n\nTBR=c_name@chromium.org\" "
-           "--author \"author@chromium.org <author@chromium.org>\""),
+      Cmd("git new-branch v8-roll-roll_hsh", "", cwd=chrome_dir),
+      Cmd("roll-dep v8 roll_hsh", "rolled", cb=WriteDeps, cwd=chrome_dir),
+      Cmd(("git commit -am \"%s\" "
+           "--author \"author@chromium.org <author@chromium.org>\"" %
+           self.ROLL_COMMIT_MSG),
           "", cwd=chrome_dir),
       Cmd("git cl upload --send-mail --email \"author@chromium.org\" -f", "",
           cwd=chrome_dir),
@@ -1049,9 +1029,10 @@ def get_list():
     self.Expect(expectations)
 
     args = ["-a", "author@chromium.org", "-c", chrome_dir,
-            "--sheriff", "--googlers-mapping", googlers_mapping_py,
+            "--sheriff",
             "-r", "reviewer@chromium.org",
-            "--last-roll", "last_roll_hsh"]
+            "--last-roll", "last_roll_hsh",
+            "roll_hsh"]
     ChromiumRoll(TEST_CONFIG, self).Run(args)
 
     deps = FileToText(os.path.join(chrome_dir, "DEPS"))
@@ -1072,11 +1053,7 @@ def get_list():
         auto_push.AutoPush, LastReleaseBailout, AUTO_PUSH_ARGS))
 
   def testAutoPush(self):
-    TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
-
     self.Expect([
-      Cmd("git status -s -uno", ""),
-      Cmd("git status -s -b -uno", "## some_branch\n"),
       Cmd("git fetch", ""),
       Cmd("git fetch origin +refs/heads/roll:refs/heads/roll", ""),
       Cmd("git show-ref -s refs/heads/roll", "abc123\n"),
@@ -1127,8 +1104,14 @@ deps = {
           "owner=author%40chromium.org&limit=30&closed=3&format=json",
           ("{\"results\": [{\"subject\": \"different\"}]}")),
       Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
-      Cmd("git tag", self.TAGS),
-      Cmd("git log -1 --format=%H 3.22.4", "push_hash\n"),
+      Cmd("git rev-list --max-age=740800 --tags",
+          "bad_tag\nhash_234\nhash_123"),
+      Cmd("git describe --tags bad_tag", ""),
+      Cmd("git describe --tags hash_234", "3.22.4"),
+      Cmd("git describe --tags hash_123", "3.22.3"),
+      Cmd("git describe --tags abcd123455", "3.22.4"),
+      Cmd("git describe --tags hash_234", "3.22.4"),
+      Cmd("git describe --tags hash_123", "3.22.3"),
     ])
 
     result = auto_roll.AutoRoll(TEST_CONFIG, self).Run(
@@ -1138,16 +1121,19 @@ deps = {
   def testAutoRoll(self):
     TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
     TextToFile(self.FAKE_DEPS, os.path.join(TEST_CONFIG["CHROMIUM"], "DEPS"))
-    TEST_CONFIG["CLUSTERFUZZ_API_KEY_FILE"]  = self.MakeEmptyTempFile()
-    TextToFile("fake key", TEST_CONFIG["CLUSTERFUZZ_API_KEY_FILE"])
 
     self.Expect([
       URL("https://codereview.chromium.org/search",
           "owner=author%40chromium.org&limit=30&closed=3&format=json",
           ("{\"results\": [{\"subject\": \"different\"}]}")),
       Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
-      Cmd("git tag", self.TAGS),
-      Cmd("git log -1 --format=%H 3.22.4", "push_hash\n"),
+      Cmd("git rev-list --max-age=740800 --tags",
+          "bad_tag\nhash_234\nhash_123"),
+      Cmd("git describe --tags bad_tag", ""),
+      Cmd("git describe --tags hash_234", "3.22.4"),
+      Cmd("git describe --tags hash_123", "3.22.3"),
+      Cmd("git describe --tags abcd123455", "3.22.3.1"),
+      Cmd("git describe --tags hash_234", "3.22.4"),
     ])
 
     result = auto_roll.AutoRoll(TEST_CONFIG, self).Run(
@@ -1192,14 +1178,15 @@ LOG=N
       self.assertEquals(msg, commit)
       version = FileToText(
           os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE))
-      self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version))
-      self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version))
-      self.assertTrue(re.search(r"#define PATCH_LEVEL\s+1", version))
-      self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version))
+      self.assertTrue(re.search(r"#define V8_MINOR_VERSION\s+22", version))
+      self.assertTrue(re.search(r"#define V8_BUILD_NUMBER\s+5", version))
+      self.assertTrue(re.search(r"#define V8_PATCH_LEVEL\s+1", version))
+      self.assertTrue(
+          re.search(r"#define V8_IS_CANDIDATE_VERSION\s+0", version))
 
     self.Expect([
       Cmd("git status -s -uno", ""),
-      Cmd("git status -s -b -uno", "## some_branch\n"),
+      Cmd("git checkout -f origin/master", ""),
       Cmd("git fetch", ""),
       Cmd("git branch", "  branch1\n* branch2\n"),
       Cmd("git new-branch %s --upstream refs/remotes/origin/candidates" %
@@ -1273,7 +1260,7 @@ LOG=N
           "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 checkout -f origin/master", ""),
       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
     ])
 
@@ -1360,7 +1347,7 @@ Cr-Commit-Position: refs/heads/4.2.71@{#1}
 
     self.Expect([
       Cmd("git status -s -uno", ""),
-      Cmd("git status -s -b -uno", "## some_branch\n"),
+      Cmd("git checkout -f origin/master", ""),
       Cmd("git fetch", ""),
       Cmd("git branch", "  branch1\n* branch2\n"),
       Cmd("git new-branch %s" % TEST_CONFIG["BRANCHNAME"], ""),
@@ -1419,6 +1406,10 @@ Cr-Commit-Position: refs/heads/4.2.71@{#1}
       Cmd("git status -s -uno", "", cwd=chrome_dir),
       Cmd("git checkout -f master", "", cwd=chrome_dir),
       Cmd("git pull", "", cwd=chrome_dir),
+      Cmd("git branch", "  branch1\n* %s" % TEST_CONFIG["BRANCHNAME"],
+          cwd=chrome_dir),
+      Cmd("git branch -D %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),
@@ -1453,7 +1444,7 @@ Cr-Commit-Position: refs/heads/4.2.71@{#1}
           cwd=chrome_dir),
       Cmd("git checkout -f master", "", cwd=chrome_dir),
       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], "", cwd=chrome_dir),
-      Cmd("git checkout -f some_branch", ""),
+      Cmd("git checkout -f origin/master", ""),
       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
     ])
 
index 8627319..f7e77ca 100755 (executable)
@@ -130,6 +130,7 @@ GC_STRESS_FLAGS = ["--gc-interval=500", "--stress-compaction",
 SUPPORTED_ARCHS = ["android_arm",
                    "android_arm64",
                    "android_ia32",
+                   "android_x64",
                    "arm",
                    "ia32",
                    "x87",
@@ -147,6 +148,7 @@ SUPPORTED_ARCHS = ["android_arm",
 SLOW_ARCHS = ["android_arm",
               "android_arm64",
               "android_ia32",
+              "android_x64",
               "arm",
               "mips",
               "mipsel",
index 63c9148..f771079 100755 (executable)
@@ -111,6 +111,7 @@ ARCH_GUESS = utils.DefaultArch()
 SUPPORTED_ARCHS = ["android_arm",
                    "android_arm64",
                    "android_ia32",
+                   "android_x64",
                    "arm",
                    "ia32",
                    "mips",
@@ -533,7 +534,8 @@ class AndroidPlatform(Platform):  # pragma: no cover
     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="."):
+  def _PushFile(self, host_dir, file_name, target_rel=".",
+                skip_if_missing=False):
     file_on_host = os.path.join(host_dir, file_name)
     file_on_device_tmp = os.path.join(
         AndroidPlatform.DEVICE_DIR, "_tmp_", file_name)
@@ -541,6 +543,12 @@ class AndroidPlatform(Platform):  # pragma: no cover
         AndroidPlatform.DEVICE_DIR, target_rel, file_name)
     folder_on_device = os.path.dirname(file_on_device)
 
+    # Only attempt to push files that exist.
+    if not os.path.exists(file_on_host):
+      if not skip_if_missing:
+        logging.critical('Missing file on host: %s' % file_on_host)
+      return
+
     # Only push files not yet pushed in one execution.
     if file_on_host in self.pushed:
       return
@@ -568,6 +576,12 @@ class AndroidPlatform(Platform):  # pragma: no cover
       bench_abs = suite_dir
 
     self._PushFile(self.shell_dir, node.binary)
+
+    # Push external startup data. Backwards compatible for revisions where
+    # these files didn't exist.
+    self._PushFile(self.shell_dir, "natives_blob.bin", skip_if_missing=True)
+    self._PushFile(self.shell_dir, "snapshot_blob.bin", skip_if_missing=True)
+
     if isinstance(node, Runnable):
       self._PushFile(bench_abs, node.main, bench_rel)
     for resource in node.resources:
diff --git a/deps/v8/tools/test-push-to-trunk.sh b/deps/v8/tools/test-push-to-trunk.sh
deleted file mode 100755 (executable)
index 6c201e4..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-#!/bin/bash
-# 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.
-
-# Tests the push-to-trunk.sh script. Needs to be run in V8 base dir:
-# ./tools/test-push-to-trunk.sh
-
-# TODO(machenbach): Check automatically if expectations match.
-# TODO(machenbach): Mock out version number retrieval.
-# TODO(machenbach): Allow multiple different test cases.
-# TODO(machenbach): Allow multi line mock output.
-# TODO(machenbach): Represent test expectations/mock output without an array
-# index increment.
-
-########## Stdin for push-to-trunk.sh
-
-# Confirm push to trunk commit ID
-INPUT[0]="Y"
-# Open editor
-INPUT[1]=""
-# Confirm increment version number
-INPUT[2]="Y"
-# Reviewer for V8 CL
-INPUT[3]="reviewer@chromium.org"
-# Enter LGTM for V8 CL
-INPUT[4]="LGTM"
-# Confirm checkout sanity
-INPUT[5]="Y"
-# Manually type in trunk revision
-INPUT[6]="12345"
-# Reviewer for Chromium CL
-INPUT[7]="reviewer@chromium.org"
-
-########## Expected commands and mock output
-
-EXP[0]="git status -s -uno"
-OUT[0]=""
-EXP[1]="git status -s -b -uno"
-OUT[1]="## some_branch"
-EXP[2]="git svn fetch"
-OUT[2]=""
-EXP[3]="git branch"
-OUT[3]="not the temp branch"
-EXP[4]="git checkout -b prepare-push-temporary-branch-created-by-script"
-OUT[4]=""
-EXP[5]="git branch"
-OUT[5]="not the branch"
-EXP[6]="git branch"
-OUT[6]="not the trunk branch"
-EXP[7]="git checkout -b prepare-push svn/bleeding_edge"
-OUT[7]=""
-EXP[8]="git log -1 --format=%H ChangeLog"
-OUT[8]="hash1"
-EXP[9]="git log -1 hash1"
-OUT[9]=""
-EXP[10]="git log hash1..HEAD --format=%H"
-OUT[10]="hash2"
-EXP[11]="git log -1 hash2 --format=\"%w(80,8,8)%s\""
-OUT[11]="Log line..."
-EXP[12]="git log -1 hash2 --format=\"%B\""
-OUT[12]="BUG=6789"
-EXP[13]="git log -1 hash2 --format=\"%w(80,8,8)(%an)\""
-OUT[13]="   (author@chromium.org)"
-EXP[14]="git commit -a -m \"Prepare push to trunk.  Now working on version 3.4.5.\""
-OUT[14]=""
-EXP[15]="git cl upload -r reviewer@chromium.org --send-mail"
-OUT[15]=""
-EXP[16]="git cl dcommit"
-OUT[16]=""
-EXP[17]="git svn fetch"
-OUT[17]=""
-EXP[18]="git checkout svn/bleeding_edge"
-OUT[18]=""
-EXP[19]="git log -1 --format=%H --grep=Prepare push to trunk.  Now working on version 3.4.5."
-OUT[19]="hash3"
-EXP[20]="git diff svn/trunk"
-OUT[20]="patch1"
-EXP[21]="git checkout -b trunk-push svn/trunk"
-OUT[21]=""
-EXP[22]="git apply --index --reject /tmp/v8-push-to-trunk-tempfile-patch"
-OUT[22]=""
-EXP[23]="git add src/version.cc"
-OUT[23]=""
-EXP[24]="git commit -F /tmp/v8-push-to-trunk-tempfile-commitmsg"
-OUT[24]=""
-EXP[25]="git svn dcommit"
-OUT[25]="r1234"
-EXP[26]="git svn tag 3.4.5 -m \"Tagging version 3.4.5\""
-OUT[26]=""
-EXP[27]="git status -s -uno"
-OUT[27]=""
-EXP[28]="git checkout master"
-OUT[28]=""
-EXP[29]="git pull"
-OUT[29]=""
-EXP[30]="git checkout -b v8-roll-12345"
-OUT[30]=""
-EXP[31]="git commit -am Update V8 to version 3.4.5."
-OUT[31]=""
-EXP[32]="git cl upload --send-mail"
-OUT[32]=""
-EXP[33]="git checkout -f some_branch"
-OUT[33]=""
-EXP[34]="git branch -D prepare-push-temporary-branch-created-by-script"
-OUT[34]=""
-EXP[35]="git branch -D prepare-push"
-OUT[35]=""
-EXP[36]="git branch -D trunk-push"
-OUT[36]=""
-
-########## Global temp files for test input/output
-
-export TEST_OUTPUT=$(mktemp)
-export INDEX=$(mktemp)
-export MOCK_OUTPUT=$(mktemp)
-export EXPECTED_COMMANDS=$(mktemp)
-
-########## Command index
-
-inc_index() {
-  local I="$(command cat $INDEX)"
-  let "I+=1"
-  echo "$I" > $INDEX
-  echo $I
-}
-
-echo "-1" > $INDEX
-export -f inc_index
-
-########## Mock output accessor
-
-get_mock_output() {
-  local I=$1
-  let "I+=1"
-  command sed "${I}q;d" $MOCK_OUTPUT
-}
-
-export -f get_mock_output
-
-for E in "${OUT[@]}"; do
-  echo $E
-done > $MOCK_OUTPUT
-
-########## Expected commands accessor
-
-get_expected_command() {
-  local I=$1
-  let "I+=1"
-  command sed "${I}q;d" $EXPECTED_COMMANDS
-}
-
-export -f get_expected_command
-
-for E in "${EXP[@]}"; do
-  echo $E
-done > $EXPECTED_COMMANDS
-
-########## Mock commands
-
-git() {
-  # All calls to git are mocked out. Expected calls and mock output are stored
-  # in the EXP/OUT arrays above.
-  local I=$(inc_index)
-  local OUT=$(get_mock_output $I)
-  local EXP=$(get_expected_command $I)
-  echo "#############################" >> $TEST_OUTPUT
-  echo "Com. Index:  $I" >> $TEST_OUTPUT
-  echo "Expected:    ${EXP}" >> $TEST_OUTPUT
-  echo "Actual:      git $@" >> $TEST_OUTPUT
-  echo "Mock Output: ${OUT}" >> $TEST_OUTPUT
-  echo "${OUT}"
-}
-
-mv() {
-  echo "#############################" >> $TEST_OUTPUT
-  echo "mv $@" >> $TEST_OUTPUT
-}
-
-sed() {
-  # Only calls to sed * -i * are mocked out.
-  echo "#############################" >> $TEST_OUTPUT
-  local arr=$@
-  if [[ "${arr[@]}" =~ "-i" || "${arr[${#arr[@]}-1]}" == "-i" ]]; then
-    echo "sed $@" >> $TEST_OUTPUT
-  else
-    echo "sed $@" >> $TEST_OUTPUT
-    command sed "$@"
-  fi
-}
-
-editor() {
-  echo "#############################" >> $TEST_OUTPUT
-  echo "editor $@" >> $TEST_OUTPUT
-}
-
-cd() {
-  echo "#############################" >> $TEST_OUTPUT
-  echo "cd $@" >> $TEST_OUTPUT
-}
-
-export -f git
-export -f mv
-export -f sed
-export -f cd
-export -f editor
-export EDITOR=editor
-
-########## Invoke script with test stdin
-
-for i in "${INPUT[@]}"; do 
-    echo $i
-done | tools/push-to-trunk.sh -c "path/to/chromium"
-
-echo "Collected output:"
-command cat $TEST_OUTPUT
-
-########## Clean up
-
-rm -rf $TEST_OUTPUT
-rm -rf $INDEX
-rm -rf $MOCK_OUTPUT
-rm -rf $EXPECTED_COMMANDS
index a52fa56..d8c1549 100644 (file)
@@ -55,8 +55,9 @@ DEFS = {FAIL_OK: [FAIL, OKAY],
 VARIABLES = {ALWAYS: True}
 for var in ["debug", "release", "big", "little",
             "android_arm", "android_arm64", "android_ia32", "android_x87",
-            "arm", "arm64", "ia32", "mips", "mipsel", "mips64el", "x64", "x87", "nacl_ia32",
-            "nacl_x64", "ppc", "ppc64", "macos", "windows", "linux", "aix"]:
+            "android_x64", "arm", "arm64", "ia32", "mips", "mipsel",
+            "mips64el", "x64", "x87", "nacl_ia32", "nacl_x64", "ppc", "ppc64",
+            "macos", "windows", "linux", "aix"]:
   VARIABLES[var] = var
 
 
index 1f25d14..838d92a 100755 (executable)
 ########## Global variable definitions
 
 BASE_URL="https://code.google.com/p/v8/source/list"
-VERSION="src/version.cc"
-MAJOR="MAJOR_VERSION"
-MINOR="MINOR_VERSION"
-BUILD="BUILD_NUMBER"
-PATCH="PATCH_LEVEL"
+VERSION="include/v8-version.h"
+MAJOR="V8_MAJOR_VERSION"
+MINOR="V8_MINOR_VERSION"
+BUILD="V8_BUILD_NUMBER"
+PATCH="V8_PATCH_LEVEL"
 
 V8="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"