summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Varga <pvarga@inf.u-szeged.hu>2012-06-13 09:21:17 +0200
committerQt by Nokia <qt-info@nokia.com>2012-06-13 09:55:50 +0200
commitd47c4a1dad750d278bcf00b630af69c4b8bdb97f (patch)
tree289865bd448633ffec5e8d7e85436b6c0a8a6cad
parent28017b45db578180d0d54e67aea209ad95f73b9f (diff)
downloadqtjsbackend-d47c4a1dad750d278bcf00b630af69c4b8bdb97f.tar.gz
Updated V8 from git://github.com/v8/v8.git to 3e6ec7e018bbf2c63ef04b85ff688198ea204c04
Update V8 source to version 3.11.4 * Performance and stability improvements on all platforms. * Fixed native ARM build (issues 1744, 539) * Fixed several bugs in heap profiles (including issue 2078). * Throw syntax errors on illegal escape sequences. * Made handling of const more consistent when combined with 'eval' and 'with'. * Fixed V8 on MinGW-x64 (issue 2026). * Put new global var semantics behind a flag until WebKit tests are cleaned up. * Enabled inlining some V8 API functions. * Enabled MIPS cross-compilation. * Implemented clearing of CompareICs (issue 2102). * Fixed python deprecations. (issue 1391) * Fixed GCC 4.7 (C++11) compilation. (issue 2136) Change-Id: I72594bd22356391dd55e315c022d0c9f3fd5b451 Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
-rw-r--r--src/3rdparty/v8/ChangeLog190
-rw-r--r--src/3rdparty/v8/DEPS27
-rw-r--r--src/3rdparty/v8/Makefile73
-rw-r--r--src/3rdparty/v8/SConstruct17
-rw-r--r--src/3rdparty/v8/build/armu.gypi36
-rw-r--r--src/3rdparty/v8/build/common.gypi269
-rwxr-xr-xsrc/3rdparty/v8/build/gyp_v836
-rw-r--r--src/3rdparty/v8/build/mipsu.gypi33
-rw-r--r--src/3rdparty/v8/build/standalone.gypi16
-rwxr-xr-x[-rw-r--r--]src/3rdparty/v8/include/v8-debug.h0
-rw-r--r--src/3rdparty/v8/include/v8-profiler.h73
-rw-r--r--src/3rdparty/v8/include/v8.h357
-rw-r--r--src/3rdparty/v8/samples/lineprocessor.cc6
-rw-r--r--src/3rdparty/v8/samples/samples.gyp8
-rw-r--r--src/3rdparty/v8/src/api.cc307
-rw-r--r--src/3rdparty/v8/src/apiutils.h9
-rw-r--r--src/3rdparty/v8/src/arguments.h13
-rw-r--r--src/3rdparty/v8/src/arm/code-stubs-arm.cc114
-rw-r--r--src/3rdparty/v8/src/arm/cpu-arm.cc15
-rw-r--r--src/3rdparty/v8/src/arm/debug-arm.cc4
-rw-r--r--src/3rdparty/v8/src/arm/deoptimizer-arm.cc15
-rw-r--r--src/3rdparty/v8/src/arm/full-codegen-arm.cc347
-rw-r--r--src/3rdparty/v8/src/arm/ic-arm.cc49
-rw-r--r--src/3rdparty/v8/src/arm/lithium-arm.cc141
-rw-r--r--src/3rdparty/v8/src/arm/lithium-arm.h101
-rw-r--r--src/3rdparty/v8/src/arm/lithium-codegen-arm.cc345
-rw-r--r--src/3rdparty/v8/src/arm/lithium-codegen-arm.h19
-rw-r--r--src/3rdparty/v8/src/arm/macro-assembler-arm.cc31
-rw-r--r--src/3rdparty/v8/src/arm/macro-assembler-arm.h16
-rw-r--r--src/3rdparty/v8/src/arm/stub-cache-arm.cc135
-rw-r--r--src/3rdparty/v8/src/array.js176
-rw-r--r--src/3rdparty/v8/src/assembler.h4
-rw-r--r--src/3rdparty/v8/src/ast.cc228
-rw-r--r--src/3rdparty/v8/src/ast.h12
-rw-r--r--src/3rdparty/v8/src/atomicops.h11
-rw-r--r--src/3rdparty/v8/src/atomicops_internals_arm_qnx.h117
-rw-r--r--src/3rdparty/v8/src/bootstrapper.cc20
-rw-r--r--src/3rdparty/v8/src/builtins.cc75
-rw-r--r--src/3rdparty/v8/src/builtins.h1
-rw-r--r--src/3rdparty/v8/src/code-stubs.cc19
-rw-r--r--src/3rdparty/v8/src/code-stubs.h5
-rw-r--r--src/3rdparty/v8/src/compiler-intrinsics.h17
-rw-r--r--src/3rdparty/v8/src/compiler.cc19
-rw-r--r--src/3rdparty/v8/src/compiler.h16
-rw-r--r--src/3rdparty/v8/src/contexts.cc35
-rw-r--r--src/3rdparty/v8/src/contexts.h6
-rw-r--r--src/3rdparty/v8/src/d8.cc68
-rw-r--r--src/3rdparty/v8/src/d8.h1
-rw-r--r--src/3rdparty/v8/src/debug-agent.cc6
-rw-r--r--src/3rdparty/v8/src/debug-debugger.js62
-rw-r--r--src/3rdparty/v8/src/debug.cc42
-rw-r--r--src/3rdparty/v8/src/debug.h55
-rw-r--r--src/3rdparty/v8/src/double.h6
-rw-r--r--src/3rdparty/v8/src/elements.cc182
-rw-r--r--src/3rdparty/v8/src/elements.h59
-rw-r--r--src/3rdparty/v8/src/execution.cc31
-rw-r--r--src/3rdparty/v8/src/execution.h8
-rw-r--r--src/3rdparty/v8/src/factory.cc46
-rw-r--r--src/3rdparty/v8/src/factory.h12
-rw-r--r--src/3rdparty/v8/src/flag-definitions.h16
-rw-r--r--src/3rdparty/v8/src/frames.cc7
-rw-r--r--src/3rdparty/v8/src/frames.h3
-rw-r--r--src/3rdparty/v8/src/full-codegen.cc133
-rw-r--r--src/3rdparty/v8/src/full-codegen.h24
-rw-r--r--src/3rdparty/v8/src/globals.h9
-rw-r--r--src/3rdparty/v8/src/handles.cc6
-rw-r--r--src/3rdparty/v8/src/hashmap.h10
-rw-r--r--src/3rdparty/v8/src/heap-inl.h66
-rw-r--r--src/3rdparty/v8/src/heap-profiler.cc42
-rw-r--r--src/3rdparty/v8/src/heap-profiler.h11
-rw-r--r--src/3rdparty/v8/src/heap.cc282
-rw-r--r--src/3rdparty/v8/src/heap.h72
-rw-r--r--src/3rdparty/v8/src/hydrogen-instructions.cc111
-rw-r--r--src/3rdparty/v8/src/hydrogen-instructions.h268
-rw-r--r--src/3rdparty/v8/src/hydrogen.cc1231
-rw-r--r--src/3rdparty/v8/src/hydrogen.h68
-rw-r--r--src/3rdparty/v8/src/ia32/assembler-ia32.h3
-rw-r--r--src/3rdparty/v8/src/ia32/builtins-ia32.cc11
-rw-r--r--src/3rdparty/v8/src/ia32/code-stubs-ia32.cc166
-rw-r--r--src/3rdparty/v8/src/ia32/codegen-ia32.cc18
-rw-r--r--src/3rdparty/v8/src/ia32/debug-ia32.cc39
-rw-r--r--src/3rdparty/v8/src/ia32/deoptimizer-ia32.cc15
-rw-r--r--src/3rdparty/v8/src/ia32/full-codegen-ia32.cc356
-rw-r--r--src/3rdparty/v8/src/ia32/ic-ia32.cc190
-rw-r--r--src/3rdparty/v8/src/ia32/lithium-codegen-ia32.cc287
-rw-r--r--src/3rdparty/v8/src/ia32/lithium-codegen-ia32.h11
-rw-r--r--src/3rdparty/v8/src/ia32/lithium-ia32.cc73
-rw-r--r--src/3rdparty/v8/src/ia32/lithium-ia32.h77
-rw-r--r--src/3rdparty/v8/src/ia32/macro-assembler-ia32.cc2
-rw-r--r--src/3rdparty/v8/src/ia32/macro-assembler-ia32.h3
-rw-r--r--src/3rdparty/v8/src/ia32/stub-cache-ia32.cc359
-rw-r--r--src/3rdparty/v8/src/ic.cc69
-rw-r--r--src/3rdparty/v8/src/ic.h20
-rw-r--r--src/3rdparty/v8/src/incremental-marking-inl.h26
-rw-r--r--src/3rdparty/v8/src/incremental-marking.cc56
-rw-r--r--src/3rdparty/v8/src/incremental-marking.h15
-rw-r--r--src/3rdparty/v8/src/interface.cc13
-rw-r--r--src/3rdparty/v8/src/interface.h46
-rw-r--r--src/3rdparty/v8/src/isolate.cc19
-rw-r--r--src/3rdparty/v8/src/isolate.h36
-rw-r--r--src/3rdparty/v8/src/jsregexp.cc1031
-rw-r--r--src/3rdparty/v8/src/jsregexp.h456
-rw-r--r--src/3rdparty/v8/src/lazy-instance.h2
-rw-r--r--src/3rdparty/v8/src/list-inl.h31
-rw-r--r--src/3rdparty/v8/src/list.h11
-rw-r--r--src/3rdparty/v8/src/lithium-allocator.cc2
-rw-r--r--src/3rdparty/v8/src/liveedit-debugger.js5
-rw-r--r--src/3rdparty/v8/src/liveedit.cc62
-rw-r--r--src/3rdparty/v8/src/macros.py10
-rw-r--r--src/3rdparty/v8/src/mark-compact-inl.h28
-rw-r--r--src/3rdparty/v8/src/mark-compact.cc300
-rw-r--r--src/3rdparty/v8/src/mark-compact.h66
-rw-r--r--src/3rdparty/v8/src/math.js1
-rw-r--r--src/3rdparty/v8/src/messages.js197
-rw-r--r--src/3rdparty/v8/src/mips/assembler-mips.cc9
-rw-r--r--src/3rdparty/v8/src/mips/assembler-mips.h2
-rw-r--r--src/3rdparty/v8/src/mips/code-stubs-mips.cc136
-rw-r--r--src/3rdparty/v8/src/mips/constants-mips.h5
-rw-r--r--src/3rdparty/v8/src/mips/debug-mips.cc4
-rw-r--r--src/3rdparty/v8/src/mips/deoptimizer-mips.cc15
-rw-r--r--src/3rdparty/v8/src/mips/full-codegen-mips.cc357
-rw-r--r--src/3rdparty/v8/src/mips/ic-mips.cc47
-rw-r--r--src/3rdparty/v8/src/mips/lithium-codegen-mips.cc174
-rw-r--r--src/3rdparty/v8/src/mips/lithium-codegen-mips.h8
-rw-r--r--src/3rdparty/v8/src/mips/lithium-mips.cc78
-rw-r--r--src/3rdparty/v8/src/mips/lithium-mips.h71
-rw-r--r--src/3rdparty/v8/src/mips/macro-assembler-mips.cc2
-rw-r--r--src/3rdparty/v8/src/mips/macro-assembler-mips.h5
-rw-r--r--src/3rdparty/v8/src/mips/regexp-macro-assembler-mips.cc61
-rw-r--r--src/3rdparty/v8/src/mips/stub-cache-mips.cc148
-rw-r--r--src/3rdparty/v8/src/mirror-debugger.js88
-rw-r--r--src/3rdparty/v8/src/objects-debug.cc91
-rw-r--r--src/3rdparty/v8/src/objects-inl.h206
-rw-r--r--src/3rdparty/v8/src/objects-printer.cc35
-rw-r--r--src/3rdparty/v8/src/objects-visiting-inl.h4
-rw-r--r--src/3rdparty/v8/src/objects-visiting.cc1
-rw-r--r--src/3rdparty/v8/src/objects-visiting.h17
-rw-r--r--src/3rdparty/v8/src/objects.cc349
-rw-r--r--src/3rdparty/v8/src/objects.h201
-rw-r--r--src/3rdparty/v8/src/parser.cc65
-rw-r--r--src/3rdparty/v8/src/platform-cygwin.cc13
-rw-r--r--src/3rdparty/v8/src/platform-freebsd.cc14
-rw-r--r--src/3rdparty/v8/src/platform-linux.cc32
-rw-r--r--src/3rdparty/v8/src/platform-macos.cc13
-rw-r--r--src/3rdparty/v8/src/platform-nullos.cc5
-rw-r--r--src/3rdparty/v8/src/platform-openbsd.cc13
-rw-r--r--src/3rdparty/v8/src/platform-posix.cc35
-rw-r--r--src/3rdparty/v8/src/platform-qnx.cc1078
-rw-r--r--src/3rdparty/v8/src/platform-solaris.cc15
-rw-r--r--src/3rdparty/v8/src/platform-win32.cc31
-rw-r--r--src/3rdparty/v8/src/platform.h6
-rw-r--r--src/3rdparty/v8/src/preparser.cc10
-rw-r--r--src/3rdparty/v8/src/preparser.h15
-rw-r--r--src/3rdparty/v8/src/prettyprinter.cc3
-rw-r--r--src/3rdparty/v8/src/profile-generator-inl.h49
-rw-r--r--src/3rdparty/v8/src/profile-generator.cc1866
-rw-r--r--src/3rdparty/v8/src/profile-generator.h360
-rw-r--r--src/3rdparty/v8/src/property.h7
-rw-r--r--src/3rdparty/v8/src/regexp.js21
-rw-r--r--src/3rdparty/v8/src/runtime.cc608
-rw-r--r--src/3rdparty/v8/src/runtime.h19
-rw-r--r--src/3rdparty/v8/src/runtime.js2
-rwxr-xr-xsrc/3rdparty/v8/src/scanner.cc18
-rw-r--r--src/3rdparty/v8/src/scanner.h9
-rw-r--r--src/3rdparty/v8/src/scopeinfo.cc22
-rw-r--r--src/3rdparty/v8/src/scopes.cc128
-rw-r--r--src/3rdparty/v8/src/scopes.h39
-rw-r--r--src/3rdparty/v8/src/serialize.cc2
-rw-r--r--src/3rdparty/v8/src/spaces-inl.h18
-rw-r--r--src/3rdparty/v8/src/spaces.cc19
-rw-r--r--src/3rdparty/v8/src/spaces.h13
-rw-r--r--src/3rdparty/v8/src/string.js147
-rw-r--r--src/3rdparty/v8/src/stub-cache.cc23
-rw-r--r--src/3rdparty/v8/src/stub-cache.h5
-rw-r--r--src/3rdparty/v8/src/utils.cc15
-rw-r--r--src/3rdparty/v8/src/utils.h26
-rw-r--r--src/3rdparty/v8/src/v8.cc3
-rw-r--r--src/3rdparty/v8/src/v8globals.h4
-rw-r--r--src/3rdparty/v8/src/v8utils.h9
-rw-r--r--src/3rdparty/v8/src/variables.cc3
-rw-r--r--src/3rdparty/v8/src/variables.h6
-rw-r--r--src/3rdparty/v8/src/version.cc4
-rw-r--r--src/3rdparty/v8/src/x64/assembler-x64.h3
-rw-r--r--src/3rdparty/v8/src/x64/code-stubs-x64.cc115
-rw-r--r--src/3rdparty/v8/src/x64/debug-x64.cc15
-rw-r--r--src/3rdparty/v8/src/x64/deoptimizer-x64.cc16
-rw-r--r--src/3rdparty/v8/src/x64/full-codegen-x64.cc336
-rw-r--r--src/3rdparty/v8/src/x64/ic-x64.cc22
-rw-r--r--src/3rdparty/v8/src/x64/lithium-codegen-x64.cc296
-rw-r--r--src/3rdparty/v8/src/x64/lithium-codegen-x64.h11
-rw-r--r--src/3rdparty/v8/src/x64/lithium-x64.cc78
-rw-r--r--src/3rdparty/v8/src/x64/lithium-x64.h83
-rw-r--r--src/3rdparty/v8/src/x64/macro-assembler-x64.cc16
-rw-r--r--src/3rdparty/v8/src/x64/macro-assembler-x64.h7
-rw-r--r--src/3rdparty/v8/src/x64/stub-cache-x64.cc122
-rw-r--r--src/3rdparty/v8/test/cctest/test-accessors.cc9
-rw-r--r--src/3rdparty/v8/test/cctest/test-alloc.cc36
-rw-r--r--src/3rdparty/v8/test/cctest/test-api.cc323
-rw-r--r--src/3rdparty/v8/test/cctest/test-debug.cc64
-rw-r--r--src/3rdparty/v8/test/cctest/test-decls.cc16
-rw-r--r--src/3rdparty/v8/test/cctest/test-double.cc15
-rw-r--r--src/3rdparty/v8/test/cctest/test-heap-profiler.cc436
-rw-r--r--src/3rdparty/v8/test/cctest/test-heap.cc106
-rw-r--r--src/3rdparty/v8/test/cctest/test-list.cc12
-rw-r--r--src/3rdparty/v8/test/cctest/test-mark-compact.cc2
-rw-r--r--src/3rdparty/v8/test/cctest/test-regexp.cc75
-rw-r--r--src/3rdparty/v8/test/cctest/test-strings.cc52
-rw-r--r--src/3rdparty/v8/test/cctest/test-weakmaps.cc80
-rw-r--r--src/3rdparty/v8/test/cctest/testcfg.py2
-rw-r--r--src/3rdparty/v8/test/mjsunit/array-bounds-check-removal.js145
-rw-r--r--src/3rdparty/v8/test/mjsunit/big-array-literal.js3
-rw-r--r--src/3rdparty/v8/test/mjsunit/compiler/alloc-object-huge.js2
-rw-r--r--src/3rdparty/v8/test/mjsunit/compiler/inline-arguments.js67
-rw-r--r--src/3rdparty/v8/test/mjsunit/compiler/inline-construct.js6
-rw-r--r--src/3rdparty/v8/test/mjsunit/compiler/literals.js24
-rw-r--r--src/3rdparty/v8/test/mjsunit/compiler/optimize-bitnot.js42
-rw-r--r--src/3rdparty/v8/test/mjsunit/debug-evaluate-locals-optimized-double.js17
-rw-r--r--src/3rdparty/v8/test/mjsunit/debug-evaluate-locals-optimized.js17
-rw-r--r--src/3rdparty/v8/test/mjsunit/debug-function-scopes.js162
-rw-r--r--src/3rdparty/v8/test/mjsunit/debug-liveedit-stack-padding.js88
-rw-r--r--src/3rdparty/v8/test/mjsunit/debug-scripts-request.js6
-rw-r--r--src/3rdparty/v8/test/mjsunit/debug-stepin-builtin-callback.js157
-rw-r--r--src/3rdparty/v8/test/mjsunit/declare-locally.js6
-rw-r--r--src/3rdparty/v8/test/mjsunit/error-constructors.js101
-rw-r--r--src/3rdparty/v8/test/mjsunit/harmony/debug-function-scopes.js115
-rw-r--r--src/3rdparty/v8/test/mjsunit/harmony/module-linking.js121
-rw-r--r--src/3rdparty/v8/test/mjsunit/harmony/module-parsing.js10
-rw-r--r--src/3rdparty/v8/test/mjsunit/harmony/module-resolution.js2
-rw-r--r--src/3rdparty/v8/test/mjsunit/math-floor-of-div.js216
-rw-r--r--src/3rdparty/v8/test/mjsunit/mjsunit.js2
-rw-r--r--src/3rdparty/v8/test/mjsunit/mjsunit.status1
-rw-r--r--src/3rdparty/v8/test/mjsunit/regexp-capture-3.js218
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-1119.js12
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-115452.js19
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-1170.js64
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-117409.js52
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-119609.js71
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-1217.js2
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-123512.js78
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-123919.js47
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-124594.js50
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-125515.js41
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-126412.js33
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-128018.js35
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-128146.js38
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-1639-2.js5
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-1639.js22
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-2071.js79
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-2110.js53
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-crbug-122271.js49
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-crbug-126414.js32
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-fast-literal-transition.js62
-rw-r--r--src/3rdparty/v8/test/mjsunit/regress/regress-transcendental.js49
-rw-r--r--src/3rdparty/v8/test/mozilla/mozilla.status14
-rw-r--r--src/3rdparty/v8/test/sputnik/sputnik.status40
-rw-r--r--src/3rdparty/v8/test/test262/README4
-rw-r--r--src/3rdparty/v8/test/test262/test262.status24
-rw-r--r--src/3rdparty/v8/test/test262/testcfg.py15
-rw-r--r--src/3rdparty/v8/tools/check-static-initializers.sh14
-rw-r--r--src/3rdparty/v8/tools/common-includes.sh3
-rwxr-xr-xsrc/3rdparty/v8/tools/grokdump.py114
-rw-r--r--src/3rdparty/v8/tools/gyp/v8.gyp58
-rw-r--r--src/3rdparty/v8/tools/js2c.py4
-rw-r--r--src/3rdparty/v8/tools/jsmin.py2
-rwxr-xr-xsrc/3rdparty/v8/tools/presubmit.py8
-rwxr-xr-xsrc/3rdparty/v8/tools/push-to-trunk.sh9
-rwxr-xr-xsrc/3rdparty/v8/tools/test-wrapper-gypbuild.py21
267 files changed, 13158 insertions, 9460 deletions
diff --git a/src/3rdparty/v8/ChangeLog b/src/3rdparty/v8/ChangeLog
index 25eaf56..97dac40 100644
--- a/src/3rdparty/v8/ChangeLog
+++ b/src/3rdparty/v8/ChangeLog
@@ -1,3 +1,193 @@
+2012-05-22: Version 3.11.4
+
+ Some cleanup to common.gypi. This fixes some host/target combinations
+ that weren't working in the Make build on Mac.
+
+ Handle EINTR in socket functions and continue incomplete sends.
+ (issue 2098)
+
+ Fixed python deprecations. (issue 1391)
+
+ Made socket send and receive more robust and return 0 on failure.
+ (Chromium issue 15719)
+
+ Fixed GCC 4.7 (C++11) compilation. (issue 2136)
+
+ Set '-m32' option for host and target platforms
+
+ Performance and stability improvements on all platforms.
+
+
+2012-05-18: Version 3.11.3
+
+ Disable optimization for functions that have scopes that cannot be
+ reconstructed from the context chain. (issue 2071)
+
+ Define V8_EXPORT to nothing for clients of v8. (Chromium issue 90078)
+
+ Correctly check for native error objects. (Chromium issue 2138)
+
+ Performance and stability improvements on all platforms.
+
+
+2012-05-16: Version 3.11.2
+
+ Revert r11496. (Chromium issue 128146)
+
+ Implement map collection for incremental marking. (issue 1465)
+
+ Add toString method to CallSite (which describes a frame of the
+ stack trace).
+
+
+2012-05-15: Version 3.11.1
+
+ Added a readbuffer function to d8 that reads a file into an ArrayBuffer.
+
+ Fix freebsd build. (V8 issue 2126)
+
+ Performance and stability improvements on all platforms.
+
+
+2012-05-11: Version 3.11.0
+
+ Fixed compose-discard crasher from r11524 (issue 2123).
+
+ Activated new global semantics by default. Global variables can
+ now shadow properties of the global object (ES5.1 erratum).
+
+ Properly set ElementsKind of empty FAST_DOUBLE_ELEMENTS arrays when
+ transitioning (Chromium issue 117409).
+
+ Made Error.prototype.name writable again, as required by the spec and
+ the web (Chromium issue 69187).
+
+ Implemented map collection with incremental marking (issue 1465).
+
+ Regexp: Fixed overflow in min-match-length calculation
+ (Chromium issue 126412).
+
+ MIPS: Fixed illegal instruction use on Loongson in code for
+ Math.random() (issue 2115).
+
+ Fixed crash bug in VisitChoice (Chromium issue 126272).
+
+ Fixed unsigned-Smi check in MappedArgumentsLookup
+ (Chromium issue 126414).
+
+ Fixed LiveEdit for function with no locals (issue 825).
+
+ Fixed register clobbering in LoadIC for interceptors
+ (Chromium issue 125988).
+
+ Implemented clearing of CompareICs (issue 2102).
+
+ Performance and stability improvements on all platforms.
+
+
+2012-05-03: Version 3.10.8
+
+ Enabled MIPS cross-compilation.
+
+ Ensured reload of elements pointer in StoreFastDoubleElement stub.
+ (Chromium issue 125515)
+
+ Fixed corner cases in truncation behavior when storing to
+ TypedArrays. (issue 2110)
+
+ Fixed failure to properly recognize and report out-of-memory
+ conditions when allocating code space pages. (Chromium issue
+ 118625)
+
+ Fixed idle notifications to perform a round of incremental GCs
+ after context disposal. (issue 2107)
+
+ Fixed preparser for try statement. (issue 2109)
+
+ Performance and stability improvements on all platforms.
+
+
+2012-04-30: Version 3.10.7
+
+ Performance and stability improvements on all platforms.
+
+
+2012-04-26: Version 3.10.6
+
+ Fixed some bugs in accessing details of the last regexp match.
+
+ Fixed source property of empty RegExp objects. (issue 1982)
+
+ Enabled inlining some V8 API functions.
+
+ Performance and stability improvements on all platforms.
+
+
+2012-04-23: Version 3.10.5
+
+ Put new global var semantics behind a flag until WebKit tests are
+ cleaned up.
+
+ Enabled stepping into callback passed to builtins.
+ (Chromium issue 109564)
+
+ Performance and stability improvements on all platforms.
+
+
+2012-04-19: Version 3.10.4
+
+ Fixed issues when stressing compaction with WeakMaps.
+
+ Fixed missing GVN flag for new-space promotion. (Chromium issue 123919)
+
+ Simplify invocation sequence at monomorphic function invocation sites.
+ (issue 2079)
+
+ Performance and stability improvements on all platforms.
+
+
+2012-04-17: Version 3.10.3
+
+ Fixed several bugs in heap profiles (including issue 2078).
+
+ Throw syntax errors on illegal escape sequences.
+
+ Implemented rudimentary module linking (behind --harmony flag)
+
+ Implemented ES5 erratum: Global declarations should shadow
+ inherited properties.
+
+ Made handling of const more consistent when combined with 'eval'
+ and 'with'.
+
+ Fixed V8 on MinGW-x64 (issue 2026).
+
+ Performance and stability improvements on all platforms.
+
+
+2012-04-13: Version 3.10.2
+
+ Fixed native ARM build (issues 1744, 539)
+
+ Return LOOKUP variable instead of CONTEXT for non-context allocated
+ outer scope parameters (Chromium issue 119609).
+
+ Fixed regular and ElementsKind transitions interfering with each other
+ (Chromium issue 122271).
+
+ Improved performance of keyed loads/stores which have a HeapNumber
+ index (issues 1388, 1295).
+
+ Fixed WeakMap processing for evacuation candidates (issue 2060).
+
+ Bailout on possible direct eval calls (Chromium issue 122681).
+
+ Do not assume that names of function expressions are context-allocated
+ (issue 2051).
+
+ Performance and stability improvements on all platforms.
+
+
2012-04-10: Version 3.10.1
Fixed bug with arguments object in inlined functions (issue 2045).
diff --git a/src/3rdparty/v8/DEPS b/src/3rdparty/v8/DEPS
new file mode 100644
index 0000000..e50d1d2
--- /dev/null
+++ b/src/3rdparty/v8/DEPS
@@ -0,0 +1,27 @@
+# Note: The buildbots evaluate this file with CWD set to the parent
+# directory and assume that the root of the checkout is in ./v8/, so
+# all paths in here must match this assumption.
+
+deps = {
+ # Remember to keep the revision in sync with the Makefile.
+ "v8/build/gyp":
+ "http://gyp.googlecode.com/svn/trunk@1282",
+}
+
+deps_os = {
+ "win": {
+ "v8/third_party/cygwin":
+ "http://src.chromium.org/svn/trunk/deps/third_party/cygwin@66844",
+
+ "v8/third_party/python_26":
+ "http://src.chromium.org/svn/trunk/tools/third_party/python_26@89111",
+ }
+}
+
+hooks = [
+ {
+ # A change to a .gyp, .gypi, or to GYP itself should run the generator.
+ "pattern": ".",
+ "action": ["python", "v8/build/gyp_v8"],
+ },
+]
diff --git a/src/3rdparty/v8/Makefile b/src/3rdparty/v8/Makefile
index da1d688..0d825c0 100644
--- a/src/3rdparty/v8/Makefile
+++ b/src/3rdparty/v8/Makefile
@@ -137,6 +137,12 @@ ENVFILE = $(OUTDIR)/environment
# Target definitions. "all" is the default.
all: $(MODES)
+# Special target for the buildbots to use. Depends on $(OUTDIR)/Makefile
+# having been created before.
+buildbot:
+ $(MAKE) -C "$(OUTDIR)" BUILDTYPE=$(BUILDTYPE) \
+ builddir="$(abspath $(OUTDIR))/$(BUILDTYPE)"
+
# Compile targets. MODES and ARCHES are convenience targets.
.SECONDEXPANSION:
$(MODES): $(addsuffix .$$@,$(DEFAULT_ARCHES))
@@ -144,21 +150,21 @@ $(MODES): $(addsuffix .$$@,$(DEFAULT_ARCHES))
$(ARCHES): $(addprefix $$@.,$(MODES))
# Defines how to build a particular target (e.g. ia32.release).
-$(BUILDS): $(OUTDIR)/Makefile-$$(basename $$@)
- @$(MAKE) -C "$(OUTDIR)" -f Makefile-$(basename $@) \
+$(BUILDS): $(OUTDIR)/Makefile.$$(basename $$@)
+ @$(MAKE) -C "$(OUTDIR)" -f Makefile.$(basename $@) \
CXX="$(CXX)" LINK="$(LINK)" \
BUILDTYPE=$(shell echo $(subst .,,$(suffix $@)) | \
python -c "print raw_input().capitalize()") \
builddir="$(shell pwd)/$(OUTDIR)/$@"
-native: $(OUTDIR)/Makefile-native
- @$(MAKE) -C "$(OUTDIR)" -f Makefile-native \
+native: $(OUTDIR)/Makefile.native
+ @$(MAKE) -C "$(OUTDIR)" -f Makefile.native \
CXX="$(CXX)" LINK="$(LINK)" BUILDTYPE=Release \
builddir="$(shell pwd)/$(OUTDIR)/$@"
# TODO(jkummerow): add "android.debug" when we need it.
-android android.release: $(OUTDIR)/Makefile-android
- @$(MAKE) -C "$(OUTDIR)" -f Makefile-android \
+android android.release: $(OUTDIR)/Makefile.android
+ @$(MAKE) -C "$(OUTDIR)" -f Makefile.android \
CXX="$(ANDROID_TOOL_PREFIX)-g++" \
AR="$(ANDROID_TOOL_PREFIX)-ar" \
RANLIB="$(ANDROID_TOOL_PREFIX)-ranlib" \
@@ -191,61 +197,41 @@ native.check: native
--arch-and-mode=. $(TESTFLAGS)
# Clean targets. You can clean each architecture individually, or everything.
-$(addsuffix .clean,$(ARCHES)):
- rm -f $(OUTDIR)/Makefile-$(basename $@)
+$(addsuffix .clean,$(ARCHES)) android.clean:
+ rm -f $(OUTDIR)/Makefile.$(basename $@)
rm -rf $(OUTDIR)/$(basename $@).release
rm -rf $(OUTDIR)/$(basename $@).debug
- find $(OUTDIR) -regex '.*\(host\|target\)-$(basename $@)\.mk' -delete
+ find $(OUTDIR) -regex '.*\(host\|target\).$(basename $@)\.mk' -delete
native.clean:
- rm -f $(OUTDIR)/Makefile-native
+ rm -f $(OUTDIR)/Makefile.native
rm -rf $(OUTDIR)/native
- find $(OUTDIR) -regex '.*\(host\|target\)-native\.mk' -delete
-
-android.clean:
- rm -f $(OUTDIR)/Makefile-android
- rm -rf $(OUTDIR)/android.release
- find $(OUTDIR) -regex '.*\(host\|target\)-android\.mk' -delete
+ find $(OUTDIR) -regex '.*\(host\|target\).native\.mk' -delete
-clean: $(addsuffix .clean,$(ARCHES)) native.clean
+clean: $(addsuffix .clean,$(ARCHES)) native.clean android.clean
# GYP file generation targets.
-$(OUTDIR)/Makefile-ia32: $(GYPFILES) $(ENVFILE)
- GYP_GENERATORS=make \
- build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
- -Ibuild/standalone.gypi --depth=. -Dtarget_arch=ia32 \
- -S-ia32 $(GYPFLAGS)
-
-$(OUTDIR)/Makefile-x64: $(GYPFILES) $(ENVFILE)
- GYP_GENERATORS=make \
- build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
- -Ibuild/standalone.gypi --depth=. -Dtarget_arch=x64 \
- -S-x64 $(GYPFLAGS)
-
-$(OUTDIR)/Makefile-arm: $(GYPFILES) $(ENVFILE) build/armu.gypi
- GYP_GENERATORS=make \
- build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
- -Ibuild/standalone.gypi --depth=. -Ibuild/armu.gypi \
- -S-arm $(GYPFLAGS)
-
-$(OUTDIR)/Makefile-mips: $(GYPFILES) $(ENVFILE) build/mipsu.gypi
+MAKEFILES = $(addprefix $(OUTDIR)/Makefile.,$(ARCHES))
+$(MAKEFILES): $(GYPFILES) $(ENVFILE)
GYP_GENERATORS=make \
build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
- -Ibuild/standalone.gypi --depth=. -Ibuild/mipsu.gypi \
- -S-mips $(GYPFLAGS)
+ -Ibuild/standalone.gypi --depth=. \
+ -Dv8_target_arch=$(subst .,,$(suffix $@)) \
+ -S.$(subst .,,$(suffix $@)) $(GYPFLAGS)
-$(OUTDIR)/Makefile-native: $(GYPFILES) $(ENVFILE)
+$(OUTDIR)/Makefile.native: $(GYPFILES) $(ENVFILE)
GYP_GENERATORS=make \
build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
- -Ibuild/standalone.gypi --depth=. -S-native $(GYPFLAGS)
+ -Ibuild/standalone.gypi --depth=. -S.native $(GYPFLAGS)
-$(OUTDIR)/Makefile-android: $(GYPFILES) $(ENVFILE) build/android.gypi \
+$(OUTDIR)/Makefile.android: $(GYPFILES) $(ENVFILE) build/android.gypi \
must-set-ANDROID_NDK_ROOT
GYP_GENERATORS=make \
CC="${ANDROID_TOOL_PREFIX}-gcc" \
+ CXX="${ANDROID_TOOL_PREFIX}-g++" \
build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
-Ibuild/standalone.gypi --depth=. -Ibuild/android.gypi \
- -S-android $(GYPFLAGS)
+ -S.android $(GYPFLAGS)
must-set-ANDROID_NDK_ROOT:
ifndef ANDROID_NDK_ROOT
@@ -261,7 +247,8 @@ $(ENVFILE): $(ENVFILE).new
# Stores current GYPFLAGS in a file.
$(ENVFILE).new:
- @mkdir -p $(OUTDIR); echo "GYPFLAGS=$(GYPFLAGS)" > $(ENVFILE).new;
+ @mkdir -p $(OUTDIR); echo "GYPFLAGS=$(GYPFLAGS)" > $(ENVFILE).new; \
+ echo "CXX=$(CXX)" >> $(ENVFILE).new
# Dependencies.
dependencies:
diff --git a/src/3rdparty/v8/SConstruct b/src/3rdparty/v8/SConstruct
index 34d0efc..ebce7ff 100644
--- a/src/3rdparty/v8/SConstruct
+++ b/src/3rdparty/v8/SConstruct
@@ -101,14 +101,14 @@ LIBRARY_FLAGS = {
'os:linux': {
'CCFLAGS': ['-ansi'] + GCC_EXTRA_CCFLAGS,
'library:shared': {
- 'CPPDEFINES': ['V8_SHARED'],
+ 'CPPDEFINES': ['V8_SHARED', 'BUILDING_V8_SHARED'],
'LIBS': ['pthread']
}
},
'os:macos': {
'CCFLAGS': ['-ansi', '-mmacosx-version-min=10.4'],
'library:shared': {
- 'CPPDEFINES': ['V8_SHARED']
+ 'CPPDEFINES': ['V8_SHARED', 'BUILDING_V8_SHARED'],
}
},
'os:freebsd': {
@@ -1601,4 +1601,17 @@ except:
pass
+def WarnAboutDeprecation():
+ print """
+#######################################################
+# WARNING: Building V8 with SCons is deprecated and #
+# will not work much longer. Please switch to using #
+# the GYP-based build now. Instructions are at #
+# http://code.google.com/p/v8/wiki/BuildingWithGYP. #
+#######################################################
+ """
+
+WarnAboutDeprecation()
+import atexit
+atexit.register(WarnAboutDeprecation)
Build()
diff --git a/src/3rdparty/v8/build/armu.gypi b/src/3rdparty/v8/build/armu.gypi
deleted file mode 100644
index d15b8ab..0000000
--- a/src/3rdparty/v8/build/armu.gypi
+++ /dev/null
@@ -1,36 +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.
-
-{
- 'variables': {
- 'target_arch': 'ia32',
- 'v8_target_arch': 'arm',
- 'armv7': 1,
- 'arm_neon': 0,
- 'arm_fpu': 'vfpv3',
- },
-}
diff --git a/src/3rdparty/v8/build/common.gypi b/src/3rdparty/v8/build/common.gypi
index 3016d0c..1726d2a 100644
--- a/src/3rdparty/v8/build/common.gypi
+++ b/src/3rdparty/v8/build/common.gypi
@@ -110,148 +110,117 @@
['v8_enable_gdbjit==1', {
'defines': ['ENABLE_GDB_JIT_INTERFACE',],
}],
- ['OS!="mac"', {
- # TODO(mark): The OS!="mac" conditional is temporary. It can be
- # removed once the Mac Chromium build stops setting target_arch to
- # ia32 and instead sets it to mac. Other checks in this file for
- # OS=="mac" can be removed at that time as well. This can be cleaned
- # up once http://crbug.com/44205 is fixed.
+ ['v8_target_arch=="arm"', {
+ 'defines': [
+ 'V8_TARGET_ARCH_ARM',
+ ],
'conditions': [
- ['v8_target_arch=="arm"', {
+ [ 'v8_can_use_unaligned_accesses=="true"', {
'defines': [
- 'V8_TARGET_ARCH_ARM',
+ 'CAN_USE_UNALIGNED_ACCESSES=1',
],
- 'conditions': [
- [ 'v8_can_use_unaligned_accesses=="true"', {
- 'defines': [
- 'CAN_USE_UNALIGNED_ACCESSES=1',
- ],
- }],
- [ 'v8_can_use_unaligned_accesses=="false"', {
- 'defines': [
- 'CAN_USE_UNALIGNED_ACCESSES=0',
- ],
- }],
- [ 'v8_can_use_vfp_instructions=="true"', {
- 'defines': [
- 'CAN_USE_VFP_INSTRUCTIONS',
- ],
- }],
- [ 'v8_use_arm_eabi_hardfloat=="true"', {
- 'defines': [
- 'USE_EABI_HARDFLOAT=1',
- 'CAN_USE_VFP_INSTRUCTIONS',
- ],
- 'target_conditions': [
- ['_toolset=="target"', {
- 'cflags': ['-mfloat-abi=hard',],
- }],
- ],
- }, {
- 'defines': [
- 'USE_EABI_HARDFLOAT=0',
- ],
- }],
- # The ARM assembler assumes the host is 32 bits,
- # so force building 32-bit host tools.
- ['host_arch=="x64" or OS=="android"', {
- 'target_conditions': [
- ['_toolset=="host"', {
- 'cflags': ['-m32'],
- 'ldflags': ['-m32'],
- }],
- ],
- }],
+ }],
+ [ 'v8_can_use_unaligned_accesses=="false"', {
+ 'defines': [
+ 'CAN_USE_UNALIGNED_ACCESSES=0',
],
}],
- ['v8_target_arch=="ia32"', {
+ [ 'v8_can_use_vfp_instructions=="true"', {
'defines': [
- 'V8_TARGET_ARCH_IA32',
+ 'CAN_USE_VFP_INSTRUCTIONS',
],
}],
- ['v8_target_arch=="mips"', {
+ [ 'v8_use_arm_eabi_hardfloat=="true"', {
'defines': [
- 'V8_TARGET_ARCH_MIPS',
+ 'USE_EABI_HARDFLOAT=1',
+ 'CAN_USE_VFP_INSTRUCTIONS',
],
- 'conditions': [
- [ 'target_arch=="mips"', {
- 'target_conditions': [
- ['_toolset=="target"', {
- 'cflags': ['-EL'],
- 'ldflags': ['-EL'],
- 'conditions': [
- [ 'v8_use_mips_abi_hardfloat=="true"', {
- 'cflags': ['-mhard-float'],
- 'ldflags': ['-mhard-float'],
- }, {
- 'cflags': ['-msoft-float'],
- 'ldflags': ['-msoft-float'],
- }],
- ['mips_arch_variant=="mips32r2"', {
- 'cflags': ['-mips32r2', '-Wa,-mips32r2'],
- }],
- ['mips_arch_variant=="loongson"', {
- 'cflags': ['-mips3', '-Wa,-mips3'],
- }, {
- 'cflags': ['-mips32', '-Wa,-mips32'],
- }],
- ],
- }],
- ],
- }],
- [ 'v8_can_use_fpu_instructions=="true"', {
- 'defines': [
- 'CAN_USE_FPU_INSTRUCTIONS',
- ],
- }],
- [ 'v8_use_mips_abi_hardfloat=="true"', {
- 'defines': [
- '__mips_hard_float=1',
- 'CAN_USE_FPU_INSTRUCTIONS',
- ],
- }, {
- 'defines': [
- '__mips_soft_float=1'
- ],
- }],
- ['mips_arch_variant=="mips32r2"', {
- 'defines': ['_MIPS_ARCH_MIPS32R2',],
- }],
- ['mips_arch_variant=="loongson"', {
- 'defines': ['_MIPS_ARCH_LOONGSON',],
+ 'target_conditions': [
+ ['_toolset=="target"', {
+ 'cflags': ['-mfloat-abi=hard',],
}],
- # The MIPS assembler assumes the host is 32 bits,
- # so force building 32-bit host tools.
- ['host_arch=="x64"', {
- 'target_conditions': [
- ['_toolset=="host"', {
- 'cflags': ['-m32'],
- 'ldflags': ['-m32'],
+ ],
+ }, {
+ 'defines': [
+ 'USE_EABI_HARDFLOAT=0',
+ ],
+ }],
+ ],
+ }], # v8_target_arch=="arm"
+ ['v8_target_arch=="ia32"', {
+ 'defines': [
+ 'V8_TARGET_ARCH_IA32',
+ ],
+ }], # v8_target_arch=="ia32"
+ ['v8_target_arch=="mips"', {
+ 'defines': [
+ 'V8_TARGET_ARCH_MIPS',
+ ],
+ 'variables': {
+ 'mipscompiler': '<!($(echo ${CXX:-$(which g++)}) -v 2>&1 | grep -q "^Target: mips-" && echo "yes" || echo "no")',
+ },
+ 'conditions': [
+ ['mipscompiler=="yes"', {
+ 'target_conditions': [
+ ['_toolset=="target"', {
+ 'cflags': ['-EL'],
+ 'ldflags': ['-EL'],
+ 'conditions': [
+ [ 'v8_use_mips_abi_hardfloat=="true"', {
+ 'cflags': ['-mhard-float'],
+ 'ldflags': ['-mhard-float'],
+ }, {
+ 'cflags': ['-msoft-float'],
+ 'ldflags': ['-msoft-float'],
+ }],
+ ['mips_arch_variant=="mips32r2"', {
+ 'cflags': ['-mips32r2', '-Wa,-mips32r2'],
+ }],
+ ['mips_arch_variant=="loongson"', {
+ 'cflags': ['-mips3', '-Wa,-mips3'],
+ }, {
+ 'cflags': ['-mips32', '-Wa,-mips32'],
}],
],
}],
],
}],
- ['v8_target_arch=="x64"', {
+ [ 'v8_can_use_fpu_instructions=="true"', {
'defines': [
- 'V8_TARGET_ARCH_X64',
+ 'CAN_USE_FPU_INSTRUCTIONS',
],
}],
- ],
- }, { # Section for OS=="mac".
- 'conditions': [
- ['target_arch=="ia32"', {
- 'xcode_settings': {
- 'ARCHS': ['i386'],
- }
+ [ 'v8_use_mips_abi_hardfloat=="true"', {
+ 'defines': [
+ '__mips_hard_float=1',
+ 'CAN_USE_FPU_INSTRUCTIONS',
+ ],
+ }, {
+ 'defines': [
+ '__mips_soft_float=1'
+ ],
}],
- ['target_arch=="x64"', {
- 'xcode_settings': {
- 'ARCHS': ['x86_64'],
- }
+ ['mips_arch_variant=="mips32r2"', {
+ 'defines': ['_MIPS_ARCH_MIPS32R2',],
+ }],
+ ['mips_arch_variant=="loongson"', {
+ 'defines': ['_MIPS_ARCH_LOONGSON',],
}],
],
- }],
+ }], # v8_target_arch=="mips"
+ ['v8_target_arch=="x64"', {
+ 'defines': [
+ 'V8_TARGET_ARCH_X64',
+ ],
+ 'xcode_settings': {
+ 'ARCHS': [ 'x86_64' ],
+ },
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'StackReserveSize': '2097152',
+ },
+ },
+ }], # v8_target_arch=="x64"
['v8_use_liveobjectlist=="true"', {
'defines': [
'ENABLE_DEBUGGER_SUPPORT',
@@ -280,10 +249,6 @@
['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris" \
or OS=="netbsd"', {
'conditions': [
- [ 'target_arch=="ia32"', {
- 'cflags': [ '-m32' ],
- 'ldflags': [ '-m32' ],
- }],
[ 'v8_no_strict_aliasing==1', {
'cflags': [ '-fno-strict-aliasing' ],
}],
@@ -292,6 +257,41 @@
['OS=="solaris"', {
'defines': [ '__C99FEATURES__=1' ], # isinf() etc.
}],
+ ['(OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris" \
+ or OS=="netbsd" or OS=="mac" or OS=="android") and \
+ (v8_target_arch=="arm" or v8_target_arch=="ia32" or \
+ v8_target_arch=="mips")', {
+ # Check whether the host compiler and target compiler support the
+ # '-m32' option and set it if so.
+ 'target_conditions': [
+ ['_toolset=="host"', {
+ 'variables': {
+ 'm32flag': '<!((echo | $(echo ${CXX_host:-${CXX:-$(which g++)}}) -m32 -E - > /dev/null 2>&1) && echo -n "-m32" || true)',
+ },
+ 'cflags': [ '<(m32flag)' ],
+ 'ldflags': [ '<(m32flag)' ],
+ 'xcode_settings': {
+ 'ARCHS': [ 'i386' ],
+ },
+ }],
+ ['_toolset=="target"', {
+ 'variables': {
+ 'm32flag': '<!((echo | $(echo ${CXX_target:-${CXX:-$(which g++)}}) -m32 -E - > /dev/null 2>&1) && echo -n "-m32" || true)',
+ },
+ 'cflags': [ '<(m32flag)' ],
+ 'ldflags': [ '<(m32flag)' ],
+ 'xcode_settings': {
+ 'ARCHS': [ 'i386' ],
+ },
+ }],
+ ],
+ }],
+ ['OS=="freebsd" or OS=="openbsd"', {
+ 'cflags': [ '-I/usr/local/include' ],
+ }],
+ ['OS=="netbsd"', {
+ 'cflags': [ '-I/usr/pkg/include' ],
+ }],
], # conditions
'configurations': {
'Debug': {
@@ -315,19 +315,9 @@
},
'VCLinkerTool': {
'LinkIncremental': '2',
- # For future reference, the stack size needs to be increased
- # when building for Windows 64-bit, otherwise some test cases
- # can cause stack overflow.
- # 'StackReserveSize': '297152',
},
},
'conditions': [
- ['OS=="freebsd" or OS=="openbsd"', {
- 'cflags': [ '-I/usr/local/include' ],
- }],
- ['OS=="netbsd"', {
- 'cflags': [ '-I/usr/pkg/include' ],
- }],
['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', {
'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter',
'-Wnon-virtual-dtor', '-Woverloaded-virtual' ],
@@ -357,12 +347,6 @@
}],
],
}],
- ['OS=="freebsd" or OS=="openbsd"', {
- 'cflags': [ '-I/usr/local/include' ],
- }],
- ['OS=="netbsd"', {
- 'cflags': [ '-I/usr/pkg/include' ],
- }],
['OS=="mac"', {
'xcode_settings': {
'GCC_OPTIMIZATION_LEVEL': '3', # -O3
@@ -400,12 +384,7 @@
'VCLinkerTool': {
'LinkIncremental': '1',
'OptimizeReferences': '2',
- 'OptimizeForWindows98': '1',
'EnableCOMDATFolding': '2',
- # For future reference, the stack size needs to be
- # increased when building for Windows 64-bit, otherwise
- # some test cases can cause stack overflow.
- # 'StackReserveSize': '297152',
},
},
}], # OS=="win"
diff --git a/src/3rdparty/v8/build/gyp_v8 b/src/3rdparty/v8/build/gyp_v8
index 0fe3403..345f777 100755
--- a/src/3rdparty/v8/build/gyp_v8
+++ b/src/3rdparty/v8/build/gyp_v8
@@ -38,6 +38,11 @@ import sys
script_dir = os.path.dirname(__file__)
v8_root = os.path.normpath(os.path.join(script_dir, os.pardir))
+if __name__ == '__main__':
+ os.chdir(v8_root)
+ script_dir = os.path.dirname(__file__)
+ v8_root = '.'
+
sys.path.insert(0, os.path.join(v8_root, 'tools'))
import utils
@@ -93,7 +98,7 @@ def additional_include_files(args=[]):
result.append(path)
# Always include standalone.gypi
- AddInclude(os.path.join(script_dir, 'standalone.gypi'))
+ AddInclude(os.path.join(v8_root, 'build', 'standalone.gypi'))
# Optionally add supplemental .gypi files if present.
supplements = glob.glob(os.path.join(v8_root, '*', 'supplement.gypi'))
@@ -135,7 +140,10 @@ if __name__ == '__main__':
# path separators even on Windows due to the use of shlex.split().
args.extend(shlex.split(gyp_file))
else:
- args.append(os.path.join(script_dir, 'all.gyp'))
+ # Note that this must not start with "./" or things break.
+ # So we rely on having done os.chdir(v8_root) above and use the
+ # relative path.
+ args.append(os.path.join('build', 'all.gyp'))
args.extend(['-I' + i for i in additional_include_files(args)])
@@ -156,28 +164,6 @@ if __name__ == '__main__':
# Generate for the architectures supported on the given platform.
gyp_args = list(args)
- target_arch = None
- for p in gyp_args:
- if p.find('-Dtarget_arch=') == 0:
- target_arch = p
- if target_arch is None:
- gyp_args.append('-Dtarget_arch=ia32')
if utils.GuessOS() == 'linux':
- gyp_args.append('-S-ia32')
+ gyp_args.append('--generator-output=out')
run_gyp(gyp_args)
-
- if utils.GuessOS() == 'linux':
- gyp_args = list(args)
- gyp_args.append('-Dtarget_arch=x64')
- gyp_args.append('-S-x64')
- run_gyp(gyp_args)
-
- gyp_args = list(args)
- gyp_args.append('-I' + v8_root + '/build/armu.gypi')
- gyp_args.append('-S-armu')
- run_gyp(gyp_args)
-
- gyp_args = list(args)
- gyp_args.append('-I' + v8_root + '/build/mipsu.gypi')
- gyp_args.append('-S-mipsu')
- run_gyp(gyp_args)
diff --git a/src/3rdparty/v8/build/mipsu.gypi b/src/3rdparty/v8/build/mipsu.gypi
deleted file mode 100644
index 637ff84..0000000
--- a/src/3rdparty/v8/build/mipsu.gypi
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright 2012 the V8 project authors. All rights reserved.
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'variables': {
- 'target_arch': 'ia32',
- 'v8_target_arch': 'mips',
- },
-}
diff --git a/src/3rdparty/v8/build/standalone.gypi b/src/3rdparty/v8/build/standalone.gypi
index e9b0565..ebdf557 100644
--- a/src/3rdparty/v8/build/standalone.gypi
+++ b/src/3rdparty/v8/build/standalone.gypi
@@ -37,8 +37,9 @@
'variables': {
'variables': {
'conditions': [
- ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', {
- # This handles the Linux platforms we generally deal with.
+ ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or \
+ OS=="netbsd" or OS=="mac"', {
+ # This handles the Unix platforms we generally deal with.
# Anything else gets passed through, which probably won't work
# very well; such hosts should pass an explicit target_arch
# to gyp.
@@ -46,7 +47,8 @@
'<!(uname -m | sed -e "s/i.86/ia32/;\
s/x86_64/x64/;s/amd64/x64/;s/arm.*/arm/;s/mips.*/mips/")',
}, {
- # OS!="linux" and OS!="freebsd" and OS!="openbsd" and OS!="netbsd"
+ # OS!="linux" and OS!="freebsd" and OS!="openbsd" and
+ # OS!="netbsd" and OS!="mac"
'host_arch%': 'ia32',
}],
],
@@ -71,6 +73,10 @@
'want_separate_host_toolset': 0,
}],
],
+ # Default ARM variable settings.
+ 'armv7%': 1,
+ 'arm_neon%': 0,
+ 'arm_fpu%': 'vfpv3',
},
'target_defaults': {
'default_configuration': 'Debug',
@@ -165,6 +171,9 @@
},
}], # OS=="win"
['OS=="mac"', {
+ 'xcode_settings': {
+ 'SYMROOT': '<(DEPTH)/xcodebuild',
+ },
'target_defaults': {
'xcode_settings': {
'ALWAYS_SEARCH_USER_PATHS': 'NO',
@@ -184,6 +193,7 @@
'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof
'MACOSX_DEPLOYMENT_TARGET': '10.4', # -mmacosx-version-min=10.4
'PREBINDING': 'NO', # No -Wl,-prebind
+ 'SYMROOT': '<(DEPTH)/xcodebuild',
'USE_HEADERMAP': 'NO',
'OTHER_CFLAGS': [
'-fno-strict-aliasing',
diff --git a/src/3rdparty/v8/include/v8-debug.h b/src/3rdparty/v8/include/v8-debug.h
index 9e85dc4..9e85dc4 100644..100755
--- a/src/3rdparty/v8/include/v8-debug.h
+++ b/src/3rdparty/v8/include/v8-debug.h
diff --git a/src/3rdparty/v8/include/v8-profiler.h b/src/3rdparty/v8/include/v8-profiler.h
index e36659f..8f380f2 100644
--- a/src/3rdparty/v8/include/v8-profiler.h
+++ b/src/3rdparty/v8/include/v8-profiler.h
@@ -368,16 +368,20 @@ class V8EXPORT HeapSnapshot {
* with the following structure:
*
* {
- * snapshot: {title: "...", uid: nnn},
- * nodes: [
- * meta-info (JSON string),
- * nodes themselves
- * ],
- * strings: [strings]
+ * snapshot: {
+ * title: "...",
+ * uid: nnn,
+ * meta: { meta-info },
+ * node_count: nnn,
+ * edge_count: nnn
+ * },
+ * nodes: [nodes array],
+ * edges: [edges array],
+ * strings: [strings array]
* }
*
- * Outgoing node links are stored after each node. Nodes reference strings
- * and other nodes by their indexes in corresponding arrays.
+ * Nodes reference strings, other nodes, and edges by their indexes
+ * in corresponding arrays.
*/
void Serialize(OutputStream* stream, SerializationFormat format) const;
};
@@ -409,6 +413,19 @@ class V8EXPORT HeapProfiler {
static const HeapSnapshot* FindSnapshot(unsigned uid);
/**
+ * Returns SnapshotObjectId for a heap object referenced by |value| if
+ * it has been seen by the heap profiler, kUnknownObjectId otherwise.
+ */
+ static SnapshotObjectId GetSnapshotObjectId(Handle<Value> value);
+
+ /**
+ * A constant for invalid SnapshotObjectId. GetSnapshotObjectId will return
+ * it in case heap profiler cannot find id for the object passed as
+ * parameter. HeapSnapshot::GetNodeById will always return NULL for such id.
+ */
+ static const SnapshotObjectId kUnknownObjectId = 0;
+
+ /**
* Takes a heap snapshot and returns it. Title may be an empty string.
* See HeapSnapshot::Type for types description.
*/
@@ -418,6 +435,33 @@ class V8EXPORT HeapProfiler {
ActivityControl* control = NULL);
/**
+ * Starts tracking of heap objects population statistics. After calling
+ * this method, all heap objects relocations done by the garbage collector
+ * are being registered.
+ */
+ static void StartHeapObjectsTracking();
+
+ /**
+ * Adds a new time interval entry to the aggregated statistics array. The
+ * time interval entry contains information on the current heap objects
+ * population size. The method also updates aggregated statistics and
+ * 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.
+ *
+ * StartHeapObjectsTracking must be called before the first call to this
+ * method.
+ */
+ static void PushHeapObjectsStats(OutputStream* stream);
+
+ /**
+ * Stops tracking of heap objects population statistics, cleans up all
+ * collected data. StartHeapObjectsTracking must be called again prior to
+ * calling PushHeapObjectsStats next time.
+ */
+ static void StopHeapObjectsTracking();
+
+ /**
* Deletes all snapshots taken. All previously returned pointers to
* snapshots and their contents become invalid after this call.
*/
@@ -514,6 +558,19 @@ class V8EXPORT RetainedObjectInfo { // NOLINT
};
+/**
+ * A struct for exporting HeapStats data from V8, using "push" model.
+ * See HeapProfiler::PushHeapObjectsStats.
+ */
+struct HeapStatsUpdate {
+ HeapStatsUpdate(uint32_t index, uint32_t count, uint32_t size)
+ : index(index), count(count), size(size) { }
+ uint32_t index; // Index of the time interval that was changed.
+ uint32_t count; // New value of count field for the interval with this index.
+ uint32_t size; // New value of size field for the interval with this index.
+};
+
+
} // namespace v8
diff --git a/src/3rdparty/v8/include/v8.h b/src/3rdparty/v8/include/v8.h
index 0d371c9..d31ef54 100644
--- a/src/3rdparty/v8/include/v8.h
+++ b/src/3rdparty/v8/include/v8.h
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -62,11 +62,13 @@
#else // _WIN32
-// Setup for Linux shared library export. There is no need to distinguish
-// between building or using the V8 shared library, but we should not
-// export symbols when we are building a static library.
+// Setup for Linux shared library export.
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(V8_SHARED)
+#ifdef BUILDING_V8_SHARED
#define V8EXPORT __attribute__ ((visibility("default")))
+#else
+#define V8EXPORT
+#endif
#else // defined(__GNUC__) && (__GNUC__ >= 4)
#define V8EXPORT
#endif // defined(__GNUC__) && (__GNUC__ >= 4)
@@ -107,6 +109,7 @@ class Data;
class AccessorInfo;
class StackTrace;
class StackFrame;
+class Isolate;
namespace internal {
@@ -587,12 +590,6 @@ class ScriptOrigin {
*/
class V8EXPORT Script {
public:
- enum CompileFlags {
- Default = 0x00,
- QmlMode = 0x01,
- NativeMode = 0x02
- };
-
/**
* Compiles the specified script (context-independent).
*
@@ -611,8 +608,7 @@ class V8EXPORT Script {
static Local<Script> New(Handle<String> source,
ScriptOrigin* origin = NULL,
ScriptData* pre_data = NULL,
- Handle<String> script_data = Handle<String>(),
- CompileFlags = Default);
+ Handle<String> script_data = Handle<String>());
/**
* Compiles the specified script using the specified file name
@@ -625,8 +621,7 @@ class V8EXPORT Script {
* will use the currently entered context).
*/
static Local<Script> New(Handle<String> source,
- Handle<Value> file_name,
- CompileFlags = Default);
+ Handle<Value> file_name);
/**
* Compiles the specified script (bound to current context).
@@ -647,8 +642,7 @@ class V8EXPORT Script {
static Local<Script> Compile(Handle<String> source,
ScriptOrigin* origin = NULL,
ScriptData* pre_data = NULL,
- Handle<String> script_data = Handle<String>(),
- CompileFlags = Default);
+ Handle<String> script_data = Handle<String>());
/**
* Compiles the specified script using the specified file name
@@ -665,8 +659,7 @@ class V8EXPORT Script {
*/
static Local<Script> Compile(Handle<String> source,
Handle<Value> file_name,
- Handle<String> script_data = Handle<String>(),
- CompileFlags = Default);
+ Handle<String> script_data = Handle<String>());
/**
* Runs the script returning the resulting value. If the script is
@@ -676,7 +669,6 @@ class V8EXPORT Script {
* compiled.
*/
Local<Value> Run();
- Local<Value> Run(Handle<Object> qml);
/**
* Returns the script id value.
@@ -873,13 +865,13 @@ class Value : public Data {
* Returns true if this value is the undefined value. See ECMA-262
* 4.3.10.
*/
- V8EXPORT bool IsUndefined() const;
+ inline bool IsUndefined() const;
/**
* Returns true if this value is the null value. See ECMA-262
* 4.3.11.
*/
- V8EXPORT bool IsNull() const;
+ inline bool IsNull() const;
/**
* Returns true if this value is true.
@@ -967,11 +959,6 @@ class Value : public Data {
*/
V8EXPORT bool IsRegExp() const;
- /**
- * Returns true if this value is an Error.
- */
- V8EXPORT bool IsError() const;
-
V8EXPORT Local<Boolean> ToBoolean() const;
V8EXPORT Local<Number> ToNumber() const;
V8EXPORT Local<String> ToString() const;
@@ -998,7 +985,11 @@ class Value : public Data {
V8EXPORT bool StrictEquals(Handle<Value> that) const;
private:
+ inline bool QuickIsUndefined() const;
+ inline bool QuickIsNull() const;
inline bool QuickIsString() const;
+ V8EXPORT bool FullIsUndefined() const;
+ V8EXPORT bool FullIsNull() const;
V8EXPORT bool FullIsString() const;
};
@@ -1045,51 +1036,6 @@ class String : public Primitive {
V8EXPORT bool MayContainNonAscii() const;
/**
- * Returns the hash of this string.
- */
- V8EXPORT uint32_t Hash() const;
-
- struct CompleteHashData {
- CompleteHashData() : length(0), hash(0), symbol_id(0) {}
- int length;
- uint32_t hash;
- uint32_t symbol_id;
- };
-
- /**
- * Returns the "complete" hash of the string. This is
- * all the information about the string needed to implement
- * a very efficient hash keyed on the string.
- *
- * The members of CompleteHashData are:
- * length: The length of the string. Equivalent to Length()
- * hash: The hash of the string. Equivalent to Hash()
- * symbol_id: If the string is a sequential symbol, the symbol
- * id, otherwise 0. If the symbol ids of two strings are
- * the same (and non-zero) the two strings are identical.
- * If the symbol ids are different the strings may still be
- * identical, but an Equals() check must be performed.
- */
- V8EXPORT CompleteHashData CompleteHash() const;
-
- /**
- * Compute a hash value for the passed UTF16 string
- * data.
- */
- V8EXPORT static uint32_t ComputeHash(uint16_t *string, int length);
- V8EXPORT static uint32_t ComputeHash(char *string, int length);
-
- /**
- * Returns true if this string is equal to the external
- * string data provided.
- */
- V8EXPORT bool Equals(uint16_t *string, int length);
- V8EXPORT bool Equals(char *string, int length);
- inline bool Equals(Handle<Value> that) const {
- return v8::Value::Equals(that);
- }
-
- /**
* Write the contents of the string to an external buffer.
* If no arguments are given, expects the buffer to be large
* enough to hold the entire string and NULL terminator. Copies
@@ -1120,8 +1066,6 @@ class String : public Primitive {
NO_NULL_TERMINATION = 2
};
- V8EXPORT uint16_t GetCharacter(int index);
-
// 16-bit character codes.
V8EXPORT int Write(uint16_t* buffer,
int start = 0,
@@ -1142,6 +1086,7 @@ class String : public Primitive {
* A zero length string.
*/
V8EXPORT static v8::Local<v8::String> Empty();
+ inline static v8::Local<v8::String> Empty(Isolate* isolate);
/**
* Returns true if the string is external
@@ -1299,8 +1244,7 @@ class String : public Primitive {
* this function should not otherwise delete or modify the resource. Neither
* should the underlying buffer be deallocated or modified except through the
* destructor of the external string resource.
- */
- V8EXPORT static Local<String> NewExternal(
+ */ V8EXPORT static Local<String> NewExternal(
ExternalAsciiStringResource* resource);
/**
@@ -1623,25 +1567,6 @@ class Object : public Value {
/** Sets a native pointer in an internal field. */
V8EXPORT void SetPointerInInternalField(int index, void* value);
- class V8EXPORT ExternalResource { // NOLINT
- public:
- ExternalResource() {}
- virtual ~ExternalResource() {}
-
- protected:
- virtual void Dispose() { delete this; }
-
- private:
- // Disallow copying and assigning.
- ExternalResource(const ExternalResource&);
- void operator=(const ExternalResource&);
-
- friend class v8::internal::Heap;
- };
-
- V8EXPORT void SetExternalResource(ExternalResource *);
- V8EXPORT ExternalResource *GetExternalResource();
-
// Testers for local properties.
V8EXPORT bool HasOwnProperty(Handle<String> key);
V8EXPORT bool HasRealNamedProperty(Handle<String> key);
@@ -2050,10 +1975,13 @@ class Arguments {
inline Local<Object> Holder() const;
inline bool IsConstructCall() const;
inline Local<Value> Data() const;
+ inline Isolate* GetIsolate() const;
+
private:
- static const int kDataIndex = 0;
- static const int kCalleeIndex = -1;
- static const int kHolderIndex = -2;
+ static const int kIsolateIndex = 0;
+ static const int kDataIndex = -1;
+ static const int kCalleeIndex = -2;
+ static const int kHolderIndex = -3;
friend class ImplementationUtilities;
inline Arguments(internal::Object** implicit_args,
@@ -2075,9 +2003,11 @@ class V8EXPORT AccessorInfo {
public:
inline AccessorInfo(internal::Object** args)
: args_(args) { }
+ inline Isolate* GetIsolate() const;
inline Local<Value> Data() const;
inline Local<Object> This() const;
inline Local<Object> Holder() const;
+
private:
internal::Object** args_;
};
@@ -2365,7 +2295,6 @@ class V8EXPORT FunctionTemplate : public Template {
NamedPropertyQuery query,
NamedPropertyDeleter remover,
NamedPropertyEnumerator enumerator,
- bool is_fallback,
Handle<Value> data);
void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter,
IndexedPropertySetter setter,
@@ -2449,12 +2378,6 @@ class V8EXPORT ObjectTemplate : public Template {
NamedPropertyDeleter deleter = 0,
NamedPropertyEnumerator enumerator = 0,
Handle<Value> data = Handle<Value>());
- void SetFallbackPropertyHandler(NamedPropertyGetter getter,
- NamedPropertySetter setter = 0,
- NamedPropertyQuery query = 0,
- NamedPropertyDeleter deleter = 0,
- NamedPropertyEnumerator enumerator = 0,
- Handle<Value> data = Handle<Value>());
/**
* Sets an indexed property handler on the object template.
@@ -2526,18 +2449,6 @@ class V8EXPORT ObjectTemplate : public Template {
*/
void SetInternalFieldCount(int value);
- /**
- * Sets whether the object can store an "external resource" object.
- */
- bool HasExternalResource();
- void SetHasExternalResource(bool value);
-
- /**
- * Mark object instances of the template as using the user object
- * comparison callback.
- */
- void MarkAsUseUserObjectComparison();
-
private:
ObjectTemplate();
static Local<ObjectTemplate> New(Handle<FunctionTemplate> constructor);
@@ -2604,7 +2515,7 @@ class V8EXPORT Extension { // NOLINT
int source_length = -1);
virtual ~Extension() { }
virtual v8::Handle<v8::FunctionTemplate>
- GetNativeFunction(v8::Handle<v8::String>) {
+ GetNativeFunction(v8::Handle<v8::String> name) {
return v8::Handle<v8::FunctionTemplate>();
}
@@ -2653,6 +2564,11 @@ Handle<Primitive> V8EXPORT Null();
Handle<Boolean> V8EXPORT True();
Handle<Boolean> V8EXPORT False();
+inline Handle<Primitive> Undefined(Isolate* isolate);
+inline Handle<Primitive> Null(Isolate* isolate);
+inline Handle<Boolean> True(Isolate* isolate);
+inline Handle<Boolean> False(Isolate* isolate);
+
/**
* A set of constraints that specifies the limits of the runtime's memory use.
@@ -2760,10 +2676,6 @@ typedef void (*FailedAccessCheckCallback)(Local<Object> target,
AccessType type,
Local<Value> data);
-// --- User Object Comparisoa nCallback ---
-typedef bool (*UserObjectComparisonCallback)(Local<Object> lhs,
- Local<Object> rhs);
-
// --- AllowCodeGenerationFromStrings callbacks ---
/**
@@ -2907,13 +2819,13 @@ class V8EXPORT Isolate {
/**
* Associate embedder-specific data with the isolate
*/
- void SetData(void* data);
+ inline void SetData(void* data);
/**
- * Retrive embedder-specific data from the isolate.
+ * Retrieve embedder-specific data from the isolate.
* Returns NULL if SetData has never been called.
*/
- void* GetData();
+ inline void* GetData();
private:
Isolate();
@@ -2990,7 +2902,7 @@ typedef uintptr_t (*ReturnAddressLocationResolver)(
class V8EXPORT ExternalResourceVisitor { // NOLINT
public:
virtual ~ExternalResourceVisitor() {}
- virtual void VisitExternalString(Handle<String>) {}
+ virtual void VisitExternalString(Handle<String> string) {}
};
@@ -3115,9 +3027,6 @@ class V8EXPORT V8 {
/** Callback function for reporting failed access checks.*/
static void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback);
- /** Callback for user object comparisons */
- static void SetUserObjectComparisonCallbackFunction(UserObjectComparisonCallback);
-
/**
* Enables the host application to receive a notification before a
* garbage collection. Allocations are not allowed in the
@@ -3261,7 +3170,8 @@ class V8EXPORT V8 {
* that is kept alive by JavaScript objects.
* \returns the adjusted value.
*/
- static int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes);
+ static intptr_t AdjustAmountOfExternalAllocatedMemory(
+ intptr_t change_in_bytes);
/**
* Suspends recording of tick samples in the profiler.
@@ -3619,8 +3529,6 @@ class V8EXPORT Context {
* JavaScript frames an empty handle is returned.
*/
static Local<Context> GetCalling();
- static Local<Object> GetCallingQmlGlobal();
- static Local<Value> GetCallingScriptData();
/**
* Sets the security token for the context. To access an object in
@@ -3846,6 +3754,12 @@ class V8EXPORT Locker {
/**
+ * A struct for exporting HeapStats data from V8, using "push" model.
+ */
+struct HeapStatsUpdate;
+
+
+/**
* An interface for exporting data from V8, using "push" model.
*/
class V8EXPORT OutputStream { // NOLINT
@@ -3870,6 +3784,14 @@ class V8EXPORT OutputStream { // NOLINT
* will not be called in case writing was aborted.
*/
virtual WriteResult WriteAsciiChunk(char* data, int size) = 0;
+ /**
+ * Writes the next chunk of heap stats data into the stream. Writing
+ * can be stopped by returning kAbort as function result. EndOfStream
+ * will not be called in case writing was aborted.
+ */
+ virtual WriteResult WriteHeapStatsChunk(HeapStatsUpdate* data, int count) {
+ return kAbort;
+ };
};
@@ -3958,18 +3880,6 @@ const uintptr_t kEncodablePointerMask =
PlatformSmiTagging::kEncodablePointerMask;
const int kPointerToSmiShift = PlatformSmiTagging::kPointerToSmiShift;
-template <size_t ptr_size> struct InternalConstants;
-
-// Internal constants for 32-bit systems.
-template <> struct InternalConstants<4> {
- static const int kStringResourceOffset = 3 * kApiPointerSize;
-};
-
-// Internal constants for 64-bit systems.
-template <> struct InternalConstants<8> {
- static const int kStringResourceOffset = 3 * kApiPointerSize;
-};
-
/**
* This class exports constants and functionality from within v8 that
* is necessary to implement inline functions in the v8 api. Don't
@@ -3981,18 +3891,31 @@ class Internals {
// the implementation of v8.
static const int kHeapObjectMapOffset = 0;
static const int kMapInstanceTypeOffset = 1 * kApiPointerSize + kApiIntSize;
- static const int kStringResourceOffset =
- InternalConstants<kApiPointerSize>::kStringResourceOffset;
+ static const int kStringResourceOffset = 3 * kApiPointerSize;
+ static const int kOddballKindOffset = 3 * kApiPointerSize;
static const int kForeignAddressOffset = kApiPointerSize;
static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
static const int kFullStringRepresentationMask = 0x07;
static const int kExternalTwoByteRepresentationTag = 0x02;
+ static const int kIsolateStateOffset = 0;
+ static const int kIsolateEmbedderDataOffset = 1 * kApiPointerSize;
+ static const int kIsolateRootsOffset = 3 * kApiPointerSize;
+ static const int kUndefinedValueRootIndex = 5;
+ static const int kNullValueRootIndex = 7;
+ static const int kTrueValueRootIndex = 8;
+ static const int kFalseValueRootIndex = 9;
+ static const int kEmptySymbolRootIndex = 128;
+
static const int kJSObjectType = 0xaa;
static const int kFirstNonstringType = 0x80;
+ static const int kOddballType = 0x82;
static const int kForeignType = 0x85;
+ static const int kUndefinedOddballKind = 5;
+ static const int kNullOddballKind = 3;
+
static inline bool HasHeapObjectTag(internal::Object* value) {
return ((reinterpret_cast<intptr_t>(value) & kHeapObjectTagMask) ==
kHeapObjectTag);
@@ -4012,6 +3935,11 @@ class Internals {
return ReadField<uint8_t>(map, kMapInstanceTypeOffset);
}
+ static inline int GetOddballKind(internal::Object* obj) {
+ typedef internal::Object O;
+ return SmiValue(ReadField<O*>(obj, kOddballKindOffset));
+ }
+
static inline void* GetExternalPointerFromSmi(internal::Object* value) {
const uintptr_t address = reinterpret_cast<uintptr_t>(value);
return reinterpret_cast<void*>(address >> kPointerToSmiShift);
@@ -4032,19 +3960,41 @@ class Internals {
return representation == kExternalTwoByteRepresentationTag;
}
+ static inline bool IsInitialized(v8::Isolate* isolate) {
+ uint8_t* addr = reinterpret_cast<uint8_t*>(isolate) + kIsolateStateOffset;
+ return *reinterpret_cast<int*>(addr) == 1;
+ }
+
+ static inline void SetEmbedderData(v8::Isolate* isolate, void* data) {
+ uint8_t* addr = reinterpret_cast<uint8_t*>(isolate) +
+ kIsolateEmbedderDataOffset;
+ *reinterpret_cast<void**>(addr) = data;
+ }
+
+ static inline void* GetEmbedderData(v8::Isolate* isolate) {
+ uint8_t* addr = reinterpret_cast<uint8_t*>(isolate) +
+ kIsolateEmbedderDataOffset;
+ return *reinterpret_cast<void**>(addr);
+ }
+
+ static inline internal::Object** GetRoot(v8::Isolate* isolate, int index) {
+ uint8_t* addr = reinterpret_cast<uint8_t*>(isolate) + kIsolateRootsOffset;
+ return reinterpret_cast<internal::Object**>(addr + index * kApiPointerSize);
+ }
+
template <typename T>
static inline T ReadField(Object* ptr, int offset) {
uint8_t* addr = reinterpret_cast<uint8_t*>(ptr) + offset - kHeapObjectTag;
return *reinterpret_cast<T*>(addr);
}
- static inline bool CanCastToHeapObject(void*) { return false; }
- static inline bool CanCastToHeapObject(Context*) { return true; }
- static inline bool CanCastToHeapObject(String*) { return true; }
- static inline bool CanCastToHeapObject(Object*) { return true; }
- static inline bool CanCastToHeapObject(Message*) { return true; }
- static inline bool CanCastToHeapObject(StackTrace*) { return true; }
- static inline bool CanCastToHeapObject(StackFrame*) { return true; }
+ static inline bool CanCastToHeapObject(void* o) { return false; }
+ static inline bool CanCastToHeapObject(Context* o) { return true; }
+ static inline bool CanCastToHeapObject(String* o) { return true; }
+ static inline bool CanCastToHeapObject(Object* o) { return true; }
+ static inline bool CanCastToHeapObject(Message* o) { return true; }
+ static inline bool CanCastToHeapObject(StackTrace* o) { return true; }
+ static inline bool CanCastToHeapObject(StackFrame* o) { return true; }
};
} // namespace internal
@@ -4158,6 +4108,11 @@ Local<Value> Arguments::Data() const {
}
+Isolate* Arguments::GetIsolate() const {
+ return *reinterpret_cast<Isolate**>(&implicit_args_[kIsolateIndex]);
+}
+
+
bool Arguments::IsConstructCall() const {
return is_construct_call_;
}
@@ -4270,6 +4225,15 @@ String* String::Cast(v8::Value* value) {
}
+Local<String> String::Empty(Isolate* isolate) {
+ typedef internal::Object* S;
+ typedef internal::Internals I;
+ if (!I::IsInitialized(isolate)) return Empty();
+ S* slot = I::GetRoot(isolate, I::kEmptySymbolRootIndex);
+ return Local<String>(reinterpret_cast<String*>(slot));
+}
+
+
String::ExternalStringResource* String::GetExternalStringResource() const {
typedef internal::Object O;
typedef internal::Internals I;
@@ -4288,6 +4252,42 @@ String::ExternalStringResource* String::GetExternalStringResource() const {
}
+bool Value::IsUndefined() const {
+#ifdef V8_ENABLE_CHECKS
+ return FullIsUndefined();
+#else
+ return QuickIsUndefined();
+#endif
+}
+
+bool Value::QuickIsUndefined() const {
+ typedef internal::Object O;
+ typedef internal::Internals I;
+ O* obj = *reinterpret_cast<O**>(const_cast<Value*>(this));
+ if (!I::HasHeapObjectTag(obj)) return false;
+ if (I::GetInstanceType(obj) != I::kOddballType) return false;
+ return (I::GetOddballKind(obj) == I::kUndefinedOddballKind);
+}
+
+
+bool Value::IsNull() const {
+#ifdef V8_ENABLE_CHECKS
+ return FullIsNull();
+#else
+ return QuickIsNull();
+#endif
+}
+
+bool Value::QuickIsNull() const {
+ typedef internal::Object O;
+ typedef internal::Internals I;
+ O* obj = *reinterpret_cast<O**>(const_cast<Value*>(this));
+ if (!I::HasHeapObjectTag(obj)) return false;
+ if (I::GetInstanceType(obj) != I::kOddballType) return false;
+ return (I::GetOddballKind(obj) == I::kNullOddballKind);
+}
+
+
bool Value::IsString() const {
#ifdef V8_ENABLE_CHECKS
return FullIsString();
@@ -4393,6 +4393,11 @@ External* External::Cast(v8::Value* value) {
}
+Isolate* AccessorInfo::GetIsolate() const {
+ return *reinterpret_cast<Isolate**>(&args_[-3]);
+}
+
+
Local<Value> AccessorInfo::Data() const {
return Local<Value>(reinterpret_cast<Value*>(&args_[-2]));
}
@@ -4408,6 +4413,54 @@ Local<Object> AccessorInfo::Holder() const {
}
+Handle<Primitive> Undefined(Isolate* isolate) {
+ typedef internal::Object* S;
+ typedef internal::Internals I;
+ if (!I::IsInitialized(isolate)) return Undefined();
+ S* slot = I::GetRoot(isolate, I::kUndefinedValueRootIndex);
+ return Handle<Primitive>(reinterpret_cast<Primitive*>(slot));
+}
+
+
+Handle<Primitive> Null(Isolate* isolate) {
+ typedef internal::Object* S;
+ typedef internal::Internals I;
+ if (!I::IsInitialized(isolate)) return Null();
+ S* slot = I::GetRoot(isolate, I::kNullValueRootIndex);
+ return Handle<Primitive>(reinterpret_cast<Primitive*>(slot));
+}
+
+
+Handle<Boolean> True(Isolate* isolate) {
+ typedef internal::Object* S;
+ typedef internal::Internals I;
+ if (!I::IsInitialized(isolate)) return True();
+ S* slot = I::GetRoot(isolate, I::kTrueValueRootIndex);
+ return Handle<Boolean>(reinterpret_cast<Boolean*>(slot));
+}
+
+
+Handle<Boolean> False(Isolate* isolate) {
+ typedef internal::Object* S;
+ typedef internal::Internals I;
+ if (!I::IsInitialized(isolate)) return False();
+ S* slot = I::GetRoot(isolate, I::kFalseValueRootIndex);
+ return Handle<Boolean>(reinterpret_cast<Boolean*>(slot));
+}
+
+
+void Isolate::SetData(void* data) {
+ typedef internal::Internals I;
+ I::SetEmbedderData(this, data);
+}
+
+
+void* Isolate::GetData() {
+ typedef internal::Internals I;
+ return I::GetEmbedderData(this);
+}
+
+
/**
* \example shell.cc
* A simple shell that takes a list of expressions on the
diff --git a/src/3rdparty/v8/samples/lineprocessor.cc b/src/3rdparty/v8/samples/lineprocessor.cc
index 1606a8f..7a84a2a 100644
--- a/src/3rdparty/v8/samples/lineprocessor.cc
+++ b/src/3rdparty/v8/samples/lineprocessor.cc
@@ -1,4 +1,4 @@
-// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -434,9 +434,9 @@ v8::Handle<v8::String> ReadLine() {
}
if (res == NULL) {
v8::Handle<v8::Primitive> t = v8::Undefined();
- return reinterpret_cast<v8::Handle<v8::String>&>(t);
+ return v8::Handle<v8::String>(v8::String::Cast(*t));
}
- // remove newline char
+ // Remove newline char
for (char* pos = buffer; *pos != '\0'; pos++) {
if (*pos == '\n') {
*pos = '\0';
diff --git a/src/3rdparty/v8/samples/samples.gyp b/src/3rdparty/v8/samples/samples.gyp
index 55b2a98..3c720a7 100644
--- a/src/3rdparty/v8/samples/samples.gyp
+++ b/src/3rdparty/v8/samples/samples.gyp
@@ -1,4 +1,4 @@
-# Copyright 2011 the V8 project authors. All rights reserved.
+# Copyright 2012 the V8 project authors. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
@@ -48,6 +48,12 @@
'sources': [
'process.cc',
],
+ },
+ {
+ 'target_name': 'lineprocessor',
+ 'sources': [
+ 'lineprocessor.cc',
+ ],
}
],
}
diff --git a/src/3rdparty/v8/src/api.cc b/src/3rdparty/v8/src/api.cc
index 78fc0b1..52a84ed 100644
--- a/src/3rdparty/v8/src/api.cc
+++ b/src/3rdparty/v8/src/api.cc
@@ -1152,7 +1152,6 @@ void FunctionTemplate::SetNamedInstancePropertyHandler(
NamedPropertyQuery query,
NamedPropertyDeleter remover,
NamedPropertyEnumerator enumerator,
- bool is_fallback,
Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
if (IsDeadCheck(isolate,
@@ -1171,7 +1170,6 @@ void FunctionTemplate::SetNamedInstancePropertyHandler(
if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query);
if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover);
if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator);
- obj->set_is_fallback(i::Smi::FromInt(is_fallback));
if (data.IsEmpty()) data = v8::Undefined();
obj->set_data(*Utils::OpenHandle(*data));
@@ -1316,33 +1314,6 @@ void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter,
query,
remover,
enumerator,
- false,
- data);
-}
-
-
-void ObjectTemplate::SetFallbackPropertyHandler(NamedPropertyGetter getter,
- NamedPropertySetter setter,
- NamedPropertyQuery query,
- NamedPropertyDeleter remover,
- NamedPropertyEnumerator enumerator,
- Handle<Value> data) {
- i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
- if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetNamedPropertyHandler()")) {
- return;
- }
- ENTER_V8(isolate);
- i::HandleScope scope(isolate);
- EnsureConstructor(this);
- i::FunctionTemplateInfo* constructor =
- i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
- i::Handle<i::FunctionTemplateInfo> cons(constructor);
- Utils::ToLocal(cons)->SetNamedInstancePropertyHandler(getter,
- setter,
- query,
- remover,
- enumerator,
- true,
data);
}
@@ -1465,45 +1436,6 @@ void ObjectTemplate::SetInternalFieldCount(int value) {
}
-bool ObjectTemplate::HasExternalResource()
-{
- if (IsDeadCheck(Utils::OpenHandle(this)->GetIsolate(),
- "v8::ObjectTemplate::HasExternalResource()")) {
- return 0;
- }
- return !Utils::OpenHandle(this)->has_external_resource()->IsUndefined();
-}
-
-
-void ObjectTemplate::SetHasExternalResource(bool value)
-{
- i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
- if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetHasExternalResource()")) {
- return;
- }
- ENTER_V8(isolate);
- if (value) {
- EnsureConstructor(this);
- }
- if (value) {
- Utils::OpenHandle(this)->set_has_external_resource(i::Smi::FromInt(1));
- } else {
- Utils::OpenHandle(this)->set_has_external_resource(Utils::OpenHandle(this)->GetHeap()->undefined_value());
- }
-}
-
-
-void ObjectTemplate::MarkAsUseUserObjectComparison()
-{
- i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
- if (IsDeadCheck(isolate, "v8::ObjectTemplate::MarkAsUseUserObjectComparison()")) {
- return;
- }
- ENTER_V8(isolate);
- EnsureConstructor(this);
- Utils::OpenHandle(this)->set_use_user_object_comparison(i::Smi::FromInt(1));
-}
-
// --- S c r i p t D a t a ---
@@ -1554,8 +1486,7 @@ ScriptData* ScriptData::New(const char* data, int length) {
Local<Script> Script::New(v8::Handle<String> source,
v8::ScriptOrigin* origin,
v8::ScriptData* pre_data,
- v8::Handle<String> script_data,
- v8::Script::CompileFlags compile_flags) {
+ v8::Handle<String> script_data) {
i::Isolate* isolate = i::Isolate::Current();
ON_BAILOUT(isolate, "v8::Script::New()", return Local<Script>());
LOG_API(isolate, "Script::New");
@@ -1596,8 +1527,7 @@ Local<Script> Script::New(v8::Handle<String> source,
NULL,
pre_data_impl,
Utils::OpenHandle(*script_data),
- i::NOT_NATIVES_CODE,
- compile_flags);
+ i::NOT_NATIVES_CODE);
has_pending_exception = result.is_null();
EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>());
raw_result = *result;
@@ -1608,23 +1538,21 @@ Local<Script> Script::New(v8::Handle<String> source,
Local<Script> Script::New(v8::Handle<String> source,
- v8::Handle<Value> file_name,
- v8::Script::CompileFlags compile_flags) {
+ v8::Handle<Value> file_name) {
ScriptOrigin origin(file_name);
- return New(source, &origin, 0, Handle<String>(), compile_flags);
+ return New(source, &origin);
}
Local<Script> Script::Compile(v8::Handle<String> source,
v8::ScriptOrigin* origin,
v8::ScriptData* pre_data,
- v8::Handle<String> script_data,
- v8::Script::CompileFlags compile_flags) {
+ v8::Handle<String> script_data) {
i::Isolate* isolate = i::Isolate::Current();
ON_BAILOUT(isolate, "v8::Script::Compile()", return Local<Script>());
LOG_API(isolate, "Script::Compile");
ENTER_V8(isolate);
- Local<Script> generic = New(source, origin, pre_data, script_data, compile_flags);
+ Local<Script> generic = New(source, origin, pre_data, script_data);
if (generic.IsEmpty())
return generic;
i::Handle<i::Object> obj = Utils::OpenHandle(*generic);
@@ -1640,18 +1568,13 @@ Local<Script> Script::Compile(v8::Handle<String> source,
Local<Script> Script::Compile(v8::Handle<String> source,
v8::Handle<Value> file_name,
- v8::Handle<String> script_data,
- v8::Script::CompileFlags compile_flags) {
+ v8::Handle<String> script_data) {
ScriptOrigin origin(file_name);
- return Compile(source, &origin, 0, script_data, compile_flags);
+ return Compile(source, &origin, 0, script_data);
}
Local<Value> Script::Run() {
- return Run(Handle<Object>());
-}
-
-Local<Value> Script::Run(Handle<Object> qml) {
i::Isolate* isolate = i::Isolate::Current();
ON_BAILOUT(isolate, "v8::Script::Run()", return Local<Value>());
LOG_API(isolate, "Script::Run");
@@ -1670,11 +1593,10 @@ Local<Value> Script::Run(Handle<Object> qml) {
fun = i::Handle<i::JSFunction>(i::JSFunction::cast(*obj), isolate);
}
EXCEPTION_PREAMBLE(isolate);
- i::Handle<i::Object> qmlglobal = Utils::OpenHandle(*qml);
i::Handle<i::Object> receiver(
isolate->context()->global_proxy(), isolate);
i::Handle<i::Object> result =
- i::Execution::Call(fun, receiver, 0, NULL, &has_pending_exception, false, qmlglobal);
+ i::Execution::Call(fun, receiver, 0, NULL, &has_pending_exception);
EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<Value>());
raw_result = *result;
}
@@ -2179,17 +2101,21 @@ bool StackFrame::IsConstructor() const {
// --- D a t a ---
-bool Value::IsUndefined() const {
+bool Value::FullIsUndefined() const {
if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsUndefined()")) {
return false;
}
- return Utils::OpenHandle(this)->IsUndefined();
+ bool result = Utils::OpenHandle(this)->IsUndefined();
+ ASSERT_EQ(result, QuickIsUndefined());
+ return result;
}
-bool Value::IsNull() const {
+bool Value::FullIsNull() const {
if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsNull()")) return false;
- return Utils::OpenHandle(this)->IsNull();
+ bool result = Utils::OpenHandle(this)->IsNull();
+ ASSERT_EQ(result, QuickIsNull());
+ return result;
}
@@ -2362,12 +2288,6 @@ bool Value::IsRegExp() const {
return obj->IsJSRegExp();
}
-bool Value::IsError() const {
- if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsError()")) return false;
- i::Handle<i::Object> obj = Utils::OpenHandle(this);
- return obj->HasSpecificClassOf(HEAP->Error_symbol());
-}
-
Local<String> Value::ToString() const {
i::Handle<i::Object> obj = Utils::OpenHandle(this);
@@ -2893,9 +2813,13 @@ bool v8::Object::ForceDelete(v8::Handle<Value> key) {
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
- // When turning on access checks for a global object deoptimize all functions
- // as optimized code does not always handle access checks.
- i::Deoptimizer::DeoptimizeGlobalObject(*self);
+ // When deleting a property on the global object using ForceDelete
+ // deoptimize all functions as optimized code does not check for the hole
+ // value with DontDelete properties. We have to deoptimize all contexts
+ // because of possible cross-context inlined functions.
+ if (self->IsJSGlobalProxy() || self->IsGlobalObject()) {
+ i::Deoptimizer::DeoptimizeAll();
+ }
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> obj = i::ForceDeleteProperty(self, key_obj);
@@ -3888,59 +3812,6 @@ bool String::MayContainNonAscii() const {
}
-uint32_t String::Hash() const {
- i::Handle<i::String> str = Utils::OpenHandle(this);
- if (IsDeadCheck(str->GetIsolate(), "v8::String::Hash()")) return 0;
- return str->Hash();
-}
-
-
-String::CompleteHashData String::CompleteHash() const {
- i::Handle<i::String> str = Utils::OpenHandle(this);
- if (IsDeadCheck(str->GetIsolate(), "v8::String::CompleteHash()")) {
- return CompleteHashData();
- }
- CompleteHashData result;
- result.length = str->length();
- result.hash = str->Hash();
- if (str->IsSeqString())
- result.symbol_id = i::SeqString::cast(*str)->symbol_id();
- return result;
-}
-
-
-uint32_t String::ComputeHash(uint16_t *string, int length) {
- return i::HashSequentialString<i::uc16>(string, length, i::kZeroHashSeed) >>
- i::String::kHashShift;
-}
-
-
-uint32_t String::ComputeHash(char *string, int length) {
- return i::HashSequentialString<char>(string, length, i::kZeroHashSeed) >>
- i::String::kHashShift;
-}
-
-
-uint16_t String::GetCharacter(int index) {
- i::Handle<i::String> str = Utils::OpenHandle(this);
- return str->Get(index);
-}
-
-
-bool String::Equals(uint16_t *string, int length) {
- i::Handle<i::String> str = Utils::OpenHandle(this);
- if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0;
- return str->SlowEqualsExternal(string, length);
-}
-
-
-bool String::Equals(char *string, int length) {
- i::Handle<i::String> str = Utils::OpenHandle(this);
- if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0;
- return str->SlowEqualsExternal(string, length);
-}
-
-
int String::WriteUtf8(char* buffer,
int capacity,
int* nchars_ref,
@@ -4313,34 +4184,6 @@ void v8::Object::SetPointerInInternalField(int index, void* value) {
}
-void v8::Object::SetExternalResource(v8::Object::ExternalResource *resource) {
- i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
- ENTER_V8(isolate);
- i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
- if (CanBeEncodedAsSmi(resource)) {
- obj->SetExternalResourceObject(EncodeAsSmi(resource));
- } else {
- obj->SetExternalResourceObject(*isolate->factory()->NewForeign(static_cast<i::Address>((void *)resource)));
- }
- if (!obj->IsSymbol()) {
- isolate->heap()->external_string_table()->AddObject(*obj);
- }
-}
-
-
-v8::Object::ExternalResource *v8::Object::GetExternalResource() {
- i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
- i::Object* value = obj->GetExternalResourceObject();
- if (value->IsSmi()) {
- return reinterpret_cast<v8::Object::ExternalResource*>(i::Internals::GetExternalPointerFromSmi(value));
- } else if (value->IsForeign()) {
- return reinterpret_cast<v8::Object::ExternalResource*>(i::Foreign::cast(value)->foreign_address());
- } else {
- return NULL;
- }
-}
-
-
// --- E n v i r o n m e n t ---
@@ -4607,37 +4450,6 @@ v8::Local<v8::Context> Context::GetCalling() {
}
-v8::Local<v8::Object> Context::GetCallingQmlGlobal() {
- i::Isolate* isolate = i::Isolate::Current();
- if (IsDeadCheck(isolate, "v8::Context::GetCallingQmlGlobal()")) {
- return Local<Object>();
- }
-
- i::Context *context = isolate->context();
- i::JavaScriptFrameIterator it;
- if (it.done()) return Local<Object>();
- context = i::Context::cast(it.frame()->context());
- if (!context->qml_global()->IsUndefined()) {
- i::Handle<i::Object> qmlglobal(context->qml_global());
- return Utils::ToLocal(i::Handle<i::JSObject>::cast(qmlglobal));
- } else {
- return Local<Object>();
- }
-}
-
-v8::Local<v8::Value> Context::GetCallingScriptData()
-{
- i::Isolate* isolate = i::Isolate::Current();
- if (IsDeadCheck(isolate, "v8::Context::GetCallingScriptData()")) {
- return Local<Object>();
- }
-
- i::JavaScriptFrameIterator it;
- if (it.done()) return Local<Object>();
- i::Handle<i::Script> script(i::Script::cast(i::JSFunction::cast(it.frame()->function())->shared()->script()));
- return Utils::ToLocal(i::Handle<i::Object>(script->data()));
-}
-
v8::Local<v8::Object> Context::Global() {
if (IsDeadCheck(i::Isolate::Current(), "v8::Context::Global()")) {
return Local<v8::Object>();
@@ -4818,7 +4630,9 @@ void* External::Value() const {
Local<String> v8::String::Empty() {
i::Isolate* isolate = i::Isolate::Current();
- EnsureInitializedForIsolate(isolate, "v8::String::Empty()");
+ if (!EnsureInitializedForIsolate(isolate, "v8::String::Empty()")) {
+ return v8::Local<String>();
+ }
LOG_API(isolate, "String::Empty()");
return Utils::ToLocal(isolate->factory()->empty_symbol());
}
@@ -5381,17 +5195,6 @@ void V8::SetFailedAccessCheckCallbackFunction(
isolate->SetFailedAccessCheckCallback(callback);
}
-
-void V8::SetUserObjectComparisonCallbackFunction(
- UserObjectComparisonCallback callback) {
- i::Isolate* isolate = i::Isolate::Current();
- if (IsDeadCheck(isolate, "v8::V8::SetUserObjectComparisonCallbackFunction()")) {
- return;
- }
- isolate->SetUserObjectComparisonCallback(callback);
-}
-
-
void V8::AddObjectGroup(Persistent<Value>* objects,
size_t length,
RetainedObjectInfo* info) {
@@ -5415,7 +5218,7 @@ void V8::AddImplicitReferences(Persistent<Object> parent,
}
-int V8::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) {
+intptr_t V8::AdjustAmountOfExternalAllocatedMemory(intptr_t change_in_bytes) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::V8::AdjustAmountOfExternalAllocatedMemory()")) {
return 0;
@@ -5595,17 +5398,6 @@ void Isolate::Exit() {
}
-void Isolate::SetData(void* data) {
- i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
- isolate->SetData(data);
-}
-
-void* Isolate::GetData() {
- i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
- return isolate->GetData();
-}
-
-
String::Utf8Value::Utf8Value(v8::Handle<v8::Value> obj)
: str_(NULL), length_(0) {
i::Isolate* isolate = i::Isolate::Current();
@@ -6205,7 +5997,7 @@ Handle<Value> HeapGraphEdge::GetName() const {
const HeapGraphNode* HeapGraphEdge::GetFromNode() const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapGraphEdge::GetFromNode");
- const i::HeapEntry* from = ToInternal(this)->From();
+ const i::HeapEntry* from = ToInternal(this)->from();
return reinterpret_cast<const HeapGraphNode*>(from);
}
@@ -6271,7 +6063,7 @@ const HeapGraphEdge* HeapGraphNode::GetChild(int index) const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshot::GetChild");
return reinterpret_cast<const HeapGraphEdge*>(
- &ToInternal(this)->children()[index]);
+ ToInternal(this)->children()[index]);
}
@@ -6365,7 +6157,7 @@ const HeapGraphNode* HeapSnapshot::GetNodeById(SnapshotObjectId id) const {
int HeapSnapshot::GetNodesCount() const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshot::GetNodesCount");
- return ToInternal(this)->entries()->length();
+ return ToInternal(this)->entries().length();
}
@@ -6373,7 +6165,7 @@ const HeapGraphNode* HeapSnapshot::GetNode(int index) const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshot::GetNode");
return reinterpret_cast<const HeapGraphNode*>(
- ToInternal(this)->entries()->at(index));
+ &ToInternal(this)->entries().at(index));
}
@@ -6425,6 +6217,14 @@ const HeapSnapshot* HeapProfiler::FindSnapshot(unsigned uid) {
}
+SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Value> value) {
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapProfiler::GetSnapshotObjectId");
+ i::Handle<i::Object> obj = Utils::OpenHandle(*value);
+ return i::HeapProfiler::GetSnapshotObjectId(obj);
+}
+
+
const HeapSnapshot* HeapProfiler::TakeSnapshot(Handle<String> title,
HeapSnapshot::Type type,
ActivityControl* control) {
@@ -6444,6 +6244,27 @@ const HeapSnapshot* HeapProfiler::TakeSnapshot(Handle<String> title,
}
+void HeapProfiler::StartHeapObjectsTracking() {
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapProfiler::StartHeapObjectsTracking");
+ i::HeapProfiler::StartHeapObjectsTracking();
+}
+
+
+void HeapProfiler::StopHeapObjectsTracking() {
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapProfiler::StopHeapObjectsTracking");
+ i::HeapProfiler::StopHeapObjectsTracking();
+}
+
+
+void HeapProfiler::PushHeapObjectsStats(OutputStream* stream) {
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapProfiler::PushHeapObjectsStats");
+ return i::HeapProfiler::PushHeapObjectsStats(stream);
+}
+
+
void HeapProfiler::DeleteAllSnapshots() {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapProfiler::DeleteAllSnapshots");
@@ -6491,7 +6312,11 @@ static void SetFlagsFromString(const char* flags) {
void Testing::PrepareStressRun(int run) {
static const char* kLazyOptimizations =
- "--prepare-always-opt --nolimit-inlining --noalways-opt";
+ "--prepare-always-opt "
+ "--max-inlined-source-size=999999 "
+ "--max-inlined-nodes=999999 "
+ "--max-inlined-nodes-cumulative=999999 "
+ "--noalways-opt";
static const char* kForcedOptimizations = "--always-opt";
// If deoptimization stressed turn on frequent deoptimization. If no value
diff --git a/src/3rdparty/v8/src/apiutils.h b/src/3rdparty/v8/src/apiutils.h
index 68579af..71c0e1c 100644
--- a/src/3rdparty/v8/src/apiutils.h
+++ b/src/3rdparty/v8/src/apiutils.h
@@ -1,4 +1,4 @@
-// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -40,14 +40,17 @@ class ImplementationUtilities {
}
// Packs additional parameters for the NewArguments function. |implicit_args|
- // is a pointer to the last element of 3-elements array controlled by GC.
+ // is a pointer to the last element of 4-elements array controlled by GC.
static void PrepareArgumentsData(internal::Object** implicit_args,
+ internal::Isolate* isolate,
internal::Object* data,
internal::JSFunction* callee,
internal::Object* holder) {
implicit_args[v8::Arguments::kDataIndex] = data;
implicit_args[v8::Arguments::kCalleeIndex] = callee;
implicit_args[v8::Arguments::kHolderIndex] = holder;
+ implicit_args[v8::Arguments::kIsolateIndex] =
+ reinterpret_cast<internal::Object*>(isolate);
}
static v8::Arguments NewArguments(internal::Object** implicit_args,
@@ -55,6 +58,8 @@ class ImplementationUtilities {
bool is_construct_call) {
ASSERT(implicit_args[v8::Arguments::kCalleeIndex]->IsJSFunction());
ASSERT(implicit_args[v8::Arguments::kHolderIndex]->IsHeapObject());
+ // The implicit isolate argument is not tagged and looks like a SMI.
+ ASSERT(implicit_args[v8::Arguments::kIsolateIndex]->IsSmi());
return v8::Arguments(implicit_args, argv, argc, is_construct_call);
}
diff --git a/src/3rdparty/v8/src/arguments.h b/src/3rdparty/v8/src/arguments.h
index e9a3270..f8fb00c 100644
--- a/src/3rdparty/v8/src/arguments.h
+++ b/src/3rdparty/v8/src/arguments.h
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -91,9 +91,11 @@ class CustomArguments : public Relocatable {
Object* data,
Object* self,
JSObject* holder) : Relocatable(isolate) {
- values_[2] = self;
- values_[1] = holder;
- values_[0] = data;
+ ASSERT(reinterpret_cast<Object*>(isolate)->IsSmi());
+ values_[3] = self;
+ values_[2] = holder;
+ values_[1] = data;
+ values_[0] = reinterpret_cast<Object*>(isolate);
}
inline explicit CustomArguments(Isolate* isolate) : Relocatable(isolate) {
@@ -106,8 +108,9 @@ class CustomArguments : public Relocatable {
void IterateInstance(ObjectVisitor* v);
Object** end() { return values_ + ARRAY_SIZE(values_) - 1; }
+
private:
- Object* values_[3];
+ Object* values_[4];
};
diff --git a/src/3rdparty/v8/src/arm/code-stubs-arm.cc b/src/3rdparty/v8/src/arm/code-stubs-arm.cc
index dd13f88..ad2ab7e 100644
--- a/src/3rdparty/v8/src/arm/code-stubs-arm.cc
+++ b/src/3rdparty/v8/src/arm/code-stubs-arm.cc
@@ -169,10 +169,6 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
__ str(r1, MemOperand(r0, Context::SlotOffset(Context::EXTENSION_INDEX)));
__ str(r2, MemOperand(r0, Context::SlotOffset(Context::GLOBAL_INDEX)));
- // Copy the qml global object from the surrounding context.
- __ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::QML_GLOBAL_INDEX)));
- __ str(r1, MemOperand(r0, Context::SlotOffset(Context::QML_GLOBAL_INDEX)));
-
// Initialize the rest of the slots to undefined.
__ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
@@ -237,10 +233,6 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
__ str(r1, ContextOperand(r0, Context::EXTENSION_INDEX));
__ str(r2, ContextOperand(r0, Context::GLOBAL_INDEX));
- // Copy the qml global object from the surrounding context.
- __ ldr(r1, ContextOperand(cp, Context::QML_GLOBAL_INDEX));
- __ str(r1, ContextOperand(r0, Context::QML_GLOBAL_INDEX));
-
// Initialize the rest of the slots to the hole value.
__ LoadRoot(r1, Heap::kTheHoleValueRootIndex);
for (int i = 0; i < slots_; i++) {
@@ -1642,37 +1634,6 @@ void CompareStub::Generate(MacroAssembler* masm) {
// NOTICE! This code is only reached after a smi-fast-case check, so
// it is certain that at least one operand isn't a smi.
- {
- Label not_user_equal, user_equal;
- __ and_(r2, r1, Operand(r0));
- __ tst(r2, Operand(kSmiTagMask));
- __ b(eq, &not_user_equal);
-
- __ CompareObjectType(r0, r2, r4, JS_OBJECT_TYPE);
- __ b(ne, &not_user_equal);
-
- __ CompareObjectType(r1, r3, r4, JS_OBJECT_TYPE);
- __ b(ne, &not_user_equal);
-
- __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
- __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
- __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
- __ b(eq, &user_equal);
-
- __ ldrb(r3, FieldMemOperand(r3, Map::kBitField2Offset));
- __ and_(r3, r3, Operand(1 << Map::kUseUserObjectComparison));
- __ cmp(r3, Operand(1 << Map::kUseUserObjectComparison));
- __ b(ne, &not_user_equal);
-
- __ bind(&user_equal);
-
- __ Push(r0, r1);
- __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
-
- __ bind(&not_user_equal);
- }
-
-
// Handle the case where the objects are identical. Either returns the answer
// or goes to slow. Only falls through if the objects were not identical.
EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_);
@@ -5208,9 +5169,9 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ CompareRoot(r4, Heap::kTheHoleValueRootIndex);
__ b(ne, &call);
// Patch the receiver on the stack with the global receiver object.
- __ ldr(r2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
- __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
- __ str(r2, MemOperand(sp, argc_ * kPointerSize));
+ __ ldr(r3, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ __ ldr(r3, FieldMemOperand(r3, GlobalObject::kGlobalReceiverOffset));
+ __ str(r3, MemOperand(sp, argc_ * kPointerSize));
__ bind(&call);
}
@@ -5218,9 +5179,13 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
// r1: pushed function (to be verified)
__ JumpIfSmi(r1, &non_function);
// Get the map of the function object.
- __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
+ __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
__ b(ne, &slow);
+ if (RecordCallTarget()) {
+ GenerateRecordCallTarget(masm);
+ }
+
// Fast-case: Invoke the function now.
// r1: pushed function
ParameterCount actual(argc_);
@@ -5244,8 +5209,17 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
// Slow-case: Non-function called.
__ bind(&slow);
+ if (RecordCallTarget()) {
+ // If there is a call target cache, mark it megamorphic in the
+ // non-function case. MegamorphicSentinel is an immortal immovable
+ // object (undefined) so no write barrier is needed.
+ ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
+ masm->isolate()->heap()->undefined_value());
+ __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+ __ str(ip, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
+ }
// Check for function proxy.
- __ cmp(r2, Operand(JS_FUNCTION_PROXY_TYPE));
+ __ cmp(r3, Operand(JS_FUNCTION_PROXY_TYPE));
__ b(ne, &non_function);
__ push(r1); // put proxy as additional argument
__ mov(r0, Operand(argc_ + 1, RelocInfo::NONE));
@@ -5912,36 +5886,12 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// r2: result string length
__ ldr(r4, FieldMemOperand(r0, String::kLengthOffset));
__ cmp(r2, Operand(r4, ASR, 1));
+ // Return original string.
__ b(eq, &return_r0);
+ // Longer than original string's length or negative: unsafe arguments.
+ __ b(hi, &runtime);
+ // Shorter than original string's length: an actual substring.
- Label result_longer_than_two;
- // Check for special case of two character ASCII string, in which case
- // we do a lookup in the symbol table first.
- __ cmp(r2, Operand(2));
- __ b(gt, &result_longer_than_two);
- __ b(lt, &runtime);
-
- __ JumpIfInstanceTypeIsNotSequentialAscii(r1, r1, &runtime);
-
- // Get the two characters forming the sub string.
- __ add(r0, r0, Operand(r3));
- __ ldrb(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
- __ ldrb(r4, FieldMemOperand(r0, SeqAsciiString::kHeaderSize + 1));
-
- // Try to lookup two character string in symbol table.
- Label make_two_character_string;
- StringHelper::GenerateTwoCharacterSymbolTableProbe(
- masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string);
- __ jmp(&return_r0);
-
- // r2: result string length.
- // r3: two characters combined into halfword in little endian byte order.
- __ bind(&make_two_character_string);
- __ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime);
- __ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
- __ jmp(&return_r0);
-
- __ bind(&result_longer_than_two);
// Deal with different string types: update the index if necessary
// and put the underlying string into r5.
// r0: original string
@@ -6780,18 +6730,10 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ and_(r2, r1, Operand(r0));
__ JumpIfSmi(r2, &miss);
- __ CompareObjectType(r0, r2, r3, JS_OBJECT_TYPE);
+ __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE);
__ b(ne, &miss);
- __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
- __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
- __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
- __ b(eq, &miss);
- __ CompareObjectType(r1, r2, r3, JS_OBJECT_TYPE);
+ __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE);
__ b(ne, &miss);
- __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
- __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
- __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
- __ b(eq, &miss);
ASSERT(GetCondition() == eq);
__ sub(r0, r0, Operand(r1));
@@ -6810,16 +6752,8 @@ void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
__ cmp(r2, Operand(known_map_));
__ b(ne, &miss);
- __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
- __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
- __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
- __ b(eq, &miss);
__ cmp(r3, Operand(known_map_));
__ b(ne, &miss);
- __ ldrb(r3, FieldMemOperand(r3, Map::kBitField2Offset));
- __ and_(r3, r3, Operand(1 << Map::kUseUserObjectComparison));
- __ cmp(r3, Operand(1 << Map::kUseUserObjectComparison));
- __ b(eq, &miss);
__ sub(r0, r0, Operand(r1));
__ Ret();
diff --git a/src/3rdparty/v8/src/arm/cpu-arm.cc b/src/3rdparty/v8/src/arm/cpu-arm.cc
index f7da6c3..7b08ed8 100644
--- a/src/3rdparty/v8/src/arm/cpu-arm.cc
+++ b/src/3rdparty/v8/src/arm/cpu-arm.cc
@@ -26,17 +26,12 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// CPU specific code for arm independent of OS goes here.
+#ifdef __arm__
+#include <sys/syscall.h> // for cache flushing.
+#endif
#include "v8.h"
-#if defined(__arm__)
- #if !defined(__QNXNTO__)
- #include <sys/syscall.h> // for cache flushing.
- #else
- #include <sys/mman.h> // for cache flushing.
- #endif
-#endif
-
#if defined(V8_TARGET_ARCH_ARM)
#include "cpu.h"
@@ -69,10 +64,6 @@ void CPU::FlushICache(void* start, size_t size) {
// None of this code ends up in the snapshot so there are no issues
// around whether or not to generate the code when building snapshots.
Simulator::FlushICache(Isolate::Current()->simulator_i_cache(), start, size);
-#elif defined(__QNXNTO__)
- // The QNX kernel does not expose the symbol __ARM_NR_cacheflush so we
- // use the msync system call instead of the approach used on Linux
- msync(start, size, MS_SYNC|MS_INVALIDATE_ICACHE);
#else
// Ideally, we would call
// syscall(__ARM_NR_cacheflush, start,
diff --git a/src/3rdparty/v8/src/arm/debug-arm.cc b/src/3rdparty/v8/src/arm/debug-arm.cc
index 96139a2..3e7a1e9 100644
--- a/src/3rdparty/v8/src/arm/debug-arm.cc
+++ b/src/3rdparty/v8/src/arm/debug-arm.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -125,6 +125,8 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() {
Assembler::kDebugBreakSlotInstructions);
}
+const bool Debug::FramePaddingLayout::kIsSupported = false;
+
#define __ ACCESS_MASM(masm)
diff --git a/src/3rdparty/v8/src/arm/deoptimizer-arm.cc b/src/3rdparty/v8/src/arm/deoptimizer-arm.cc
index 7b2a3c4..699e6aa 100644
--- a/src/3rdparty/v8/src/arm/deoptimizer-arm.cc
+++ b/src/3rdparty/v8/src/arm/deoptimizer-arm.cc
@@ -457,6 +457,8 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
int frame_index) {
+ Builtins* builtins = isolate_->builtins();
+ Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
unsigned height = iterator->Next();
unsigned height_in_bytes = height * kPointerSize;
@@ -464,7 +466,7 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
PrintF(" translating construct stub => height=%d\n", height_in_bytes);
}
- unsigned fixed_frame_size = 7 * kPointerSize;
+ unsigned fixed_frame_size = 8 * kPointerSize;
unsigned output_frame_size = height_in_bytes + fixed_frame_size;
// Allocate and store the output frame description.
@@ -529,6 +531,15 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
top_address + output_offset, output_offset, value);
}
+ // The output frame reflects a JSConstructStubGeneric frame.
+ output_offset -= kPointerSize;
+ value = reinterpret_cast<intptr_t>(construct_stub);
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; code object\n",
+ top_address + output_offset, output_offset, value);
+ }
+
// Number of incoming arguments.
output_offset -= kPointerSize;
value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1));
@@ -559,8 +570,6 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
ASSERT(0 == output_offset);
- Builtins* builtins = isolate_->builtins();
- Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
uint32_t pc = reinterpret_cast<uint32_t>(
construct_stub->instruction_start() +
isolate_->heap()->construct_stub_deopt_pc_offset()->value());
diff --git a/src/3rdparty/v8/src/arm/full-codegen-arm.cc b/src/3rdparty/v8/src/arm/full-codegen-arm.cc
index 1eff534..3c8df29 100644
--- a/src/3rdparty/v8/src/arm/full-codegen-arm.cc
+++ b/src/3rdparty/v8/src/arm/full-codegen-arm.cc
@@ -70,6 +70,7 @@ class JumpPatchSite BASE_EMBEDDED {
// the inlined smi code.
void EmitJumpIfNotSmi(Register reg, Label* target) {
ASSERT(!patch_site_.is_bound() && !info_emitted_);
+ Assembler::BlockConstPoolScope block_const_pool(masm_);
__ bind(&patch_site_);
__ cmp(reg, Operand(reg));
// Don't use b(al, ...) as that might emit the constant pool right after the
@@ -82,6 +83,7 @@ class JumpPatchSite BASE_EMBEDDED {
// the inlined smi code.
void EmitJumpIfSmi(Register reg, Label* target) {
ASSERT(!patch_site_.is_bound() && !info_emitted_);
+ Assembler::BlockConstPoolScope block_const_pool(masm_);
__ bind(&patch_site_);
__ cmp(reg, Operand(reg));
__ b(ne, target); // Never taken before patched.
@@ -180,13 +182,12 @@ void FullCodeGenerator::Generate() {
// Possibly allocate a local context.
int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
- if (heap_slots > 0 ||
- (scope()->is_qml_mode() && scope()->is_global_scope())) {
+ if (heap_slots > 0) {
Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is in r1.
__ push(r1);
if (heap_slots <= FastNewContextStub::kMaximumSlots) {
- FastNewContextStub stub((heap_slots < 0)?0:heap_slots);
+ FastNewContextStub stub(heap_slots);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kNewFunctionContext, 1);
@@ -267,11 +268,11 @@ void FullCodeGenerator::Generate() {
// For named function expressions, declare the function name as a
// constant.
if (scope()->is_function_scope() && scope()->function() != NULL) {
- VariableProxy* proxy = scope()->function();
- ASSERT(proxy->var()->mode() == CONST ||
- proxy->var()->mode() == CONST_HARMONY);
- ASSERT(proxy->var()->location() != Variable::UNALLOCATED);
- EmitDeclaration(proxy, proxy->var()->mode(), NULL);
+ VariableDeclaration* function = scope()->function();
+ ASSERT(function->proxy()->var()->mode() == CONST ||
+ function->proxy()->var()->mode() == CONST_HARMONY);
+ ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED);
+ VisitVariableDeclaration(function);
}
VisitDeclarations(scope()->declarations());
}
@@ -781,62 +782,51 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
}
-void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
- VariableMode mode,
- FunctionLiteral* function) {
+void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
+ // The variable in the declaration always resides in the current function
+ // context.
+ ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
+ if (FLAG_debug_code) {
+ // Check that we're not inside a with or catch context.
+ __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset));
+ __ CompareRoot(r1, Heap::kWithContextMapRootIndex);
+ __ Check(ne, "Declaration in with context.");
+ __ CompareRoot(r1, Heap::kCatchContextMapRootIndex);
+ __ Check(ne, "Declaration in catch context.");
+ }
+}
+
+
+void FullCodeGenerator::VisitVariableDeclaration(
+ VariableDeclaration* declaration) {
// If it was not possible to allocate the variable at compile time, we
// need to "declare" it at runtime to make sure it actually exists in the
// local context.
+ VariableProxy* proxy = declaration->proxy();
+ VariableMode mode = declaration->mode();
Variable* variable = proxy->var();
- bool binding_needs_init = (function == NULL) &&
- (mode == CONST || mode == CONST_HARMONY || mode == LET);
+ bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
switch (variable->location()) {
case Variable::UNALLOCATED:
- ++global_count_;
+ globals_->Add(variable->name());
+ globals_->Add(variable->binding_needs_init()
+ ? isolate()->factory()->the_hole_value()
+ : isolate()->factory()->undefined_value());
break;
case Variable::PARAMETER:
case Variable::LOCAL:
- if (function != NULL) {
- Comment cmnt(masm_, "[ Declaration");
- VisitForAccumulatorValue(function);
- __ str(result_register(), StackOperand(variable));
- } else if (binding_needs_init) {
- Comment cmnt(masm_, "[ Declaration");
+ if (hole_init) {
+ Comment cmnt(masm_, "[ VariableDeclaration");
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ str(ip, StackOperand(variable));
}
break;
case Variable::CONTEXT:
- // The variable in the decl always resides in the current function
- // context.
- ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
- if (FLAG_debug_code) {
- // Check that we're not inside a with or catch context.
- __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset));
- __ CompareRoot(r1, Heap::kWithContextMapRootIndex);
- __ Check(ne, "Declaration in with context.");
- __ CompareRoot(r1, Heap::kCatchContextMapRootIndex);
- __ Check(ne, "Declaration in catch context.");
- }
- if (function != NULL) {
- Comment cmnt(masm_, "[ Declaration");
- VisitForAccumulatorValue(function);
- __ str(result_register(), ContextOperand(cp, variable->index()));
- int offset = Context::SlotOffset(variable->index());
- // We know that we have written a function, which is not a smi.
- __ RecordWriteContextSlot(cp,
- offset,
- result_register(),
- r2,
- kLRHasBeenSaved,
- kDontSaveFPRegs,
- EMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
- } else if (binding_needs_init) {
- Comment cmnt(masm_, "[ Declaration");
+ if (hole_init) {
+ Comment cmnt(masm_, "[ VariableDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ str(ip, ContextOperand(cp, variable->index()));
// No write barrier since the_hole_value is in old space.
@@ -845,13 +835,11 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
break;
case Variable::LOOKUP: {
- Comment cmnt(masm_, "[ Declaration");
+ Comment cmnt(masm_, "[ VariableDeclaration");
__ mov(r2, Operand(variable->name()));
// Declaration nodes are always introduced in one of four modes.
- ASSERT(mode == VAR ||
- mode == CONST ||
- mode == CONST_HARMONY ||
- mode == LET);
+ ASSERT(mode == VAR || mode == LET ||
+ mode == CONST || mode == CONST_HARMONY);
PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY)
? READ_ONLY : NONE;
__ mov(r1, Operand(Smi::FromInt(attr)));
@@ -859,11 +847,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
// Note: For variables we must not push an initial value (such as
// 'undefined') because we may have a (legal) redeclaration and we
// must not destroy the current value.
- if (function != NULL) {
- __ Push(cp, r2, r1);
- // Push initial value for function declaration.
- VisitForStackValue(function);
- } else if (binding_needs_init) {
+ if (hole_init) {
__ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
__ Push(cp, r2, r1, r0);
} else {
@@ -877,6 +861,122 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
}
+void FullCodeGenerator::VisitFunctionDeclaration(
+ FunctionDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED: {
+ globals_->Add(variable->name());
+ Handle<SharedFunctionInfo> function =
+ Compiler::BuildFunctionInfo(declaration->fun(), script());
+ // Check for stack-overflow exception.
+ if (function.is_null()) return SetStackOverflow();
+ globals_->Add(function);
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ VisitForAccumulatorValue(declaration->fun());
+ __ str(result_register(), StackOperand(variable));
+ break;
+ }
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ VisitForAccumulatorValue(declaration->fun());
+ __ str(result_register(), ContextOperand(cp, variable->index()));
+ int offset = Context::SlotOffset(variable->index());
+ // We know that we have written a function, which is not a smi.
+ __ RecordWriteContextSlot(cp,
+ offset,
+ result_register(),
+ r2,
+ kLRHasBeenSaved,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
+ break;
+ }
+
+ case Variable::LOOKUP: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ __ mov(r2, Operand(variable->name()));
+ __ mov(r1, Operand(Smi::FromInt(NONE)));
+ __ Push(cp, r2, r1);
+ // Push initial value for function declaration.
+ VisitForStackValue(declaration->fun());
+ __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ break;
+ }
+ }
+}
+
+
+void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ Handle<JSModule> instance = declaration->module()->interface()->Instance();
+ ASSERT(!instance.is_null());
+
+ switch (variable->location()) {
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "[ ModuleDeclaration");
+ globals_->Add(variable->name());
+ globals_->Add(instance);
+ Visit(declaration->module());
+ break;
+ }
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ ModuleDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ __ mov(r1, Operand(instance));
+ __ str(r1, ContextOperand(cp, variable->index()));
+ Visit(declaration->module());
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::LOOKUP:
+ UNREACHABLE();
+ }
+}
+
+
+void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ // TODO(rossberg)
+ break;
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ ImportDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ // TODO(rossberg)
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::LOOKUP:
+ UNREACHABLE();
+ }
+}
+
+
+void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
+ // TODO(rossberg)
+}
+
+
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
// The context is the first argument.
@@ -1230,7 +1330,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
__ bind(&fast);
}
- __ ldr(r0, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ ldr(r0, GlobalObjectOperand());
__ mov(r2, Operand(var->name()));
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
@@ -1317,7 +1417,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
Comment cmnt(masm_, "Global variable");
// Use inline caching. Variable name is passed in r2 and the global
// object (receiver) in r0.
- __ ldr(r0, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ ldr(r0, GlobalObjectOperand());
__ mov(r2, Operand(var->name()));
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
@@ -1984,7 +2084,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
if (var->IsUnallocated()) {
// Global var, const, or let.
__ mov(r2, Operand(var->name()));
- __ ldr(r1, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ ldr(r1, GlobalObjectOperand());
Handle<Code> ic = is_classic_mode()
? isolate()->builtins()->StoreIC_Initialize()
: isolate()->builtins()->StoreIC_Initialize_Strict();
@@ -2263,6 +2363,18 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
}
// Record source position for debugger.
SetSourcePosition(expr->position());
+
+ // Record call targets in unoptimized code, but not in the snapshot.
+ if (!Serializer::enabled()) {
+ flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
+ Handle<Object> uninitialized =
+ TypeFeedbackCells::UninitializedSentinel(isolate());
+ Handle<JSGlobalPropertyCell> cell =
+ isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
+ RecordTypeFeedbackCell(expr->id(), cell);
+ __ mov(r2, Operand(cell));
+ }
+
CallFunctionStub stub(arg_count, flags);
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
@@ -2294,12 +2406,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
__ mov(r1, Operand(Smi::FromInt(scope()->start_position())));
__ push(r1);
- // Push the qml mode flag.
- __ mov(r1, Operand(Smi::FromInt(is_qml_mode())));
- __ push(r1);
-
// Do the runtime call.
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
}
@@ -2356,7 +2464,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
context()->DropAndPlug(1, r0);
} else if (proxy != NULL && proxy->var()->IsUnallocated()) {
// Push global object as receiver for the call IC.
- __ ldr(r0, proxy->var()->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ ldr(r0, GlobalObjectOperand());
__ push(r0);
EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
} else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
@@ -3358,104 +3466,6 @@ void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
}
-void FullCodeGenerator::EmitSwapElements(CallRuntime* expr) {
- ZoneList<Expression*>* args = expr->arguments();
- ASSERT(args->length() == 3);
- VisitForStackValue(args->at(0));
- VisitForStackValue(args->at(1));
- VisitForStackValue(args->at(2));
- Label done;
- Label slow_case;
- Register object = r0;
- Register index1 = r1;
- Register index2 = r2;
- Register elements = r3;
- Register scratch1 = r4;
- Register scratch2 = r5;
-
- __ ldr(object, MemOperand(sp, 2 * kPointerSize));
- // Fetch the map and check if array is in fast case.
- // Check that object doesn't require security checks and
- // has no indexed interceptor.
- __ CompareObjectType(object, scratch1, scratch2, JS_ARRAY_TYPE);
- __ b(ne, &slow_case);
- // Map is now in scratch1.
-
- __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
- __ tst(scratch2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
- __ b(ne, &slow_case);
-
- // Check the object's elements are in fast case and writable.
- __ ldr(elements, FieldMemOperand(object, JSObject::kElementsOffset));
- __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
- __ cmp(scratch1, ip);
- __ b(ne, &slow_case);
-
- // Check that both indices are smis.
- __ ldr(index1, MemOperand(sp, 1 * kPointerSize));
- __ ldr(index2, MemOperand(sp, 0));
- __ JumpIfNotBothSmi(index1, index2, &slow_case);
-
- // Check that both indices are valid.
- __ ldr(scratch1, FieldMemOperand(object, JSArray::kLengthOffset));
- __ cmp(scratch1, index1);
- __ cmp(scratch1, index2, hi);
- __ b(ls, &slow_case);
-
- // Bring the address of the elements into index1 and index2.
- __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ add(index1,
- scratch1,
- Operand(index1, LSL, kPointerSizeLog2 - kSmiTagSize));
- __ add(index2,
- scratch1,
- Operand(index2, LSL, kPointerSizeLog2 - kSmiTagSize));
-
- // Swap elements.
- __ ldr(scratch1, MemOperand(index1, 0));
- __ ldr(scratch2, MemOperand(index2, 0));
- __ str(scratch1, MemOperand(index2, 0));
- __ str(scratch2, MemOperand(index1, 0));
-
- Label no_remembered_set;
- __ CheckPageFlag(elements,
- scratch1,
- 1 << MemoryChunk::SCAN_ON_SCAVENGE,
- ne,
- &no_remembered_set);
- // Possible optimization: do a check that both values are Smis
- // (or them and test against Smi mask.)
-
- // We are swapping two objects in an array and the incremental marker never
- // pauses in the middle of scanning a single object. Therefore the
- // incremental marker is not disturbed, so we don't need to call the
- // RecordWrite stub that notifies the incremental marker.
- __ RememberedSetHelper(elements,
- index1,
- scratch2,
- kDontSaveFPRegs,
- MacroAssembler::kFallThroughAtEnd);
- __ RememberedSetHelper(elements,
- index2,
- scratch2,
- kDontSaveFPRegs,
- MacroAssembler::kFallThroughAtEnd);
-
- __ bind(&no_remembered_set);
- // We are done. Drop elements from the stack, and return undefined.
- __ Drop(3);
- __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
- __ jmp(&done);
-
- __ bind(&slow_case);
- __ CallRuntime(Runtime::kSwapElements, 3);
-
- __ bind(&done);
- context()->Plug(r0);
-}
-
-
void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(2, args->length());
@@ -3878,7 +3888,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
// but "delete this" is allowed.
ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
if (var->IsUnallocated()) {
- __ ldr(r2, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ __ ldr(r2, GlobalObjectOperand());
__ mov(r1, Operand(var->name()));
__ mov(r0, Operand(Smi::FromInt(kNonStrictMode)));
__ Push(r2, r1, r0);
@@ -4181,7 +4191,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
VariableProxy* proxy = expr->AsVariableProxy();
if (proxy != NULL && proxy->var()->IsUnallocated()) {
Comment cmnt(masm_, "Global variable");
- __ ldr(r0, proxy->var()->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ __ ldr(r0, GlobalObjectOperand());
__ mov(r2, Operand(proxy->name()));
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
// Use a regular load, not a contextual load, to avoid a reference
@@ -4451,7 +4461,8 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
Scope* declaration_scope = scope()->DeclarationScope();
- if (declaration_scope->is_global_scope()) {
+ if (declaration_scope->is_global_scope() ||
+ declaration_scope->is_module_scope()) {
// Contexts nested in the global context have a canonical empty function
// as their closure, not the anonymous closure containing the global
// code. Pass a smi sentinel and let the runtime look up the empty
diff --git a/src/3rdparty/v8/src/arm/ic-arm.cc b/src/3rdparty/v8/src/arm/ic-arm.cc
index e843657..c12c167 100644
--- a/src/3rdparty/v8/src/arm/ic-arm.cc
+++ b/src/3rdparty/v8/src/arm/ic-arm.cc
@@ -774,7 +774,7 @@ static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm,
__ b(lt, slow_case);
// Check that the key is a positive smi.
- __ tst(key, Operand(0x8000001));
+ __ tst(key, Operand(0x80000001));
__ b(ne, slow_case);
// Load the elements into scratch1 and check its map.
@@ -1690,12 +1690,12 @@ void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
// Activate inlined smi code.
if (previous_state == UNINITIALIZED) {
- PatchInlinedSmiCode(address());
+ PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
}
}
-void PatchInlinedSmiCode(Address address) {
+void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
Address cmp_instruction_address =
address + Assembler::kCallTargetAddressOffset;
@@ -1729,34 +1729,31 @@ void PatchInlinedSmiCode(Address address) {
Instr instr_at_patch = Assembler::instr_at(patch_address);
Instr branch_instr =
Assembler::instr_at(patch_address + Instruction::kInstrSize);
- ASSERT(Assembler::IsCmpRegister(instr_at_patch));
- ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(),
- Assembler::GetRm(instr_at_patch).code());
+ // This is patching a conditional "jump if not smi/jump if smi" site.
+ // Enabling by changing from
+ // cmp rx, rx
+ // b eq/ne, <target>
+ // to
+ // tst rx, #kSmiTagMask
+ // b ne/eq, <target>
+ // and vice-versa to be disabled again.
+ CodePatcher patcher(patch_address, 2);
+ Register reg = Assembler::GetRn(instr_at_patch);
+ if (check == ENABLE_INLINED_SMI_CHECK) {
+ ASSERT(Assembler::IsCmpRegister(instr_at_patch));
+ ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(),
+ Assembler::GetRm(instr_at_patch).code());
+ patcher.masm()->tst(reg, Operand(kSmiTagMask));
+ } else {
+ ASSERT(check == DISABLE_INLINED_SMI_CHECK);
+ ASSERT(Assembler::IsTstImmediate(instr_at_patch));
+ patcher.masm()->cmp(reg, reg);
+ }
ASSERT(Assembler::IsBranch(branch_instr));
if (Assembler::GetCondition(branch_instr) == eq) {
- // This is patching a "jump if not smi" site to be active.
- // Changing
- // cmp rx, rx
- // b eq, <target>
- // to
- // tst rx, #kSmiTagMask
- // b ne, <target>
- CodePatcher patcher(patch_address, 2);
- Register reg = Assembler::GetRn(instr_at_patch);
- patcher.masm()->tst(reg, Operand(kSmiTagMask));
patcher.EmitCondition(ne);
} else {
ASSERT(Assembler::GetCondition(branch_instr) == ne);
- // This is patching a "jump if smi" site to be active.
- // Changing
- // cmp rx, rx
- // b ne, <target>
- // to
- // tst rx, #kSmiTagMask
- // b eq, <target>
- CodePatcher patcher(patch_address, 2);
- Register reg = Assembler::GetRn(instr_at_patch);
- patcher.masm()->tst(reg, Operand(kSmiTagMask));
patcher.EmitCondition(eq);
}
}
diff --git a/src/3rdparty/v8/src/arm/lithium-arm.cc b/src/3rdparty/v8/src/arm/lithium-arm.cc
index 31fd4ad..5c60f53 100644
--- a/src/3rdparty/v8/src/arm/lithium-arm.cc
+++ b/src/3rdparty/v8/src/arm/lithium-arm.cc
@@ -108,22 +108,17 @@ void LInstruction::PrintTo(StringStream* stream) {
}
-template<int R, int I, int T>
-void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) {
+void LInstruction::PrintDataTo(StringStream* stream) {
stream->Add("= ");
- for (int i = 0; i < inputs_.length(); i++) {
+ for (int i = 0; i < InputCount(); i++) {
if (i > 0) stream->Add(" ");
- inputs_[i]->PrintTo(stream);
+ InputAt(i)->PrintTo(stream);
}
}
-template<int R, int I, int T>
-void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) {
- for (int i = 0; i < results_.length(); i++) {
- if (i > 0) stream->Add(" ");
- results_[i]->PrintTo(stream);
- }
+void LInstruction::PrintOutputOperandTo(StringStream* stream) {
+ if (HasResult()) result()->PrintTo(stream);
}
@@ -732,22 +727,6 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
}
-LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
- LInstruction* instr, int ast_id) {
- ASSERT(instruction_pending_deoptimization_environment_ == NULL);
- ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
- instruction_pending_deoptimization_environment_ = instr;
- pending_deoptimization_ast_id_ = ast_id;
- return instr;
-}
-
-
-void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
- instruction_pending_deoptimization_environment_ = NULL;
- pending_deoptimization_ast_id_ = AstNode::kNoNumber;
-}
-
-
LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
HInstruction* hinstr,
CanDeoptimize can_deoptimize) {
@@ -760,8 +739,10 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
if (hinstr->HasObservableSideEffects()) {
ASSERT(hinstr->next()->IsSimulate());
HSimulate* sim = HSimulate::cast(hinstr->next());
- instr = SetInstructionPendingDeoptimizationEnvironment(
- instr, sim->ast_id());
+ ASSERT(instruction_pending_deoptimization_environment_ == NULL);
+ ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
+ instruction_pending_deoptimization_environment_ = instr;
+ pending_deoptimization_ast_id_ = sim->ast_id();
}
// If instruction does not have side-effects lazy deoptimization
@@ -779,12 +760,6 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
}
-LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
- instr->MarkAsSaveDoubles();
- return instr;
-}
-
-
LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
ASSERT(!instr->HasPointerMap());
instr->set_pointer_map(new(zone()) LPointerMap(position_));
@@ -1151,7 +1126,7 @@ LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
LOperand* context = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new(zone()) LGlobalObject(context, instr->qml_global()));
+ return DefineAsRegister(new(zone()) LGlobalObject(context));
}
@@ -1224,7 +1199,7 @@ LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
argument_count_ -= instr->argument_count();
- return MarkAsCall(DefineFixed(new(zone()) LCallGlobal(instr->qml_global()), r0), instr);
+ return MarkAsCall(DefineFixed(new(zone()) LCallGlobal, r0), instr);
}
@@ -1295,6 +1270,7 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
ASSERT(instr->value()->representation().IsInteger32());
ASSERT(instr->representation().IsInteger32());
+ if (instr->HasNoUses()) return NULL;
LOperand* value = UseRegisterAtStart(instr->value());
return DefineAsRegister(new(zone()) LBitNotI(value));
}
@@ -1319,6 +1295,75 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
}
+bool LChunkBuilder::HasMagicNumberForDivisor(int32_t divisor) {
+ uint32_t divisor_abs = abs(divisor);
+ // Dividing by 0, 1, and powers of 2 is easy.
+ // Note that IsPowerOf2(0) returns true;
+ ASSERT(IsPowerOf2(0) == true);
+ if (IsPowerOf2(divisor_abs)) return true;
+
+ // We have magic numbers for a few specific divisors.
+ // Details and proofs can be found in:
+ // - Hacker's Delight, Henry S. Warren, Jr.
+ // - The PowerPC Compiler Writer’s Guide
+ // and probably many others.
+ //
+ // We handle
+ // <divisor with magic numbers> * <power of 2>
+ // but not
+ // <divisor with magic numbers> * <other divisor with magic numbers>
+ int32_t power_of_2_factor =
+ CompilerIntrinsics::CountTrailingZeros(divisor_abs);
+ DivMagicNumbers magic_numbers =
+ DivMagicNumberFor(divisor_abs >> power_of_2_factor);
+ if (magic_numbers.M != InvalidDivMagicNumber.M) return true;
+
+ return false;
+}
+
+
+HValue* LChunkBuilder::SimplifiedDividendForMathFloorOfDiv(HValue* dividend) {
+ // A value with an integer representation does not need to be transformed.
+ if (dividend->representation().IsInteger32()) {
+ return dividend;
+ // A change from an integer32 can be replaced by the integer32 value.
+ } else if (dividend->IsChange() &&
+ HChange::cast(dividend)->from().IsInteger32()) {
+ return HChange::cast(dividend)->value();
+ }
+ return NULL;
+}
+
+
+HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) {
+ // Only optimize when we have magic numbers for the divisor.
+ // The standard integer division routine is usually slower than transitionning
+ // to VFP.
+ if (divisor->IsConstant() &&
+ HConstant::cast(divisor)->HasInteger32Value()) {
+ HConstant* constant_val = HConstant::cast(divisor);
+ int32_t int32_val = constant_val->Integer32Value();
+ if (LChunkBuilder::HasMagicNumberForDivisor(int32_val)) {
+ return constant_val->CopyToRepresentation(Representation::Integer32());
+ }
+ }
+ return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
+ HValue* right = instr->right();
+ LOperand* dividend = UseRegister(instr->left());
+ LOperand* divisor = UseRegisterOrConstant(right);
+ LOperand* remainder = TempRegister();
+ ASSERT(right->IsConstant() &&
+ HConstant::cast(right)->HasInteger32Value() &&
+ HasMagicNumberForDivisor(HConstant::cast(right)->Integer32Value()));
+ return AssignEnvironment(DefineAsRegister(
+ new LMathFloorOfDiv(dividend, divisor, remainder)));
+}
+
+
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
if (instr->representation().IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
@@ -2242,9 +2287,12 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
if (pending_deoptimization_ast_id_ == instr->ast_id()) {
LInstruction* result = new(zone()) LLazyBailout;
result = AssignEnvironment(result);
+ // Store the lazy deopt environment with the instruction if needed. Right
+ // now it is only used for LInstanceOfKnownGlobal.
instruction_pending_deoptimization_environment_->
- set_deoptimization_environment(result->environment());
- ClearInstructionPendingDeoptimizationEnvironment();
+ SetDeferredLazyDeoptimizationEnvironment(result->environment());
+ instruction_pending_deoptimization_environment_ = NULL;
+ pending_deoptimization_ast_id_ = AstNode::kNoNumber;
return result;
}
@@ -2271,8 +2319,8 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
undefined,
instr->call_kind(),
instr->is_construct());
- if (instr->arguments() != NULL) {
- inner->Bind(instr->arguments(), graph()->GetArgumentsObject());
+ if (instr->arguments_var() != NULL) {
+ inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
}
current_block_->UpdateEnvironment(inner);
chunk_->AddInlinedClosure(instr->closure());
@@ -2281,10 +2329,21 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
+ LInstruction* pop = NULL;
+
+ HEnvironment* env = current_block_->last_environment();
+
+ if (instr->arguments_pushed()) {
+ int argument_count = env->arguments_environment()->parameter_count();
+ pop = new(zone()) LDrop(argument_count);
+ argument_count_ -= argument_count;
+ }
+
HEnvironment* outer = current_block_->last_environment()->
DiscardInlined(false);
current_block_->UpdateEnvironment(outer);
- return NULL;
+
+ return pop;
}
diff --git a/src/3rdparty/v8/src/arm/lithium-arm.h b/src/3rdparty/v8/src/arm/lithium-arm.h
index 30a7bf5..dbae813 100644
--- a/src/3rdparty/v8/src/arm/lithium-arm.h
+++ b/src/3rdparty/v8/src/arm/lithium-arm.h
@@ -132,6 +132,7 @@ class LCodeGen;
V(LoadNamedField) \
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
+ V(MathFloorOfDiv) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
@@ -179,7 +180,8 @@ class LCodeGen;
V(CheckMapValue) \
V(LoadFieldByIndex) \
V(DateField) \
- V(WrapReceiver)
+ V(WrapReceiver) \
+ V(Drop)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
@@ -203,15 +205,14 @@ class LInstruction: public ZoneObject {
LInstruction()
: environment_(NULL),
hydrogen_value_(NULL),
- is_call_(false),
- is_save_doubles_(false) { }
+ is_call_(false) { }
virtual ~LInstruction() { }
virtual void CompileToNative(LCodeGen* generator) = 0;
virtual const char* Mnemonic() const = 0;
virtual void PrintTo(StringStream* stream);
- virtual void PrintDataTo(StringStream* stream) = 0;
- virtual void PrintOutputOperandTo(StringStream* stream) = 0;
+ virtual void PrintDataTo(StringStream* stream);
+ virtual void PrintOutputOperandTo(StringStream* stream);
enum Opcode {
// Declare a unique enum value for each instruction.
@@ -246,22 +247,12 @@ class LInstruction: public ZoneObject {
void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; }
HValue* hydrogen_value() const { return hydrogen_value_; }
- void set_deoptimization_environment(LEnvironment* env) {
- deoptimization_environment_.set(env);
- }
- LEnvironment* deoptimization_environment() const {
- return deoptimization_environment_.get();
- }
- bool HasDeoptimizationEnvironment() const {
- return deoptimization_environment_.is_set();
- }
+ virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { }
void MarkAsCall() { is_call_ = true; }
- void MarkAsSaveDoubles() { is_save_doubles_ = true; }
// Interface to the register allocator and iterators.
bool IsMarkedAsCall() const { return is_call_; }
- bool IsMarkedAsSaveDoubles() const { return is_save_doubles_; }
virtual bool HasResult() const = 0;
virtual LOperand* result() = 0;
@@ -282,9 +273,7 @@ class LInstruction: public ZoneObject {
LEnvironment* environment_;
SetOncePointer<LPointerMap> pointer_map_;
HValue* hydrogen_value_;
- SetOncePointer<LEnvironment> deoptimization_environment_;
bool is_call_;
- bool is_save_doubles_;
};
@@ -306,9 +295,6 @@ class LTemplateInstruction: public LInstruction {
int TempCount() { return T; }
LOperand* TempAt(int i) { return temps_[i]; }
- virtual void PrintDataTo(StringStream* stream);
- virtual void PrintOutputOperandTo(StringStream* stream);
-
protected:
EmbeddedContainer<LOperand*, R> results_;
EmbeddedContainer<LOperand*, I> inputs_;
@@ -534,9 +520,8 @@ class LArgumentsLength: public LTemplateInstruction<1, 1, 0> {
class LArgumentsElements: public LTemplateInstruction<1, 0, 0> {
public:
- LArgumentsElements() { }
-
DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements")
+ DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements)
};
@@ -582,6 +567,21 @@ class LDivI: public LTemplateInstruction<1, 2, 0> {
};
+class LMathFloorOfDiv: public LTemplateInstruction<1, 2, 1> {
+ public:
+ LMathFloorOfDiv(LOperand* left,
+ LOperand* right,
+ LOperand* temp = NULL) {
+ inputs_[0] = left;
+ inputs_[1] = right;
+ temps_[0] = temp;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv, "math-floor-of-div")
+ DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
+};
+
+
class LMulI: public LTemplateInstruction<1, 2, 1> {
public:
LMulI(LOperand* left, LOperand* right, LOperand* temp) {
@@ -834,6 +834,15 @@ class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> {
DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal)
Handle<JSFunction> function() const { return hydrogen()->function(); }
+ LEnvironment* GetDeferredLazyDeoptimizationEnvironment() {
+ return lazy_deopt_env_;
+ }
+ virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) {
+ lazy_deopt_env_ = env;
+ }
+
+ private:
+ LEnvironment* lazy_deopt_env_;
};
@@ -1227,6 +1236,7 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -1243,13 +1253,13 @@ class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
- LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
- LOperand* key) {
+ LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) {
inputs_[0] = external_pointer;
inputs_[1] = key;
}
@@ -1263,6 +1273,7 @@ class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -1378,6 +1389,19 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> {
};
+class LDrop: public LTemplateInstruction<0, 0, 0> {
+ public:
+ explicit LDrop(int count) : count_(count) { }
+
+ int count() const { return count_; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Drop, "drop")
+
+ private:
+ int count_;
+};
+
+
class LThisFunction: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function")
@@ -1412,17 +1436,13 @@ class LDeclareGlobals: public LTemplateInstruction<0, 0, 0> {
class LGlobalObject: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LGlobalObject(LOperand* context, bool qml_global) {
+ explicit LGlobalObject(LOperand* context) {
inputs_[0] = context;
- qml_global_ = qml_global;
}
DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object")
LOperand* context() { return InputAt(0); }
- bool qml_global() { return qml_global_; }
- private:
- bool qml_global_;
};
@@ -1464,6 +1484,7 @@ class LInvokeFunction: public LTemplateInstruction<1, 1, 0> {
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
+ Handle<JSFunction> known_function() { return hydrogen()->known_function(); }
};
@@ -1514,16 +1535,10 @@ class LCallGlobal: public LTemplateInstruction<1, 0, 0> {
DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call-global")
DECLARE_HYDROGEN_ACCESSOR(CallGlobal)
- explicit LCallGlobal(bool qml_global) : qml_global_(qml_global) {}
-
virtual void PrintDataTo(StringStream* stream);
Handle<String> name() const {return hydrogen()->name(); }
int arity() const { return hydrogen()->argument_count() - 1; }
-
- bool qml_global() { return qml_global_; }
- private:
- bool qml_global_;
};
@@ -1727,6 +1742,7 @@ class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
LOperand* object() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -1749,6 +1765,9 @@ class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
+
+ bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
};
@@ -1791,6 +1810,7 @@ class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -2284,6 +2304,10 @@ class LChunkBuilder BASE_EMBEDDED {
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
#undef DECLARE_DO
+ static bool HasMagicNumberForDivisor(int32_t divisor);
+ static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* val);
+ static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val);
+
private:
enum Status {
UNUSED,
@@ -2379,11 +2403,6 @@ class LChunkBuilder BASE_EMBEDDED {
LInstruction* instr,
HInstruction* hinstr,
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
- LInstruction* MarkAsSaveDoubles(LInstruction* instr);
-
- LInstruction* SetInstructionPendingDeoptimizationEnvironment(
- LInstruction* instr, int ast_id);
- void ClearInstructionPendingDeoptimizationEnvironment();
LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
int* argument_index_accumulator);
diff --git a/src/3rdparty/v8/src/arm/lithium-codegen-arm.cc b/src/3rdparty/v8/src/arm/lithium-codegen-arm.cc
index 045814f..d224d24 100644
--- a/src/3rdparty/v8/src/arm/lithium-codegen-arm.cc
+++ b/src/3rdparty/v8/src/arm/lithium-codegen-arm.cc
@@ -174,13 +174,12 @@ bool LCodeGen::GeneratePrologue() {
// Possibly allocate a local context.
int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
- if (heap_slots > 0 ||
- (scope()->is_qml_mode() && scope()->is_global_scope())) {
+ if (heap_slots > 0) {
Comment(";;; Allocate local context");
// Argument to NewContext is the function, which is in r1.
__ push(r1);
if (heap_slots <= FastNewContextStub::kMaximumSlots) {
- FastNewContextStub stub((heap_slots < 0)?0:heap_slots);
+ FastNewContextStub stub(heap_slots);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kNewFunctionContext, 1);
@@ -1035,6 +1034,100 @@ void LCodeGen::DoModI(LModI* instr) {
}
+void LCodeGen::EmitSignedIntegerDivisionByConstant(
+ Register result,
+ Register dividend,
+ int32_t divisor,
+ Register remainder,
+ Register scratch,
+ LEnvironment* environment) {
+ ASSERT(!AreAliased(dividend, scratch, ip));
+ ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor));
+
+ uint32_t divisor_abs = abs(divisor);
+
+ int32_t power_of_2_factor =
+ CompilerIntrinsics::CountTrailingZeros(divisor_abs);
+
+ switch (divisor_abs) {
+ case 0:
+ DeoptimizeIf(al, environment);
+ return;
+
+ case 1:
+ if (divisor > 0) {
+ __ Move(result, dividend);
+ } else {
+ __ rsb(result, dividend, Operand(0), SetCC);
+ DeoptimizeIf(vs, environment);
+ }
+ // Compute the remainder.
+ __ mov(remainder, Operand(0));
+ return;
+
+ default:
+ if (IsPowerOf2(divisor_abs)) {
+ // Branch and condition free code for integer division by a power
+ // of two.
+ int32_t power = WhichPowerOf2(divisor_abs);
+ if (power > 1) {
+ __ mov(scratch, Operand(dividend, ASR, power - 1));
+ }
+ __ add(scratch, dividend, Operand(scratch, LSR, 32 - power));
+ __ mov(result, Operand(scratch, ASR, power));
+ // Negate if necessary.
+ // We don't need to check for overflow because the case '-1' is
+ // handled separately.
+ if (divisor < 0) {
+ ASSERT(divisor != -1);
+ __ rsb(result, result, Operand(0));
+ }
+ // Compute the remainder.
+ if (divisor > 0) {
+ __ sub(remainder, dividend, Operand(result, LSL, power));
+ } else {
+ __ add(remainder, dividend, Operand(result, LSL, power));
+ }
+ return;
+ } else {
+ // Use magic numbers for a few specific divisors.
+ // Details and proofs can be found in:
+ // - Hacker's Delight, Henry S. Warren, Jr.
+ // - The PowerPC Compiler Writer’s Guide
+ // and probably many others.
+ //
+ // We handle
+ // <divisor with magic numbers> * <power of 2>
+ // but not
+ // <divisor with magic numbers> * <other divisor with magic numbers>
+ DivMagicNumbers magic_numbers =
+ DivMagicNumberFor(divisor_abs >> power_of_2_factor);
+ // Branch and condition free code for integer division by a power
+ // of two.
+ const int32_t M = magic_numbers.M;
+ const int32_t s = magic_numbers.s + power_of_2_factor;
+
+ __ mov(ip, Operand(M));
+ __ smull(ip, scratch, dividend, ip);
+ if (M < 0) {
+ __ add(scratch, scratch, Operand(dividend));
+ }
+ if (s > 0) {
+ __ mov(scratch, Operand(scratch, ASR, s));
+ }
+ __ add(result, scratch, Operand(dividend, LSR, 31));
+ if (divisor < 0) __ rsb(result, result, Operand(0));
+ // Compute the remainder.
+ __ mov(ip, Operand(divisor));
+ // This sequence could be replaced with 'mls' when
+ // it gets implemented.
+ __ mul(scratch, result, ip);
+ __ sub(remainder, dividend, scratch);
+ }
+ }
+}
+
+
void LCodeGen::DoDivI(LDivI* instr) {
class DeferredDivI: public LDeferredCode {
public:
@@ -1116,6 +1209,34 @@ void LCodeGen::DoDivI(LDivI* instr) {
}
+void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
+ const Register result = ToRegister(instr->result());
+ const Register left = ToRegister(instr->InputAt(0));
+ const Register remainder = ToRegister(instr->TempAt(0));
+ const Register scratch = scratch0();
+
+ // We only optimize this for division by constants, because the standard
+ // integer division routine is usually slower than transitionning to VFP.
+ // This could be optimized on processors with SDIV available.
+ ASSERT(instr->InputAt(1)->IsConstantOperand());
+ int32_t divisor = ToInteger32(LConstantOperand::cast(instr->InputAt(1)));
+ if (divisor < 0) {
+ __ cmp(left, Operand(0));
+ DeoptimizeIf(eq, instr->environment());
+ }
+ EmitSignedIntegerDivisionByConstant(result,
+ left,
+ divisor,
+ remainder,
+ scratch,
+ instr->environment());
+ // We operated a truncating division. Correct the result if necessary.
+ __ cmp(remainder, Operand(0));
+ __ teq(remainder, Operand(divisor), ne);
+ __ sub(result, result, Operand(1), LeaveCC, mi);
+}
+
+
template<int T>
void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
Token::Value op) {
@@ -2268,8 +2389,7 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
RelocInfo::CODE_TARGET,
instr,
RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
- ASSERT(instr->HasDeoptimizationEnvironment());
- LEnvironment* env = instr->deoptimization_environment();
+ LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
// Put the result value into the result register slot and
// restore all registers.
@@ -2467,42 +2587,38 @@ void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
Register object = ToRegister(instr->object());
Register result = ToRegister(instr->result());
Register scratch = scratch0();
+
int map_count = instr->hydrogen()->types()->length();
+ bool need_generic = instr->hydrogen()->need_generic();
+
+ if (map_count == 0 && !need_generic) {
+ DeoptimizeIf(al, instr->environment());
+ return;
+ }
Handle<String> name = instr->hydrogen()->name();
- if (map_count == 0) {
- ASSERT(instr->hydrogen()->need_generic());
- __ mov(r2, Operand(name));
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- CallCode(ic, RelocInfo::CODE_TARGET, instr);
- } else {
- Label done;
- __ ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
- for (int i = 0; i < map_count - 1; ++i) {
- Handle<Map> map = instr->hydrogen()->types()->at(i);
+ Label done;
+ __ ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
+ for (int i = 0; i < map_count; ++i) {
+ bool last = (i == map_count - 1);
+ Handle<Map> map = instr->hydrogen()->types()->at(i);
+ __ cmp(scratch, Operand(map));
+ if (last && !need_generic) {
+ DeoptimizeIf(ne, instr->environment());
+ EmitLoadFieldOrConstantFunction(result, object, map, name);
+ } else {
Label next;
- __ cmp(scratch, Operand(map));
__ b(ne, &next);
EmitLoadFieldOrConstantFunction(result, object, map, name);
__ b(&done);
__ bind(&next);
}
- Handle<Map> map = instr->hydrogen()->types()->last();
- __ cmp(scratch, Operand(map));
- if (instr->hydrogen()->need_generic()) {
- Label generic;
- __ b(ne, &generic);
- EmitLoadFieldOrConstantFunction(result, object, map, name);
- __ b(&done);
- __ bind(&generic);
- __ mov(r2, Operand(name));
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- CallCode(ic, RelocInfo::CODE_TARGET, instr);
- } else {
- DeoptimizeIf(ne, instr->environment());
- EmitLoadFieldOrConstantFunction(result, object, map, name);
- }
- __ bind(&done);
}
+ if (need_generic) {
+ __ mov(r2, Operand(name));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ }
+ __ bind(&done);
}
@@ -2628,7 +2744,9 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
// Load the result.
__ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
- __ ldr(result, FieldMemOperand(scratch, FixedArray::kHeaderSize));
+ uint32_t offset = FixedArray::kHeaderSize +
+ (instr->additional_index() << kPointerSizeLog2);
+ __ ldr(result, FieldMemOperand(scratch, offset));
// Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) {
@@ -2660,13 +2778,14 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
}
Operand operand = key_is_constant
- ? Operand(constant_key * (1 << shift_size) +
+ ? Operand(((constant_key + instr->additional_index()) << shift_size) +
FixedDoubleArray::kHeaderSize - kHeapObjectTag)
: Operand(key, LSL, shift_size);
__ add(elements, elements, operand);
if (!key_is_constant) {
__ add(elements, elements,
- Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
+ Operand((FixedDoubleArray::kHeaderSize - kHeapObjectTag) +
+ (instr->additional_index() << shift_size)));
}
__ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
@@ -2693,26 +2812,33 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
key = ToRegister(instr->key());
}
int shift_size = ElementsKindToShiftSize(elements_kind);
+ int additional_offset = instr->additional_index() << shift_size;
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
CpuFeatures::Scope scope(VFP3);
DwVfpRegister result = ToDoubleRegister(instr->result());
Operand operand = key_is_constant
- ? Operand(constant_key * (1 << shift_size))
+ ? Operand(constant_key << shift_size)
: Operand(key, LSL, shift_size);
__ add(scratch0(), external_pointer, operand);
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
- __ vldr(result.low(), scratch0(), 0);
+ __ vldr(result.low(), scratch0(), additional_offset);
__ vcvt_f64_f32(result, result.low());
} else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
- __ vldr(result, scratch0(), 0);
+ __ vldr(result, scratch0(), additional_offset);
}
} else {
Register result = ToRegister(instr->result());
+ if (instr->additional_index() != 0 && !key_is_constant) {
+ __ add(scratch0(), key, Operand(instr->additional_index()));
+ }
MemOperand mem_operand(key_is_constant
- ? MemOperand(external_pointer, constant_key * (1 << shift_size))
- : MemOperand(external_pointer, key, LSL, shift_size));
+ ? MemOperand(external_pointer,
+ (constant_key << shift_size) + additional_offset)
+ : (instr->additional_index() == 0
+ ? MemOperand(external_pointer, key, LSL, shift_size)
+ : MemOperand(external_pointer, scratch0(), LSL, shift_size)));
switch (elements_kind) {
case EXTERNAL_BYTE_ELEMENTS:
__ ldrsb(result, mem_operand);
@@ -2765,16 +2891,20 @@ void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
Register scratch = scratch0();
Register result = ToRegister(instr->result());
- // Check if the calling frame is an arguments adaptor frame.
- Label done, adapted;
- __ ldr(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
- __ ldr(result, MemOperand(scratch, StandardFrameConstants::kContextOffset));
- __ cmp(result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
+ if (instr->hydrogen()->from_inlined()) {
+ __ sub(result, sp, Operand(2 * kPointerSize));
+ } else {
+ // Check if the calling frame is an arguments adaptor frame.
+ Label done, adapted;
+ __ ldr(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+ __ ldr(result, MemOperand(scratch, StandardFrameConstants::kContextOffset));
+ __ cmp(result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
- // Result is the frame pointer for the frame if not adapted and for the real
- // frame below the adaptor frame if adapted.
- __ mov(result, fp, LeaveCC, ne);
- __ mov(result, scratch, LeaveCC, eq);
+ // Result is the frame pointer for the frame if not adapted and for the real
+ // frame below the adaptor frame if adapted.
+ __ mov(result, fp, LeaveCC, ne);
+ __ mov(result, scratch, LeaveCC, eq);
+ }
}
@@ -2883,7 +3013,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
__ b(ne, &loop);
__ bind(&invoke);
- ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ ASSERT(instr->HasPointerMap());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator safepoint_generator(
@@ -2908,6 +3038,11 @@ void LCodeGen::DoPushArgument(LPushArgument* instr) {
}
+void LCodeGen::DoDrop(LDrop* instr) {
+ __ Drop(instr->count());
+}
+
+
void LCodeGen::DoThisFunction(LThisFunction* instr) {
Register result = ToRegister(instr->result());
__ LoadHeapObject(result, instr->hydrogen()->closure());
@@ -2940,7 +3075,7 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
Register result = ToRegister(instr->result());
- __ ldr(result, ContextOperand(cp, instr->qml_global()?Context::QML_GLOBAL_INDEX:Context::GLOBAL_INDEX));
+ __ ldr(result, ContextOperand(cp, Context::GLOBAL_INDEX));
}
@@ -2954,7 +3089,8 @@ void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
- CallKind call_kind) {
+ CallKind call_kind,
+ R1State r1_state) {
bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
function->shared()->formal_parameter_count() == arity;
@@ -2962,7 +3098,10 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
RecordPosition(pointers->position());
if (can_invoke_directly) {
- __ LoadHeapObject(r1, function);
+ if (r1_state == R1_UNINITIALIZED) {
+ __ LoadHeapObject(r1, function);
+ }
+
// Change context if needed.
bool change_context =
(info()->closure()->context() != function->context()) ||
@@ -3001,7 +3140,8 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
CallKnownFunction(instr->function(),
instr->arity(),
instr,
- CALL_AS_METHOD);
+ CALL_AS_METHOD,
+ R1_UNINITIALIZED);
}
@@ -3425,13 +3565,21 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(ToRegister(instr->function()).is(r1));
ASSERT(instr->HasPointerMap());
- ASSERT(instr->HasDeoptimizationEnvironment());
- LPointerMap* pointers = instr->pointer_map();
- RecordPosition(pointers->position());
- SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
- ParameterCount count(instr->arity());
- __ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+
+ if (instr->known_function().is_null()) {
+ LPointerMap* pointers = instr->pointer_map();
+ RecordPosition(pointers->position());
+ SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+ ParameterCount count(instr->arity());
+ __ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
+ __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ } else {
+ CallKnownFunction(instr->known_function(),
+ instr->arity(),
+ instr,
+ CALL_AS_METHOD,
+ R1_CONTAINS_TARGET);
+ }
}
@@ -3486,7 +3634,11 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(r0));
- CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
+ CallKnownFunction(instr->target(),
+ instr->arity(),
+ instr,
+ CALL_AS_FUNCTION,
+ R1_UNINITIALIZED);
}
@@ -3584,10 +3736,16 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
int offset =
- ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
+ (ToInteger32(const_operand) + instr->additional_index()) * kPointerSize
+ + FixedArray::kHeaderSize;
__ str(value, FieldMemOperand(elements, offset));
} else {
__ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
+ if (instr->additional_index() != 0) {
+ __ add(scratch,
+ scratch,
+ Operand(instr->additional_index() << kPointerSizeLog2));
+ }
__ str(value, FieldMemOperand(scratch, FixedArray::kHeaderSize));
}
@@ -3616,7 +3774,6 @@ void LCodeGen::DoStoreKeyedFastDoubleElement(
Register scratch = scratch0();
bool key_is_constant = instr->key()->IsConstantOperand();
int constant_key = 0;
- Label not_nan;
// Calculate the effective address of the slot in the array to store the
// double value.
@@ -3630,7 +3787,7 @@ void LCodeGen::DoStoreKeyedFastDoubleElement(
}
int shift_size = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
Operand operand = key_is_constant
- ? Operand(constant_key * (1 << shift_size) +
+ ? Operand((constant_key << shift_size) +
FixedDoubleArray::kHeaderSize - kHeapObjectTag)
: Operand(key, LSL, shift_size);
__ add(scratch, elements, operand);
@@ -3639,14 +3796,16 @@ void LCodeGen::DoStoreKeyedFastDoubleElement(
Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
}
- // Check for NaN. All NaNs must be canonicalized.
- __ VFPCompareAndSetFlags(value, value);
-
- // Only load canonical NaN if the comparison above set the overflow.
- __ Vmov(value, FixedDoubleArray::canonical_not_the_hole_nan_as_double(), vs);
+ if (instr->NeedsCanonicalization()) {
+ // Check for NaN. All NaNs must be canonicalized.
+ __ VFPCompareAndSetFlags(value, value);
+ // Only load canonical NaN if the comparison above set the overflow.
+ __ Vmov(value,
+ FixedDoubleArray::canonical_not_the_hole_nan_as_double(),
+ vs);
+ }
- __ bind(&not_nan);
- __ vstr(value, scratch, 0);
+ __ vstr(value, scratch, instr->additional_index() << shift_size);
}
@@ -3667,25 +3826,33 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement(
key = ToRegister(instr->key());
}
int shift_size = ElementsKindToShiftSize(elements_kind);
+ int additional_offset = instr->additional_index() << shift_size;
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
CpuFeatures::Scope scope(VFP3);
DwVfpRegister value(ToDoubleRegister(instr->value()));
- Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size))
+ Operand operand(key_is_constant ? Operand(constant_key << shift_size)
: Operand(key, LSL, shift_size));
__ add(scratch0(), external_pointer, operand);
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ vcvt_f32_f64(double_scratch0().low(), value);
- __ vstr(double_scratch0().low(), scratch0(), 0);
+ __ vstr(double_scratch0().low(), scratch0(), additional_offset);
} else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
- __ vstr(value, scratch0(), 0);
+ __ vstr(value, scratch0(), additional_offset);
}
} else {
Register value(ToRegister(instr->value()));
+ if (instr->additional_index() != 0 && !key_is_constant) {
+ __ add(scratch0(), key, Operand(instr->additional_index()));
+ }
MemOperand mem_operand(key_is_constant
- ? MemOperand(external_pointer, constant_key * (1 << shift_size))
- : MemOperand(external_pointer, key, LSL, shift_size));
+ ? MemOperand(external_pointer,
+ ((constant_key + instr->additional_index())
+ << shift_size))
+ : (instr->additional_index() == 0
+ ? MemOperand(external_pointer, key, LSL, shift_size)
+ : MemOperand(external_pointer, scratch0(), LSL, shift_size)));
switch (elements_kind) {
case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_BYTE_ELEMENTS:
@@ -4650,9 +4817,10 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
__ str(r2, FieldMemOperand(result, total_offset + 4));
}
} else if (elements->IsFixedArray()) {
+ Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
for (int i = 0; i < elements_length; i++) {
int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
- Handle<Object> value = JSObject::GetElement(object, i);
+ Handle<Object> value(fast_elements->get(i));
if (value->IsJSObject()) {
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
__ add(r2, result, Operand(*offset));
@@ -4676,6 +4844,23 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
int size = instr->hydrogen()->total_size();
+ ElementsKind boilerplate_elements_kind =
+ instr->hydrogen()->boilerplate()->GetElementsKind();
+
+ // Deopt if the literal boilerplate ElementsKind is of a type different than
+ // the expected one. The check isn't necessary if the boilerplate has already
+ // been converted to FAST_ELEMENTS.
+ if (boilerplate_elements_kind != FAST_ELEMENTS) {
+ __ LoadHeapObject(r1, instr->hydrogen()->boilerplate());
+ // Load map into r2.
+ __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+ // Load the map's "bit field 2".
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
+ // Retrieve elements_kind from bit field 2.
+ __ ubfx(r2, r2, Map::kElementsKindShift, Map::kElementsKindBitCount);
+ __ cmp(r2, Operand(boilerplate_elements_kind));
+ DeoptimizeIf(ne, instr->environment());
+ }
// Allocate all objects that are part of the literal in one big
// allocation. This avoids multiple limit checks.
@@ -4971,7 +5156,7 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
Register strict = scratch0();
__ mov(strict, Operand(Smi::FromInt(strict_mode_flag())));
__ Push(object, key, strict);
- ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ ASSERT(instr->HasPointerMap());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator safepoint_generator(
@@ -4984,7 +5169,7 @@ void LCodeGen::DoIn(LIn* instr) {
Register obj = ToRegister(instr->object());
Register key = ToRegister(instr->key());
__ Push(key, obj);
- ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ ASSERT(instr->HasPointerMap());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt);
diff --git a/src/3rdparty/v8/src/arm/lithium-codegen-arm.h b/src/3rdparty/v8/src/arm/lithium-codegen-arm.h
index adb6e1b..c6a3af7 100644
--- a/src/3rdparty/v8/src/arm/lithium-codegen-arm.h
+++ b/src/3rdparty/v8/src/arm/lithium-codegen-arm.h
@@ -215,12 +215,18 @@ class LCodeGen BASE_EMBEDDED {
int argc,
LInstruction* instr);
+ enum R1State {
+ R1_UNINITIALIZED,
+ R1_CONTAINS_TARGET
+ };
+
// Generate a direct call to a known function. Expects the function
// to be in r1.
void CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
- CallKind call_kind);
+ CallKind call_kind,
+ R1State r1_state);
void LoadHeapObject(Register result, Handle<HeapObject> object);
@@ -317,6 +323,17 @@ class LCodeGen BASE_EMBEDDED {
Register source,
int* offset);
+ // Emit optimized code for integer division.
+ // Inputs are signed.
+ // All registers are clobbered.
+ // If 'remainder' is no_reg, it is not computed.
+ void EmitSignedIntegerDivisionByConstant(Register result,
+ Register dividend,
+ int32_t divisor,
+ Register remainder,
+ Register scratch,
+ LEnvironment* environment);
+
struct JumpTableEntry {
explicit inline JumpTableEntry(Address entry)
: label(),
diff --git a/src/3rdparty/v8/src/arm/macro-assembler-arm.cc b/src/3rdparty/v8/src/arm/macro-assembler-arm.cc
index 857c2bf..4da2fec 100644
--- a/src/3rdparty/v8/src/arm/macro-assembler-arm.cc
+++ b/src/3rdparty/v8/src/arm/macro-assembler-arm.cc
@@ -3710,22 +3710,35 @@ void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
}
-bool AreAliased(Register r1, Register r2, Register r3, Register r4) {
- if (r1.is(r2)) return true;
- if (r1.is(r3)) return true;
- if (r1.is(r4)) return true;
- if (r2.is(r3)) return true;
- if (r2.is(r4)) return true;
- if (r3.is(r4)) return true;
- return false;
+#ifdef DEBUG
+bool AreAliased(Register reg1,
+ Register reg2,
+ Register reg3,
+ Register reg4,
+ Register reg5,
+ Register reg6) {
+ int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() +
+ reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid();
+
+ RegList regs = 0;
+ if (reg1.is_valid()) regs |= reg1.bit();
+ if (reg2.is_valid()) regs |= reg2.bit();
+ if (reg3.is_valid()) regs |= reg3.bit();
+ if (reg4.is_valid()) regs |= reg4.bit();
+ if (reg5.is_valid()) regs |= reg5.bit();
+ if (reg6.is_valid()) regs |= reg6.bit();
+ int n_of_non_aliasing_regs = NumRegs(regs);
+
+ return n_of_valid_regs != n_of_non_aliasing_regs;
}
+#endif
CodePatcher::CodePatcher(byte* address, int instructions)
: address_(address),
instructions_(instructions),
size_(instructions * Assembler::kInstrSize),
- masm_(Isolate::Current(), address, size_ + Assembler::kGap) {
+ masm_(NULL, address, size_ + Assembler::kGap) {
// Create a new macro assembler pointing to the address of the code to patch.
// The size is adjusted with kGap on order for the assembler to generate size
// bytes of instructions without failing with buffer size constraints.
diff --git a/src/3rdparty/v8/src/arm/macro-assembler-arm.h b/src/3rdparty/v8/src/arm/macro-assembler-arm.h
index 751a81c..360f4c1 100644
--- a/src/3rdparty/v8/src/arm/macro-assembler-arm.h
+++ b/src/3rdparty/v8/src/arm/macro-assembler-arm.h
@@ -85,7 +85,14 @@ enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved };
-bool AreAliased(Register r1, Register r2, Register r3, Register r4);
+#ifdef DEBUG
+bool AreAliased(Register reg1,
+ Register reg2,
+ Register reg3 = no_reg,
+ Register reg4 = no_reg,
+ Register reg5 = no_reg,
+ Register reg6 = no_reg);
+#endif
// MacroAssembler implements a collection of frequently used macros.
@@ -1321,7 +1328,6 @@ class MacroAssembler: public Assembler {
};
-#ifdef ENABLE_DEBUGGER_SUPPORT
// The code patcher is used to patch (typically) small parts of code e.g. for
// debugging and other types of instrumentation. When using the code patcher
// the exact number of bytes specified must be emitted. It is not legal to emit
@@ -1351,7 +1357,6 @@ class CodePatcher {
int size_; // Number of bytes of the expected patch size.
MacroAssembler masm_; // Macro assembler used to generate the code.
};
-#endif // ENABLE_DEBUGGER_SUPPORT
// -----------------------------------------------------------------------------
@@ -1367,11 +1372,6 @@ inline MemOperand GlobalObjectOperand() {
}
-static inline MemOperand QmlGlobalObjectOperand() {
- return ContextOperand(cp, Context::QML_GLOBAL_INDEX);
-}
-
-
#ifdef GENERATED_CODE_COVERAGE
#define CODE_COVERAGE_STRINGIFY(x) #x
#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
diff --git a/src/3rdparty/v8/src/arm/stub-cache-arm.cc b/src/3rdparty/v8/src/arm/stub-cache-arm.cc
index cfd93bc..49c0982 100644
--- a/src/3rdparty/v8/src/arm/stub-cache-arm.cc
+++ b/src/3rdparty/v8/src/arm/stub-cache-arm.cc
@@ -443,8 +443,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Label exit;
// Check that the map of the object hasn't changed.
+ CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
+ : REQUIRE_EXACT_MAP;
__ CheckMap(receiver_reg, scratch, Handle<Map>(object->map()), miss_label,
- DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ DO_SMI_CHECK, mode);
// Perform global security token check if needed.
if (object->IsJSGlobalProxy()) {
@@ -580,6 +582,8 @@ static void PushInterceptorArguments(MacroAssembler* masm,
__ push(holder);
__ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
__ push(scratch);
+ __ mov(scratch, Operand(ExternalReference::isolate_address()));
+ __ push(scratch);
}
@@ -594,7 +598,7 @@ static void CompileCallLoadPropertyWithInterceptor(
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
masm->isolate());
- __ mov(r0, Operand(5));
+ __ mov(r0, Operand(6));
__ mov(r1, Operand(ref));
CEntryStub stub(1);
@@ -602,9 +606,9 @@ static void CompileCallLoadPropertyWithInterceptor(
}
-static const int kFastApiCallArguments = 3;
+static const int kFastApiCallArguments = 4;
-// Reserves space for the extra arguments to FastHandleApiCall in the
+// Reserves space for the extra arguments to API function in the
// caller's frame.
//
// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
@@ -630,7 +634,8 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
// -- sp[0] : holder (set by CheckPrototypes)
// -- sp[4] : callee JS function
// -- sp[8] : call data
- // -- sp[12] : last JS argument
+ // -- sp[12] : isolate
+ // -- sp[16] : last JS argument
// -- ...
// -- sp[(argc + 3) * 4] : first JS argument
// -- sp[(argc + 4) * 4] : receiver
@@ -640,7 +645,7 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
__ LoadHeapObject(r5, function);
__ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset));
- // Pass the additional arguments FastHandleApiCall expects.
+ // Pass the additional arguments.
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Handle<Object> call_data(api_call_info->data());
if (masm->isolate()->heap()->InNewSpace(*call_data)) {
@@ -649,13 +654,15 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
} else {
__ Move(r6, call_data);
}
- // Store JS function and call data.
- __ stm(ib, sp, r5.bit() | r6.bit());
+ __ mov(r7, Operand(ExternalReference::isolate_address()));
+ // Store JS function, call data and isolate.
+ __ stm(ib, sp, r5.bit() | r6.bit() | r7.bit());
- // r2 points to call data as expected by Arguments
- // (refer to layout above).
- __ add(r2, sp, Operand(2 * kPointerSize));
+ // Prepare arguments.
+ __ add(r2, sp, Operand(3 * kPointerSize));
+ // Allocate the v8::Arguments structure in the arguments' space since
+ // it's not controlled by GC.
const int kApiStackSpace = 4;
FrameScope frame_scope(masm, StackFrame::MANUAL);
@@ -664,9 +671,9 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
// r0 = v8::Arguments&
// Arguments is after the return address.
__ add(r0, sp, Operand(1 * kPointerSize));
- // v8::Arguments::implicit_args = data
+ // v8::Arguments::implicit_args_
__ str(r2, MemOperand(r0, 0 * kPointerSize));
- // v8::Arguments::values = last argument
+ // v8::Arguments::values_
__ add(ip, r2, Operand(argc * kPointerSize));
__ str(ip, MemOperand(r0, 1 * kPointerSize));
// v8::Arguments::length_ = argc
@@ -843,7 +850,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
__ CallExternalReference(
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
masm->isolate()),
- 5);
+ 6);
// Restore the name_ register.
__ pop(name_);
// Leave the internal frame.
@@ -1202,7 +1209,9 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
} else {
__ Move(scratch3, Handle<Object>(callback->data()));
}
- __ Push(reg, scratch3, name_reg);
+ __ Push(reg, scratch3);
+ __ mov(scratch3, Operand(ExternalReference::isolate_address()));
+ __ Push(scratch3, name_reg);
__ mov(r0, sp); // r0 = Handle<String>
const int kApiStackSpace = 1;
@@ -1214,7 +1223,7 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
__ str(scratch2, MemOperand(sp, 1 * kPointerSize));
__ add(r1, sp, Operand(1 * kPointerSize)); // r1 = AccessorInfo&
- const int kStackUnwindSpace = 4;
+ const int kStackUnwindSpace = 5;
Address getter_address = v8::ToCData<Address>(callback->getter());
ApiFunction fun(getter_address);
ExternalReference ref =
@@ -1264,12 +1273,19 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
name, miss);
ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
+ // Preserve the receiver register explicitly whenever it is different from
+ // the holder and it is needed should the interceptor return without any
+ // result. The CALLBACKS case needs the receiver to be passed into C++ code,
+ // the FIELD case might cause a miss during the prototype check.
+ bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
+ bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
+ (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
+
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
{
FrameScope frame_scope(masm(), StackFrame::INTERNAL);
- if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
- // CALLBACKS case needs a receiver to be passed into C++ callback.
+ if (must_preserve_receiver_reg) {
__ Push(receiver, holder_reg, name_reg);
} else {
__ Push(holder_reg, name_reg);
@@ -1294,14 +1310,14 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
__ bind(&interceptor_failed);
__ pop(name_reg);
__ pop(holder_reg);
- if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
+ if (must_preserve_receiver_reg) {
__ pop(receiver);
}
// Leave the internal frame.
}
// Check that the maps from interceptor's holder to lookup's holder
// haven't changed. And load lookup's holder into |holder| register.
- if (*interceptor_holder != lookup->holder()) {
+ if (must_perfrom_prototype_check) {
holder_reg = CheckPrototypes(interceptor_holder,
holder_reg,
Handle<JSObject>(lookup->holder()),
@@ -1335,20 +1351,19 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
if (!receiver.is(holder_reg)) {
ASSERT(scratch1.is(holder_reg));
__ Push(receiver, holder_reg);
- __ ldr(scratch3,
- FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
- __ Push(scratch3, scratch2, name_reg);
} else {
__ push(receiver);
- __ ldr(scratch3,
- FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
- __ Push(holder_reg, scratch3, scratch2, name_reg);
+ __ push(holder_reg);
}
+ __ ldr(scratch3,
+ FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
+ __ mov(scratch1, Operand(ExternalReference::isolate_address()));
+ __ Push(scratch3, scratch1, scratch2, name_reg);
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
masm()->isolate());
- __ TailCallExternalReference(ref, 5, 1);
+ __ TailCallExternalReference(ref, 6, 1);
}
} else { // !compile_followup_inline
// Call the runtime system to load the interceptor.
@@ -1362,7 +1377,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
masm()->isolate());
- __ TailCallExternalReference(ref, 5, 1);
+ __ TailCallExternalReference(ref, 6, 1);
}
}
@@ -3368,6 +3383,44 @@ static bool IsElementTypeSigned(ElementsKind elements_kind) {
}
+static void GenerateSmiKeyCheck(MacroAssembler* masm,
+ Register key,
+ Register scratch0,
+ Register scratch1,
+ DwVfpRegister double_scratch0,
+ Label* fail) {
+ if (CpuFeatures::IsSupported(VFP3)) {
+ CpuFeatures::Scope scope(VFP3);
+ Label key_ok;
+ // Check for smi or a smi inside a heap number. We convert the heap
+ // number and check if the conversion is exact and fits into the smi
+ // range.
+ __ JumpIfSmi(key, &key_ok);
+ __ CheckMap(key,
+ scratch0,
+ Heap::kHeapNumberMapRootIndex,
+ fail,
+ DONT_DO_SMI_CHECK);
+ __ sub(ip, key, Operand(kHeapObjectTag));
+ __ vldr(double_scratch0, ip, HeapNumber::kValueOffset);
+ __ EmitVFPTruncate(kRoundToZero,
+ double_scratch0.low(),
+ double_scratch0,
+ scratch0,
+ scratch1,
+ kCheckForInexactConversion);
+ __ b(ne, fail);
+ __ vmov(scratch0, double_scratch0.low());
+ __ TrySmiTag(scratch0, fail, scratch1);
+ __ mov(key, scratch0);
+ __ bind(&key_ok);
+ } else {
+ // Check that the key is a smi.
+ __ JumpIfNotSmi(key, fail);
+ }
+}
+
+
void KeyedLoadStubCompiler::GenerateLoadExternalArray(
MacroAssembler* masm,
ElementsKind elements_kind) {
@@ -3384,8 +3437,8 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, key, r4, r5, d1, &miss_force_generic);
__ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// r3: elements array
@@ -3715,8 +3768,8 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, key, r4, r5, d1, &miss_force_generic);
__ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
@@ -4041,8 +4094,8 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(r0, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, r0, r4, r5, d1, &miss_force_generic);
// Get the elements array.
__ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
@@ -4093,8 +4146,8 @@ void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(key_reg, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, &miss_force_generic);
// Get the elements array.
__ ldr(elements_reg,
@@ -4169,8 +4222,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(key_reg, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, &miss_force_generic);
if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
__ JumpIfNotSmi(value_reg, &transition_elements_kind);
@@ -4336,7 +4389,9 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- __ JumpIfNotSmi(key_reg, &miss_force_generic);
+
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, &miss_force_generic);
__ ldr(elements_reg,
FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
@@ -4427,6 +4482,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
// Increment the length of the array.
__ mov(length_reg, Operand(Smi::FromInt(1)));
__ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
+ __ ldr(elements_reg,
+ FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
__ jmp(&finish_store);
__ bind(&check_capacity);
diff --git a/src/3rdparty/v8/src/array.js b/src/3rdparty/v8/src/array.js
index daa75d5..a1cc5b6 100644
--- a/src/3rdparty/v8/src/array.js
+++ b/src/3rdparty/v8/src/array.js
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -465,15 +465,19 @@ function ArrayPush() {
}
+// Returns an array containing the array elements of the object followed
+// by the array elements of each argument in order. See ECMA-262,
+// section 15.4.4.7.
function ArrayConcat(arg1) { // length == 1
if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
throw MakeTypeError("called_on_null_or_undefined",
["Array.prototype.concat"]);
}
+ var array = ToObject(this);
var arg_count = %_ArgumentsLength();
var arrays = new InternalArray(1 + arg_count);
- arrays[0] = this;
+ arrays[0] = array;
for (var i = 0; i < arg_count; i++) {
arrays[i + 1] = %_Arguments(i);
}
@@ -823,7 +827,8 @@ function ArraySort(comparefn) {
var element = a[i];
var order = %_CallFunction(receiver, element, pivot, comparefn);
if (order < 0) {
- %_SwapElements(a, i, low_end);
+ a[i] = a[low_end];
+ a[low_end] = element;
low_end++;
} else if (order > 0) {
do {
@@ -832,9 +837,12 @@ function ArraySort(comparefn) {
var top_elem = a[high_start];
order = %_CallFunction(receiver, top_elem, pivot, comparefn);
} while (order > 0);
- %_SwapElements(a, i, high_start);
+ a[i] = a[high_start];
+ a[high_start] = element;
if (order < 0) {
- %_SwapElements(a, i, low_end);
+ element = a[i];
+ a[i] = a[low_end];
+ a[low_end] = element;
low_end++;
}
}
@@ -1023,13 +1031,28 @@ function ArrayFilter(f, receiver) {
var result = new $Array();
var accumulator = new InternalArray();
var accumulator_length = 0;
- for (var i = 0; i < length; i++) {
- if (i in array) {
- var element = array[i];
- if (%_CallFunction(receiver, element, i, array, f)) {
- accumulator[accumulator_length++] = element;
+ if (%DebugCallbackSupportsStepping(f)) {
+ for (var i = 0; i < length; i++) {
+ if (i in array) {
+ var element = array[i];
+ // Prepare break slots for debugger step in.
+ %DebugPrepareStepInIfStepping(f);
+ if (%_CallFunction(receiver, element, i, array, f)) {
+ accumulator[accumulator_length++] = element;
+ }
+ }
+ }
+ } else {
+ // This is a duplicate of the previous loop sans debug stepping.
+ for (var i = 0; i < length; i++) {
+ if (i in array) {
+ var element = array[i];
+ if (%_CallFunction(receiver, element, i, array, f)) {
+ accumulator[accumulator_length++] = element;
+ }
}
}
+ // End of duplicate.
}
%MoveArrayContents(accumulator, result);
return result;
@@ -1055,12 +1078,24 @@ function ArrayForEach(f, receiver) {
} else if (!IS_SPEC_OBJECT(receiver)) {
receiver = ToObject(receiver);
}
-
- for (var i = 0; i < length; i++) {
- if (i in array) {
- var element = array[i];
- %_CallFunction(receiver, element, i, array, f);
+ if (%DebugCallbackSupportsStepping(f)) {
+ for (var i = 0; i < length; i++) {
+ if (i in array) {
+ var element = array[i];
+ // Prepare break slots for debugger step in.
+ %DebugPrepareStepInIfStepping(f);
+ %_CallFunction(receiver, element, i, array, f);
+ }
}
+ } else {
+ // This is a duplicate of the previous loop sans debug stepping.
+ for (var i = 0; i < length; i++) {
+ if (i in array) {
+ var element = array[i];
+ %_CallFunction(receiver, element, i, array, f);
+ }
+ }
+ // End of duplicate.
}
}
@@ -1087,11 +1122,24 @@ function ArraySome(f, receiver) {
receiver = ToObject(receiver);
}
- for (var i = 0; i < length; i++) {
- if (i in array) {
- var element = array[i];
- if (%_CallFunction(receiver, element, i, array, f)) return true;
+ if (%DebugCallbackSupportsStepping(f)) {
+ for (var i = 0; i < length; i++) {
+ if (i in array) {
+ var element = array[i];
+ // Prepare break slots for debugger step in.
+ %DebugPrepareStepInIfStepping(f);
+ if (%_CallFunction(receiver, element, i, array, f)) return true;
+ }
+ }
+ } else {
+ // This is a duplicate of the previous loop sans debug stepping.
+ for (var i = 0; i < length; i++) {
+ if (i in array) {
+ var element = array[i];
+ if (%_CallFunction(receiver, element, i, array, f)) return true;
+ }
}
+ // End of duplicate.
}
return false;
}
@@ -1117,11 +1165,24 @@ function ArrayEvery(f, receiver) {
receiver = ToObject(receiver);
}
- for (var i = 0; i < length; i++) {
- if (i in array) {
- var element = array[i];
- if (!%_CallFunction(receiver, element, i, array, f)) return false;
+ if (%DebugCallbackSupportsStepping(f)) {
+ for (var i = 0; i < length; i++) {
+ if (i in array) {
+ var element = array[i];
+ // Prepare break slots for debugger step in.
+ %DebugPrepareStepInIfStepping(f);
+ if (!%_CallFunction(receiver, element, i, array, f)) return false;
+ }
+ }
+ } else {
+ // This is a duplicate of the previous loop sans debug stepping.
+ for (var i = 0; i < length; i++) {
+ if (i in array) {
+ var element = array[i];
+ if (!%_CallFunction(receiver, element, i, array, f)) return false;
+ }
}
+ // End of duplicate.
}
return true;
}
@@ -1148,11 +1209,24 @@ function ArrayMap(f, receiver) {
var result = new $Array();
var accumulator = new InternalArray(length);
- for (var i = 0; i < length; i++) {
- if (i in array) {
- var element = array[i];
- accumulator[i] = %_CallFunction(receiver, element, i, array, f);
+ if (%DebugCallbackSupportsStepping(f)) {
+ for (var i = 0; i < length; i++) {
+ if (i in array) {
+ var element = array[i];
+ // Prepare break slots for debugger step in.
+ %DebugPrepareStepInIfStepping(f);
+ accumulator[i] = %_CallFunction(receiver, element, i, array, f);
+ }
}
+ } else {
+ // This is a duplicate of the previous loop sans debug stepping.
+ for (var i = 0; i < length; i++) {
+ if (i in array) {
+ var element = array[i];
+ accumulator[i] = %_CallFunction(receiver, element, i, array, f);
+ }
+ }
+ // End of duplicate.
}
%MoveArrayContents(accumulator, result);
return result;
@@ -1307,11 +1381,27 @@ function ArrayReduce(callback, current) {
}
var receiver = %GetDefaultReceiver(callback);
- for (; i < length; i++) {
- if (i in array) {
- var element = array[i];
- current = %_CallFunction(receiver, current, element, i, array, callback);
+
+ if (%DebugCallbackSupportsStepping(callback)) {
+ for (; i < length; i++) {
+ if (i in array) {
+ var element = array[i];
+ // Prepare break slots for debugger step in.
+ %DebugPrepareStepInIfStepping(callback);
+ current =
+ %_CallFunction(receiver, current, element, i, array, callback);
+ }
+ }
+ } else {
+ // This is a duplicate of the previous loop sans debug stepping.
+ for (; i < length; i++) {
+ if (i in array) {
+ var element = array[i];
+ current =
+ %_CallFunction(receiver, current, element, i, array, callback);
+ }
}
+ // End of duplicate.
}
return current;
}
@@ -1344,11 +1434,27 @@ function ArrayReduceRight(callback, current) {
}
var receiver = %GetDefaultReceiver(callback);
- for (; i >= 0; i--) {
- if (i in array) {
- var element = array[i];
- current = %_CallFunction(receiver, current, element, i, array, callback);
+
+ if (%DebugCallbackSupportsStepping(callback)) {
+ for (; i >= 0; i--) {
+ if (i in array) {
+ var element = array[i];
+ // Prepare break slots for debugger step in.
+ %DebugPrepareStepInIfStepping(callback);
+ current =
+ %_CallFunction(receiver, current, element, i, array, callback);
+ }
+ }
+ } else {
+ // This is a duplicate of the previous loop sans debug stepping.
+ for (; i >= 0; i--) {
+ if (i in array) {
+ var element = array[i];
+ current =
+ %_CallFunction(receiver, current, element, i, array, callback);
+ }
}
+ // End of duplicate.
}
return current;
}
diff --git a/src/3rdparty/v8/src/assembler.h b/src/3rdparty/v8/src/assembler.h
index 6deca26..05fe320 100644
--- a/src/3rdparty/v8/src/assembler.h
+++ b/src/3rdparty/v8/src/assembler.h
@@ -62,6 +62,10 @@ class AssemblerBase: public Malloced {
Isolate* isolate() const { return isolate_; }
int jit_cookie() { return jit_cookie_; }
+ // Overwrite a host NaN with a quiet target NaN. Used by mksnapshot for
+ // cross-snapshotting.
+ static void QuietNaN(HeapObject* nan) { }
+
private:
Isolate* isolate_;
int jit_cookie_;
diff --git a/src/3rdparty/v8/src/ast.cc b/src/3rdparty/v8/src/ast.cc
index 71bec1a..6f9fd7a 100644
--- a/src/3rdparty/v8/src/ast.cc
+++ b/src/3rdparty/v8/src/ast.cc
@@ -171,11 +171,6 @@ LanguageMode FunctionLiteral::language_mode() const {
}
-QmlModeFlag FunctionLiteral::qml_mode_flag() const {
- return scope()->qml_mode_flag();
-}
-
-
ObjectLiteral::Property::Property(Literal* key,
Expression* value,
Isolate* isolate) {
@@ -554,11 +549,6 @@ void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle,
is_monomorphic_ = oracle->CallIsMonomorphic(this);
Property* property = expression()->AsProperty();
if (property == NULL) {
- if (VariableProxy *proxy = expression()->AsVariableProxy()) {
- if (proxy->var()->is_qml_global())
- return;
- }
-
// Function call. Specialize for monomorphic calls.
if (is_monomorphic_) target_ = oracle->GetCallTarget(this);
} else {
@@ -972,6 +962,14 @@ RegExpDisjunction::RegExpDisjunction(ZoneList<RegExpTree*>* alternatives)
}
+static int IncreaseBy(int previous, int increase) {
+ if (RegExpTree::kInfinity - previous < increase) {
+ return RegExpTree::kInfinity;
+ } else {
+ return previous + increase;
+ }
+}
+
RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes)
: nodes_(nodes) {
ASSERT(nodes->length() > 1);
@@ -979,13 +977,10 @@ RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes)
max_match_ = 0;
for (int i = 0; i < nodes->length(); i++) {
RegExpTree* node = nodes->at(i);
- min_match_ += node->min_match();
+ int node_min_match = node->min_match();
+ min_match_ = IncreaseBy(min_match_, node_min_match);
int node_max_match = node->max_match();
- if (kInfinity - max_match_ < node_max_match) {
- max_match_ = kInfinity;
- } else {
- max_match_ += node->max_match();
- }
+ max_match_ = IncreaseBy(max_match_, node_max_match);
}
}
@@ -1003,138 +998,78 @@ CaseClause::CaseClause(Isolate* isolate,
}
-#define INCREASE_NODE_COUNT(NodeType) \
+#define REGULAR_NODE(NodeType) \
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
increase_node_count(); \
}
+#define DONT_OPTIMIZE_NODE(NodeType) \
+ void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
+ increase_node_count(); \
+ add_flag(kDontOptimize); \
+ add_flag(kDontInline); \
+ add_flag(kDontSelfOptimize); \
+ }
+#define DONT_INLINE_NODE(NodeType) \
+ void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
+ increase_node_count(); \
+ add_flag(kDontInline); \
+ }
+#define DONT_SELFOPTIMIZE_NODE(NodeType) \
+ void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
+ increase_node_count(); \
+ add_flag(kDontSelfOptimize); \
+ }
-INCREASE_NODE_COUNT(VariableDeclaration)
-INCREASE_NODE_COUNT(FunctionDeclaration)
-INCREASE_NODE_COUNT(ModuleDeclaration)
-INCREASE_NODE_COUNT(ImportDeclaration)
-INCREASE_NODE_COUNT(ExportDeclaration)
-INCREASE_NODE_COUNT(ModuleLiteral)
-INCREASE_NODE_COUNT(ModuleVariable)
-INCREASE_NODE_COUNT(ModulePath)
-INCREASE_NODE_COUNT(ModuleUrl)
-INCREASE_NODE_COUNT(Block)
-INCREASE_NODE_COUNT(ExpressionStatement)
-INCREASE_NODE_COUNT(EmptyStatement)
-INCREASE_NODE_COUNT(IfStatement)
-INCREASE_NODE_COUNT(ContinueStatement)
-INCREASE_NODE_COUNT(BreakStatement)
-INCREASE_NODE_COUNT(ReturnStatement)
-INCREASE_NODE_COUNT(Conditional)
-INCREASE_NODE_COUNT(Literal)
-INCREASE_NODE_COUNT(ObjectLiteral)
-INCREASE_NODE_COUNT(Assignment)
-INCREASE_NODE_COUNT(Throw)
-INCREASE_NODE_COUNT(Property)
-INCREASE_NODE_COUNT(UnaryOperation)
-INCREASE_NODE_COUNT(CountOperation)
-INCREASE_NODE_COUNT(BinaryOperation)
-INCREASE_NODE_COUNT(CompareOperation)
-INCREASE_NODE_COUNT(ThisFunction)
-INCREASE_NODE_COUNT(Call)
-INCREASE_NODE_COUNT(CallNew)
-
-#undef INCREASE_NODE_COUNT
-
-
-void AstConstructionVisitor::VisitWithStatement(WithStatement* node) {
- increase_node_count();
- add_flag(kDontOptimize);
- add_flag(kDontInline);
-}
-
-
-void AstConstructionVisitor::VisitSwitchStatement(SwitchStatement* node) {
- increase_node_count();
- add_flag(kDontInline);
-}
-
-
-void AstConstructionVisitor::VisitDoWhileStatement(DoWhileStatement* node) {
- increase_node_count();
- add_flag(kDontSelfOptimize);
-}
-
-
-void AstConstructionVisitor::VisitWhileStatement(WhileStatement* node) {
- increase_node_count();
- add_flag(kDontSelfOptimize);
-}
-
-
-void AstConstructionVisitor::VisitForStatement(ForStatement* node) {
- increase_node_count();
- add_flag(kDontSelfOptimize);
-}
-
-
-void AstConstructionVisitor::VisitForInStatement(ForInStatement* node) {
- increase_node_count();
- add_flag(kDontSelfOptimize);
-}
-
-
-void AstConstructionVisitor::VisitTryCatchStatement(TryCatchStatement* node) {
- increase_node_count();
- add_flag(kDontOptimize);
- add_flag(kDontInline);
-}
-
-
-void AstConstructionVisitor::VisitTryFinallyStatement(
- TryFinallyStatement* node) {
- increase_node_count();
- add_flag(kDontOptimize);
- add_flag(kDontInline);
-}
-
-
-void AstConstructionVisitor::VisitDebuggerStatement(DebuggerStatement* node) {
- increase_node_count();
- add_flag(kDontOptimize);
- add_flag(kDontInline);
-}
-
-
-void AstConstructionVisitor::VisitFunctionLiteral(FunctionLiteral* node) {
- increase_node_count();
- add_flag(kDontInline);
-}
-
-
-void AstConstructionVisitor::VisitSharedFunctionInfoLiteral(
- SharedFunctionInfoLiteral* node) {
- increase_node_count();
- add_flag(kDontOptimize);
- add_flag(kDontInline);
-}
-
-
-void AstConstructionVisitor::VisitVariableProxy(VariableProxy* node) {
- increase_node_count();
- // In theory, we'd have to add:
- // if(node->var()->IsLookupSlot()) { add_flag(kDontInline); }
- // However, node->var() is usually not bound yet at VariableProxy creation
- // time, and LOOKUP variables only result from constructs that cannot
- // be inlined anyway.
-}
-
-
-void AstConstructionVisitor::VisitRegExpLiteral(RegExpLiteral* node) {
- increase_node_count();
- add_flag(kDontInline); // TODO(1322): Allow materialized literals.
-}
-
-
-void AstConstructionVisitor::VisitArrayLiteral(ArrayLiteral* node) {
- increase_node_count();
- add_flag(kDontInline); // TODO(1322): Allow materialized literals.
-}
-
+REGULAR_NODE(VariableDeclaration)
+REGULAR_NODE(FunctionDeclaration)
+REGULAR_NODE(Block)
+REGULAR_NODE(ExpressionStatement)
+REGULAR_NODE(EmptyStatement)
+REGULAR_NODE(IfStatement)
+REGULAR_NODE(ContinueStatement)
+REGULAR_NODE(BreakStatement)
+REGULAR_NODE(ReturnStatement)
+REGULAR_NODE(SwitchStatement)
+REGULAR_NODE(Conditional)
+REGULAR_NODE(Literal)
+REGULAR_NODE(ObjectLiteral)
+REGULAR_NODE(Assignment)
+REGULAR_NODE(Throw)
+REGULAR_NODE(Property)
+REGULAR_NODE(UnaryOperation)
+REGULAR_NODE(CountOperation)
+REGULAR_NODE(BinaryOperation)
+REGULAR_NODE(CompareOperation)
+REGULAR_NODE(ThisFunction)
+REGULAR_NODE(Call)
+REGULAR_NODE(CallNew)
+// In theory, for VariableProxy we'd have to add:
+// if (node->var()->IsLookupSlot()) add_flag(kDontInline);
+// But node->var() is usually not bound yet at VariableProxy creation time, and
+// LOOKUP variables only result from constructs that cannot be inlined anyway.
+REGULAR_NODE(VariableProxy)
+
+DONT_OPTIMIZE_NODE(ModuleDeclaration)
+DONT_OPTIMIZE_NODE(ImportDeclaration)
+DONT_OPTIMIZE_NODE(ExportDeclaration)
+DONT_OPTIMIZE_NODE(ModuleLiteral)
+DONT_OPTIMIZE_NODE(ModuleVariable)
+DONT_OPTIMIZE_NODE(ModulePath)
+DONT_OPTIMIZE_NODE(ModuleUrl)
+DONT_OPTIMIZE_NODE(WithStatement)
+DONT_OPTIMIZE_NODE(TryCatchStatement)
+DONT_OPTIMIZE_NODE(TryFinallyStatement)
+DONT_OPTIMIZE_NODE(DebuggerStatement)
+DONT_OPTIMIZE_NODE(SharedFunctionInfoLiteral)
+
+DONT_INLINE_NODE(FunctionLiteral)
+DONT_INLINE_NODE(RegExpLiteral) // TODO(1322): Allow materialized literals.
+DONT_INLINE_NODE(ArrayLiteral) // TODO(1322): Allow materialized literals.
+
+DONT_SELFOPTIMIZE_NODE(DoWhileStatement)
+DONT_SELFOPTIMIZE_NODE(WhileStatement)
+DONT_SELFOPTIMIZE_NODE(ForStatement)
+DONT_SELFOPTIMIZE_NODE(ForInStatement)
void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
increase_node_count();
@@ -1152,6 +1087,11 @@ void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
}
}
+#undef REGULAR_NODE
+#undef DONT_OPTIMIZE_NODE
+#undef DONT_INLINE_NODE
+#undef DONT_SELFOPTIMIZE_NODE
+
Handle<String> Literal::ToString() {
if (handle_->IsString()) return Handle<String>::cast(handle_);
diff --git a/src/3rdparty/v8/src/ast.h b/src/3rdparty/v8/src/ast.h
index 6b85b7c..dad8057 100644
--- a/src/3rdparty/v8/src/ast.h
+++ b/src/3rdparty/v8/src/ast.h
@@ -421,8 +421,8 @@ class Block: public BreakableStatement {
ZoneList<Statement*>* statements() { return &statements_; }
bool is_initializer_block() const { return is_initializer_block_; }
- Scope* block_scope() const { return block_scope_; }
- void set_block_scope(Scope* block_scope) { block_scope_ = block_scope; }
+ Scope* scope() const { return scope_; }
+ void set_scope(Scope* scope) { scope_ = scope; }
protected:
template<class> friend class AstNodeFactory;
@@ -434,13 +434,13 @@ class Block: public BreakableStatement {
: BreakableStatement(isolate, labels, TARGET_FOR_NAMED_ONLY),
statements_(capacity),
is_initializer_block_(is_initializer_block),
- block_scope_(NULL) {
+ scope_(NULL) {
}
private:
ZoneList<Statement*> statements_;
bool is_initializer_block_;
- Scope* block_scope_;
+ Scope* scope_;
};
@@ -608,6 +608,7 @@ class ModuleLiteral: public Module {
DECLARE_NODE_TYPE(ModuleLiteral)
Block* body() const { return body_; }
+ Handle<Context> context() const { return context_; }
protected:
template<class> friend class AstNodeFactory;
@@ -619,6 +620,7 @@ class ModuleLiteral: public Module {
private:
Block* body_;
+ Handle<Context> context_;
};
@@ -2045,8 +2047,6 @@ class FunctionLiteral: public Expression {
bool is_anonymous() const { return IsAnonymous::decode(bitfield_); }
bool is_classic_mode() const { return language_mode() == CLASSIC_MODE; }
LanguageMode language_mode() const;
- bool qml_mode() const { return qml_mode_flag() == kQmlMode; }
- QmlModeFlag qml_mode_flag() const;
int materialized_literal_count() { return materialized_literal_count_; }
int expected_property_count() { return expected_property_count_; }
diff --git a/src/3rdparty/v8/src/atomicops.h b/src/3rdparty/v8/src/atomicops.h
index 55de87c..e2057ed 100644
--- a/src/3rdparty/v8/src/atomicops.h
+++ b/src/3rdparty/v8/src/atomicops.h
@@ -157,16 +157,7 @@ Atomic64 Release_Load(volatile const Atomic64* ptr);
(defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64))
#include "atomicops_internals_x86_gcc.h"
#elif defined(__GNUC__) && defined(V8_HOST_ARCH_ARM)
- // We need special handling for QNX as the existing code in
- // atomicops_internals_arm_gcc.h is actually Linux-specific. This is due to
- // it using a magic hard-wired function address for LinuxKernelCmpxchgFunc.
- // The QNX implementation uses the equivalent system call for that platform
- // but is not source compatible.
- #if defined(__QNXNTO__)
- #include "atomicops_internals_arm_qnx.h"
- #else
- #include "atomicops_internals_arm_gcc.h"
- #endif
+#include "atomicops_internals_arm_gcc.h"
#elif defined(__GNUC__) && defined(V8_HOST_ARCH_MIPS)
#include "atomicops_internals_mips_gcc.h"
#else
diff --git a/src/3rdparty/v8/src/atomicops_internals_arm_qnx.h b/src/3rdparty/v8/src/atomicops_internals_arm_qnx.h
deleted file mode 100644
index 39c9850..0000000
--- a/src/3rdparty/v8/src/atomicops_internals_arm_qnx.h
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2012 Research in Motion. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-#ifndef V8_ATOMICOPS_INTERNALS_ARM_QNX_H_
-#define V8_ATOMICOPS_INTERNALS_ARM_QNX_H_
-
-#include <arm/cpuinline.h>
-#include <arm/smpxchg.h>
-
-namespace v8 {
-namespace internal {
-
-inline void MemoryBarrier() {
- __cpu_membarrier();
-}
-
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
- Atomic32 old_value,
- Atomic32 new_value) {
- return _smp_cmpxchg(reinterpret_cast<volatile unsigned*>(ptr), old_value, new_value);
-}
-
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
- Atomic32 new_value) {
- return _smp_xchg(reinterpret_cast<volatile unsigned*>(ptr), new_value);
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
- Atomic32 increment) {
- for (;;) {
- // Atomic exchange the old value with an incremented one.
- Atomic32 old_value = *ptr;
- Atomic32 new_value = old_value + increment;
- if (_smp_cmpxchg(reinterpret_cast<volatile unsigned*>(ptr), old_value, new_value)) {
- // The exchange took place as expected.
- return new_value;
- }
- // Otherwise, *ptr changed mid-loop and we need to retry.
- }
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
- Atomic32 increment) {
- MemoryBarrier();
- return NoBarrier_AtomicIncrement(ptr, increment);
-}
-
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
- Atomic32 old_value,
- Atomic32 new_value) {
- return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
- Atomic32 old_value,
- Atomic32 new_value) {
- return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
- *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
- *ptr = value;
- MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
- MemoryBarrier();
- *ptr = value;
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
- return *ptr;
-}
-
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
- Atomic32 value = *ptr;
- MemoryBarrier();
- return value;
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
- MemoryBarrier();
- return *ptr;
-}
-
-} } // namespace v8::internal
-
-#endif // V8_ATOMICOPS_INTERNALS_ARM_QNX_H_
-
diff --git a/src/3rdparty/v8/src/bootstrapper.cc b/src/3rdparty/v8/src/bootstrapper.cc
index 26451ff..048a027 100644
--- a/src/3rdparty/v8/src/bootstrapper.cc
+++ b/src/3rdparty/v8/src/bootstrapper.cc
@@ -484,8 +484,8 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
global_context()->set_initial_object_prototype(*prototype);
SetPrototype(object_fun, prototype);
- object_function_map->
- set_instance_descriptors(heap->empty_descriptor_array());
+ object_function_map->set_instance_descriptors(
+ heap->empty_descriptor_array());
}
// Allocate the empty function as the prototype for function ECMAScript
@@ -516,12 +516,10 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
function_instance_map_writable_prototype_->set_prototype(*empty_function);
// Allocate the function map first and then patch the prototype later
- Handle<Map> empty_fm = factory->CopyMapDropDescriptors(
- function_without_prototype_map);
- empty_fm->set_instance_descriptors(
- function_without_prototype_map->instance_descriptors());
- empty_fm->set_prototype(global_context()->object_function()->prototype());
- empty_function->set_map(*empty_fm);
+ Handle<Map> empty_function_map = CreateFunctionMap(DONT_ADD_PROTOTYPE);
+ empty_function_map->set_prototype(
+ global_context()->object_function()->prototype());
+ empty_function->set_map(*empty_function_map);
return empty_function;
}
@@ -811,7 +809,6 @@ void Genesis::HookUpInnerGlobal(Handle<GlobalObject> inner_global) {
Handle<JSBuiltinsObject> builtins_global(global_context_->builtins());
global_context_->set_extension(*inner_global);
global_context_->set_global(*inner_global);
- global_context_->set_qml_global(*inner_global);
global_context_->set_security_token(*inner_global);
static const PropertyAttributes attributes =
static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
@@ -837,7 +834,6 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
// Set extension and global object.
global_context()->set_extension(*inner_global);
global_context()->set_global(*inner_global);
- global_context()->set_qml_global(*inner_global);
// Security setup: Set the security token of the global object to
// its the inner global. This makes the security check between two
// different contexts fail by default even in case of global
@@ -1013,7 +1009,7 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
proto_map->set_prototype(global_context()->initial_object_prototype());
Handle<JSObject> proto = factory->NewJSObjectFromMap(proto_map);
proto->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex,
- heap->empty_string());
+ heap->query_colon_symbol());
proto->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex,
heap->false_value());
proto->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex,
@@ -2161,7 +2157,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
Handle<DescriptorArray> descs =
Handle<DescriptorArray>(from->map()->instance_descriptors());
for (int i = 0; i < descs->number_of_descriptors(); i++) {
- PropertyDetails details = PropertyDetails(descs->GetDetails(i));
+ PropertyDetails details = descs->GetDetails(i);
switch (details.type()) {
case FIELD: {
HandleScope inner;
diff --git a/src/3rdparty/v8/src/builtins.cc b/src/3rdparty/v8/src/builtins.cc
index 0f493e6..84a0c3d 100644
--- a/src/3rdparty/v8/src/builtins.cc
+++ b/src/3rdparty/v8/src/builtins.cc
@@ -412,12 +412,17 @@ static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
HeapObject* elms = array->elements();
Map* map = elms->map();
if (map == heap->fixed_array_map()) {
- if (args == NULL || !array->HasFastSmiOnlyElements()) {
+ if (args == NULL || array->HasFastElements()) return elms;
+ if (array->HasFastDoubleElements()) {
+ ASSERT(elms == heap->empty_fixed_array());
+ MaybeObject* maybe_transition =
+ array->TransitionElementsKind(FAST_ELEMENTS);
+ if (maybe_transition->IsFailure()) return maybe_transition;
return elms;
}
} else if (map == heap->fixed_cow_array_map()) {
MaybeObject* maybe_writable_result = array->EnsureWritableFastElements();
- if (args == NULL || !array->HasFastSmiOnlyElements() ||
+ if (args == NULL || array->HasFastElements() ||
maybe_writable_result->IsFailure()) {
return maybe_writable_result;
}
@@ -1098,7 +1103,7 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
CustomArguments custom(isolate);
v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
- data_obj, *function, raw_holder);
+ isolate, data_obj, *function, raw_holder);
v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
custom.end(),
@@ -1138,68 +1143,6 @@ BUILTIN(HandleApiCallConstruct) {
}
-#ifdef DEBUG
-
-static void VerifyTypeCheck(Handle<JSObject> object,
- Handle<JSFunction> function) {
- ASSERT(function->shared()->IsApiFunction());
- FunctionTemplateInfo* info = function->shared()->get_api_func_data();
- if (info->signature()->IsUndefined()) return;
- SignatureInfo* signature = SignatureInfo::cast(info->signature());
- Object* receiver_type = signature->receiver();
- if (receiver_type->IsUndefined()) return;
- FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type);
- ASSERT(object->IsInstanceOf(type));
-}
-
-#endif
-
-
-BUILTIN(FastHandleApiCall) {
- ASSERT(!CalledAsConstructor(isolate));
- Heap* heap = isolate->heap();
- const bool is_construct = false;
-
- // We expect four more arguments: callback, function, call data, and holder.
- const int args_length = args.length() - 4;
- ASSERT(args_length >= 0);
-
- Object* callback_obj = args[args_length];
-
- v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
- &args[args_length + 1],
- &args[0] - 1,
- args_length - 1,
- is_construct);
-
-#ifdef DEBUG
- VerifyTypeCheck(Utils::OpenHandle(*new_args.Holder()),
- Utils::OpenHandle(*new_args.Callee()));
-#endif
- HandleScope scope(isolate);
- Object* result;
- v8::Handle<v8::Value> value;
- {
- // Leaving JavaScript.
- VMState state(isolate, EXTERNAL);
- ExternalCallbackScope call_scope(isolate,
- v8::ToCData<Address>(callback_obj));
- v8::InvocationCallback callback =
- v8::ToCData<v8::InvocationCallback>(callback_obj);
-
- value = callback(new_args);
- }
- if (value.IsEmpty()) {
- result = heap->undefined_value();
- } else {
- result = *reinterpret_cast<Object**>(*value);
- }
-
- RETURN_IF_SCHEDULED_EXCEPTION(isolate);
- return result;
-}
-
-
// Helper function to handle calls to non-function objects created through the
// API. The object can be called as either a constructor (using new) or just as
// a function (without new).
@@ -1238,7 +1181,7 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
CustomArguments custom(isolate);
v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
- call_data->data(), constructor, obj);
+ isolate, call_data->data(), constructor, obj);
v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
custom.end(),
&args[0] - 1,
diff --git a/src/3rdparty/v8/src/builtins.h b/src/3rdparty/v8/src/builtins.h
index f079139..3ea3393 100644
--- a/src/3rdparty/v8/src/builtins.h
+++ b/src/3rdparty/v8/src/builtins.h
@@ -56,7 +56,6 @@ enum BuiltinExtraArguments {
V(ArrayConcat, NO_EXTRA_ARGUMENTS) \
\
V(HandleApiCall, NEEDS_CALLED_FUNCTION) \
- V(FastHandleApiCall, NO_EXTRA_ARGUMENTS) \
V(HandleApiCallConstruct, NEEDS_CALLED_FUNCTION) \
V(HandleApiCallAsFunction, NO_EXTRA_ARGUMENTS) \
V(HandleApiCallAsConstructor, NO_EXTRA_ARGUMENTS) \
diff --git a/src/3rdparty/v8/src/code-stubs.cc b/src/3rdparty/v8/src/code-stubs.cc
index 11016c8..814e358 100644
--- a/src/3rdparty/v8/src/code-stubs.cc
+++ b/src/3rdparty/v8/src/code-stubs.cc
@@ -73,21 +73,12 @@ SmartArrayPointer<const char> CodeStub::GetName() {
void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) {
- code->set_major_key(MajorKey());
-
Isolate* isolate = masm->isolate();
SmartArrayPointer<const char> name = GetName();
PROFILE(isolate, CodeCreateEvent(Logger::STUB_TAG, code, *name));
GDBJIT(AddCode(GDBJITInterface::STUB, *name, code));
Counters* counters = isolate->counters();
counters->total_stubs_code_size()->Increment(code->instruction_size());
-
-#ifdef ENABLE_DISASSEMBLER
- if (FLAG_print_code_stubs) {
- code->Disassemble(*name);
- PrintF("\n");
- }
-#endif
}
@@ -125,8 +116,16 @@ Handle<Code> CodeStub::GetCode() {
GetICState());
Handle<Code> new_object = factory->NewCode(
desc, flags, masm.CodeObject(), NeedsImmovableCode());
- RecordCodeGeneration(*new_object, &masm);
+ new_object->set_major_key(MajorKey());
FinishCode(new_object);
+ RecordCodeGeneration(*new_object, &masm);
+
+#ifdef ENABLE_DISASSEMBLER
+ if (FLAG_print_code_stubs) {
+ new_object->Disassemble(*GetName());
+ PrintF("\n");
+ }
+#endif
if (UseSpecialCache()) {
AddToSpecialCache(new_object);
diff --git a/src/3rdparty/v8/src/code-stubs.h b/src/3rdparty/v8/src/code-stubs.h
index 4b6ceb2..5c87178 100644
--- a/src/3rdparty/v8/src/code-stubs.h
+++ b/src/3rdparty/v8/src/code-stubs.h
@@ -343,7 +343,7 @@ class FastNewContextStub : public CodeStub {
static const int kMaximumSlots = 64;
explicit FastNewContextStub(int slots) : slots_(slots) {
- ASSERT(slots_ >= 0 && slots_ <= kMaximumSlots);
+ ASSERT(slots_ > 0 && slots_ <= kMaximumSlots);
}
void Generate(MacroAssembler* masm);
@@ -361,7 +361,7 @@ class FastNewBlockContextStub : public CodeStub {
static const int kMaximumSlots = 64;
explicit FastNewBlockContextStub(int slots) : slots_(slots) {
- ASSERT(slots_ >= 0 && slots_ <= kMaximumSlots);
+ ASSERT(slots_ > 0 && slots_ <= kMaximumSlots);
}
void Generate(MacroAssembler* masm);
@@ -498,6 +498,7 @@ class ICCompareStub: public CodeStub {
virtual void FinishCode(Handle<Code> code) {
code->set_compare_state(state_);
+ code->set_compare_operation(op_);
}
virtual CodeStub::Major MajorKey() { return CompareIC; }
diff --git a/src/3rdparty/v8/src/compiler-intrinsics.h b/src/3rdparty/v8/src/compiler-intrinsics.h
index 3b9c59e..b73e8ac 100644
--- a/src/3rdparty/v8/src/compiler-intrinsics.h
+++ b/src/3rdparty/v8/src/compiler-intrinsics.h
@@ -40,6 +40,9 @@ class CompilerIntrinsics {
// Returns number of zero bits following most significant 1 bit.
// Undefined for zero value.
INLINE(static int CountLeadingZeros(uint32_t value));
+
+ // Returns the number of bits set.
+ INLINE(static int CountSetBits(uint32_t value));
};
#ifdef __GNUC__
@@ -51,6 +54,10 @@ int CompilerIntrinsics::CountLeadingZeros(uint32_t value) {
return __builtin_clz(value);
}
+int CompilerIntrinsics::CountSetBits(uint32_t value) {
+ return __builtin_popcount(value);
+}
+
#elif defined(_MSC_VER)
#pragma intrinsic(_BitScanForward)
@@ -68,6 +75,16 @@ int CompilerIntrinsics::CountLeadingZeros(uint32_t value) {
return 31 - static_cast<int>(result);
}
+int CompilerIntrinsics::CountSetBits(uint32_t value) {
+ // Manually count set bits.
+ value = ((value >> 1) & 0x55555555) + (value & 0x55555555);
+ value = ((value >> 2) & 0x33333333) + (value & 0x33333333);
+ value = ((value >> 4) & 0x0f0f0f0f) + (value & 0x0f0f0f0f);
+ value = ((value >> 8) & 0x00ff00ff) + (value & 0x00ff00ff);
+ value = ((value >> 16) & 0x0000ffff) + (value & 0x0000ffff);
+ return value;
+}
+
#else
#error Unsupported compiler
#endif
diff --git a/src/3rdparty/v8/src/compiler.cc b/src/3rdparty/v8/src/compiler.cc
index 6435068..ecac5cb 100644
--- a/src/3rdparty/v8/src/compiler.cc
+++ b/src/3rdparty/v8/src/compiler.cc
@@ -118,7 +118,7 @@ bool CompilationInfo::ShouldSelfOptimize() {
FLAG_crankshaft &&
!function()->flags()->Contains(kDontSelfOptimize) &&
!function()->flags()->Contains(kDontOptimize) &&
- function()->scope()->allows_lazy_recompilation() &&
+ function()->scope()->AllowsLazyRecompilation() &&
(shared_info().is_null() || !shared_info()->optimization_disabled());
}
@@ -475,8 +475,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
v8::Extension* extension,
ScriptDataImpl* pre_data,
Handle<Object> script_data,
- NativesFlag natives,
- v8::Script::CompileFlags compile_flags) {
+ NativesFlag natives) {
Isolate* isolate = source->GetIsolate();
int source_length = source->length();
isolate->counters()->total_load_size()->Increment(source_length);
@@ -508,7 +507,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
// Create a script object describing the script to be compiled.
Handle<Script> script = FACTORY->NewScript(source);
- if (natives == NATIVES_CODE || compile_flags & v8::Script::NativeMode) {
+ if (natives == NATIVES_CODE) {
script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
}
if (!script_name.is_null()) {
@@ -528,7 +527,6 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
if (FLAG_use_strict) {
info.SetLanguageMode(FLAG_harmony_scoping ? EXTENDED_MODE : STRICT_MODE);
}
- if (compile_flags & v8::Script::QmlMode) info.MarkAsQmlMode();
result = MakeFunctionInfo(&info);
if (extension == NULL && !result.is_null()) {
compilation_cache->PutScript(source, result);
@@ -548,8 +546,7 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
Handle<Context> context,
bool is_global,
LanguageMode language_mode,
- int scope_position,
- bool qml_mode) {
+ int scope_position) {
Isolate* isolate = source->GetIsolate();
int source_length = source->length();
isolate->counters()->total_eval_size()->Increment(source_length);
@@ -575,7 +572,6 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
info.MarkAsEval();
if (is_global) info.MarkAsGlobal();
info.SetLanguageMode(language_mode);
- if (qml_mode) info.MarkAsQmlMode();
info.SetCallingContext(context);
result = MakeFunctionInfo(&info);
if (!result.is_null()) {
@@ -630,12 +626,6 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
info->SetLanguageMode(language_mode);
shared->set_language_mode(language_mode);
- // After parsing we know function's qml mode. Remember it.
- if (info->function()->qml_mode()) {
- shared->set_qml_mode(true);
- info->MarkAsQmlMode();
- }
-
// Compile the code.
if (!MakeCode(info)) {
if (!isolate->has_pending_exception()) {
@@ -785,7 +775,6 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
*lit->this_property_assignments());
function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
function_info->set_language_mode(lit->language_mode());
- function_info->set_qml_mode(lit->qml_mode());
function_info->set_uses_arguments(lit->scope()->arguments() != NULL);
function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
function_info->set_ast_node_count(lit->ast_node_count());
diff --git a/src/3rdparty/v8/src/compiler.h b/src/3rdparty/v8/src/compiler.h
index 09583c0..44df9e0 100644
--- a/src/3rdparty/v8/src/compiler.h
+++ b/src/3rdparty/v8/src/compiler.h
@@ -58,7 +58,6 @@ class CompilationInfo BASE_EMBEDDED {
return LanguageModeField::decode(flags_);
}
bool is_in_loop() const { return IsInLoop::decode(flags_); }
- bool is_qml_mode() const { return IsQmlMode::decode(flags_); }
FunctionLiteral* function() const { return function_; }
Scope* scope() const { return scope_; }
Scope* global_scope() const { return global_scope_; }
@@ -89,9 +88,6 @@ class CompilationInfo BASE_EMBEDDED {
ASSERT(is_lazy());
flags_ |= IsInLoop::encode(true);
}
- void MarkAsQmlMode() {
- flags_ |= IsQmlMode::encode(true);
- }
void MarkAsNative() {
flags_ |= IsNative::encode(true);
}
@@ -200,9 +196,6 @@ class CompilationInfo BASE_EMBEDDED {
ASSERT(language_mode() == CLASSIC_MODE);
SetLanguageMode(shared_info_->language_mode());
}
- if (!shared_info_.is_null() && shared_info_->qml_mode()) {
- MarkAsQmlMode();
- }
}
void SetMode(Mode mode) {
@@ -229,8 +222,7 @@ class CompilationInfo BASE_EMBEDDED {
// If compiling for debugging produce just full code matching the
// initial mode setting.
class IsCompilingForDebugging: public BitField<bool, 8, 1> {};
- // Qml mode
- class IsQmlMode: public BitField<bool, 9, 1> {};
+
unsigned flags_;
@@ -300,16 +292,14 @@ class Compiler : public AllStatic {
v8::Extension* extension,
ScriptDataImpl* pre_data,
Handle<Object> script_data,
- NativesFlag is_natives_code,
- v8::Script::CompileFlags = v8::Script::Default);
+ NativesFlag is_natives_code);
// Compile a String source within a context for Eval.
static Handle<SharedFunctionInfo> CompileEval(Handle<String> source,
Handle<Context> context,
bool is_global,
LanguageMode language_mode,
- int scope_position,
- bool qml_mode);
+ int scope_position);
// Compile from function info (used for lazy compilation). Returns true on
// success and false if the compilation resulted in a stack overflow.
diff --git a/src/3rdparty/v8/src/contexts.cc b/src/3rdparty/v8/src/contexts.cc
index cf07cc6..76784bd 100644
--- a/src/3rdparty/v8/src/contexts.cc
+++ b/src/3rdparty/v8/src/contexts.cc
@@ -103,9 +103,6 @@ Handle<Object> Context::Lookup(Handle<String> name,
PrintF(")\n");
}
- Handle<JSObject> qml_global;
- Handle<JSObject> qml_global_global;
-
do {
if (FLAG_trace_contexts) {
PrintF(" - looking in context %p", reinterpret_cast<void*>(*context));
@@ -113,11 +110,6 @@ Handle<Object> Context::Lookup(Handle<String> name,
PrintF("\n");
}
- if (qml_global.is_null() && !context->qml_global()->IsUndefined()) {
- qml_global = Handle<JSObject>(context->qml_global(), isolate);
- qml_global_global = Handle<JSObject>(context->global(), isolate);
- }
-
// 1. Check global objects, subjects of with, and extension objects.
if (context->IsGlobalContext() ||
context->IsWithContext() ||
@@ -241,33 +233,6 @@ Handle<Object> Context::Lookup(Handle<String> name,
}
} while (follow_context_chain);
- if (!qml_global.is_null()) {
- if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0) {
- *attributes = qml_global_global->GetLocalPropertyAttribute(*name);
- } else {
- *attributes = qml_global_global->GetPropertyAttribute(*name);
- }
-
- if (*attributes != ABSENT) {
- *attributes = ABSENT;
- } else {
- if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0) {
- *attributes = qml_global->GetLocalPropertyAttribute(*name);
- } else {
- *attributes = qml_global->GetPropertyAttribute(*name);
- }
-
- if (*attributes != ABSENT) {
- // property found
- if (FLAG_trace_contexts) {
- PrintF("=> found property in qml global object %p\n",
- reinterpret_cast<void*>(*qml_global));
- }
- return qml_global;
- }
- }
- }
-
if (FLAG_trace_contexts) {
PrintF("=> no property/slot found\n");
}
diff --git a/src/3rdparty/v8/src/contexts.h b/src/3rdparty/v8/src/contexts.h
index 326e6db..647c15c 100644
--- a/src/3rdparty/v8/src/contexts.h
+++ b/src/3rdparty/v8/src/contexts.h
@@ -221,7 +221,6 @@ class Context: public FixedArray {
// (with contexts), or the variable name (catch contexts), the serialized
// scope info (block contexts).
EXTENSION_INDEX,
- QML_GLOBAL_INDEX,
GLOBAL_INDEX,
MIN_CONTEXT_SLOTS,
@@ -328,9 +327,6 @@ class Context: public FixedArray {
}
void set_global(GlobalObject* global) { set(GLOBAL_INDEX, global); }
- JSObject *qml_global() { return reinterpret_cast<JSObject *>(get(QML_GLOBAL_INDEX)); }
- void set_qml_global(JSObject *qml_global) { set(QML_GLOBAL_INDEX, qml_global); }
-
// Returns a JSGlobalProxy object or null.
JSObject* global_proxy();
void set_global_proxy(JSObject* global);
@@ -401,7 +397,7 @@ class Context: public FixedArray {
GLOBAL_CONTEXT_FIELDS(GLOBAL_CONTEXT_FIELD_ACCESSORS)
#undef GLOBAL_CONTEXT_FIELD_ACCESSORS
- // Lookup the the slot called name, starting with the current context.
+ // Lookup the slot called name, starting with the current context.
// There are three possibilities:
//
// 1) result->IsContext():
diff --git a/src/3rdparty/v8/src/d8.cc b/src/3rdparty/v8/src/d8.cc
index 1e8b4c8..ddd4100 100644
--- a/src/3rdparty/v8/src/d8.cc
+++ b/src/3rdparty/v8/src/d8.cc
@@ -26,7 +26,8 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifdef USING_V8_SHARED // Defined when linking against shared lib on Windows.
+// Defined when linking against shared lib on Windows.
+#if defined(USING_V8_SHARED) && !defined(V8_SHARED)
#define V8_SHARED
#endif
@@ -315,9 +316,10 @@ static size_t convertToUint(Local<Value> value_in, TryCatch* try_catch) {
}
-const char kArrayBufferReferencePropName[] = "_is_array_buffer_";
-const char kArrayBufferMarkerPropName[] = "_array_buffer_ref_";
+const char kArrayBufferMarkerPropName[] = "_is_array_buffer_";
+const char kArrayBufferReferencePropName[] = "_array_buffer_ref_";
+static const int kExternalArrayAllocationHeaderSize = 2;
Handle<Value> Shell::CreateExternalArray(const Arguments& args,
ExternalArrayType type,
@@ -352,10 +354,11 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args,
Local<Value> length_value = (args.Length() < 3)
? (first_arg_is_array_buffer
- ? args[0]->ToObject()->Get(String::New("length"))
+ ? args[0]->ToObject()->Get(String::New("byteLength"))
: args[0])
: args[2];
- size_t length = convertToUint(length_value, &try_catch);
+ size_t byteLength = convertToUint(length_value, &try_catch);
+ size_t length = byteLength;
if (try_catch.HasCaught()) return try_catch.Exception();
void* data = NULL;
@@ -367,7 +370,7 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args,
data = derived_from->GetIndexedPropertiesExternalArrayData();
size_t array_buffer_length = convertToUint(
- derived_from->Get(String::New("length")),
+ derived_from->Get(String::New("byteLength")),
&try_catch);
if (try_catch.HasCaught()) return try_catch.Exception();
@@ -433,13 +436,14 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args,
return ThrowException(String::New("Array exceeds maximum size (2G)"));
}
// Prepend the size of the allocated chunk to the data itself.
- int total_size = length * element_size + sizeof(size_t);
+ int total_size = length * element_size +
+ kExternalArrayAllocationHeaderSize * sizeof(size_t);
data = malloc(total_size);
if (data == NULL) {
return ThrowException(String::New("Memory allocation failed."));
}
*reinterpret_cast<size_t*>(data) = total_size;
- data = reinterpret_cast<size_t*>(data) + 1;
+ data = reinterpret_cast<size_t*>(data) + kExternalArrayAllocationHeaderSize;
memset(data, 0, length * element_size);
V8::AdjustAmountOfExternalAllocatedMemory(total_size);
}
@@ -449,10 +453,20 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args,
array->SetIndexedPropertiesToExternalArrayData(
reinterpret_cast<uint8_t*>(data) + offset, type,
static_cast<int>(length));
- array->Set(String::New("length"),
- Int32::New(static_cast<int32_t>(length)), ReadOnly);
- array->Set(String::New("BYTES_PER_ELEMENT"),
- Int32::New(static_cast<int32_t>(element_size)));
+ array->Set(String::New("byteLength"),
+ Int32::New(static_cast<int32_t>(byteLength)), ReadOnly);
+ if (!is_array_buffer_construct) {
+ array->Set(String::New("length"),
+ Int32::New(static_cast<int32_t>(length)), ReadOnly);
+ array->Set(String::New("byteOffset"),
+ Int32::New(static_cast<int32_t>(offset)), ReadOnly);
+ array->Set(String::New("BYTES_PER_ELEMENT"),
+ Int32::New(static_cast<int32_t>(element_size)));
+ // We currently support 'buffer' property only if constructed from a buffer.
+ if (first_arg_is_array_buffer) {
+ array->Set(String::New("buffer"), args[0], ReadOnly);
+ }
+ }
return array;
}
@@ -463,7 +477,7 @@ void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) {
Handle<Object> converted_object = object->ToObject();
Local<Value> prop_value = converted_object->Get(prop_name);
if (data != NULL && !prop_value->IsObject()) {
- data = reinterpret_cast<size_t*>(data) - 1;
+ data = reinterpret_cast<size_t*>(data) - kExternalArrayAllocationHeaderSize;
V8::AdjustAmountOfExternalAllocatedMemory(
-static_cast<int>(*reinterpret_cast<size_t*>(data)));
free(data);
@@ -822,6 +836,8 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate() {
global_template->Set(String::New("read"), FunctionTemplate::New(Read));
global_template->Set(String::New("readbinary"),
FunctionTemplate::New(ReadBinary));
+ global_template->Set(String::New("readbuffer"),
+ FunctionTemplate::New(ReadBuffer));
global_template->Set(String::New("readline"),
FunctionTemplate::New(ReadLine));
global_template->Set(String::New("load"), FunctionTemplate::New(Load));
@@ -1057,6 +1073,32 @@ Handle<Value> Shell::ReadBinary(const Arguments& args) {
}
+Handle<Value> Shell::ReadBuffer(const Arguments& args) {
+ String::Utf8Value filename(args[0]);
+ int length;
+ if (*filename == NULL) {
+ return ThrowException(String::New("Error loading file"));
+ }
+ char* data = ReadChars(*filename, &length);
+ if (data == NULL) {
+ return ThrowException(String::New("Error reading file"));
+ }
+
+ Handle<Object> buffer = Object::New();
+ buffer->Set(String::New(kArrayBufferMarkerPropName), True(), ReadOnly);
+
+ Persistent<Object> persistent_buffer = Persistent<Object>::New(buffer);
+ persistent_buffer.MakeWeak(data, ExternalArrayWeakCallback);
+ persistent_buffer.MarkIndependent();
+
+ buffer->SetIndexedPropertiesToExternalArrayData(
+ reinterpret_cast<uint8_t*>(data), kExternalUnsignedByteArray, length);
+ buffer->Set(String::New("byteLength"),
+ Int32::New(static_cast<int32_t>(length)), ReadOnly);
+ return buffer;
+}
+
+
#ifndef V8_SHARED
static char* ReadToken(char* data, char token) {
char* next = i::OS::StrChr(data, token);
diff --git a/src/3rdparty/v8/src/d8.h b/src/3rdparty/v8/src/d8.h
index c872f90..23fdebc 100644
--- a/src/3rdparty/v8/src/d8.h
+++ b/src/3rdparty/v8/src/d8.h
@@ -308,6 +308,7 @@ class Shell : public i::AllStatic {
static Handle<Value> DisableProfiler(const Arguments& args);
static Handle<Value> Read(const Arguments& args);
static Handle<Value> ReadBinary(const Arguments& args);
+ static Handle<Value> ReadBuffer(const Arguments& args);
static Handle<String> ReadFromStdin();
static Handle<Value> ReadLine(const Arguments& args) {
return ReadFromStdin();
diff --git a/src/3rdparty/v8/src/debug-agent.cc b/src/3rdparty/v8/src/debug-agent.cc
index 511663d..10c0053 100644
--- a/src/3rdparty/v8/src/debug-agent.cc
+++ b/src/3rdparty/v8/src/debug-agent.cc
@@ -1,4 +1,4 @@
-// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -247,7 +247,7 @@ SmartArrayPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
while (!(c == '\n' && prev_c == '\r')) {
prev_c = c;
received = conn->Receive(&c, 1);
- if (received <= 0) {
+ if (received == 0) {
PrintF("Error %d\n", Socket::LastError());
return SmartArrayPointer<char>();
}
@@ -454,7 +454,7 @@ int DebuggerAgentUtil::ReceiveAll(const Socket* conn, char* data, int len) {
int total_received = 0;
while (total_received < len) {
int received = conn->Receive(data + total_received, len - total_received);
- if (received <= 0) {
+ if (received == 0) {
return total_received;
}
total_received += received;
diff --git a/src/3rdparty/v8/src/debug-debugger.js b/src/3rdparty/v8/src/debug-debugger.js
index 3a58bda..91838e8 100644
--- a/src/3rdparty/v8/src/debug-debugger.js
+++ b/src/3rdparty/v8/src/debug-debugger.js
@@ -449,11 +449,6 @@ ScriptBreakPoint.prototype.set = function (script) {
actual_position = position;
}
var actual_location = script.locationFromPosition(actual_position, true);
- // Check for any relocation and compare it with the breakpoint_relocation flag
- if (actual_location.line != line && !%AllowBreakPointRelocation()) {
- %ClearBreakPoint(break_point);
- return;
- }
break_point.actual_location = { line: actual_location.line,
column: actual_location.column,
script_id: script.id };
@@ -1962,7 +1957,7 @@ DebugCommandProcessor.prototype.frameForScopeRequest_ = function(request) {
if (request.arguments && !IS_UNDEFINED(request.arguments.frameNumber)) {
frame_index = request.arguments.frameNumber;
if (frame_index < 0 || this.exec_state_.frameCount() <= frame_index) {
- return response.failed('Invalid frame number');
+ throw new Error('Invalid frame number');
}
return this.exec_state_.frame(frame_index);
} else {
@@ -1971,20 +1966,44 @@ DebugCommandProcessor.prototype.frameForScopeRequest_ = function(request) {
};
-DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
- // No frames no scopes.
- if (this.exec_state_.frameCount() == 0) {
- return response.failed('No scopes');
+// Gets scope host object from request. It is either a function
+// ('functionHandle' argument must be specified) or a stack frame
+// ('frameNumber' may be specified and the current frame is taken by default).
+DebugCommandProcessor.prototype.scopeHolderForScopeRequest_ =
+ function(request) {
+ if (request.arguments && "functionHandle" in request.arguments) {
+ if (!IS_NUMBER(request.arguments.functionHandle)) {
+ throw new Error('Function handle must be a number');
+ }
+ var function_mirror = LookupMirror(request.arguments.functionHandle);
+ if (!function_mirror) {
+ throw new Error('Failed to find function object by handle');
+ }
+ if (!function_mirror.isFunction()) {
+ throw new Error('Value of non-function type is found by handle');
+ }
+ return function_mirror;
+ } else {
+ // No frames no scopes.
+ if (this.exec_state_.frameCount() == 0) {
+ throw new Error('No scopes');
+ }
+
+ // Get the frame for which the scopes are requested.
+ var frame = this.frameForScopeRequest_(request);
+ return frame;
}
+}
- // Get the frame for which the scopes are requested.
- var frame = this.frameForScopeRequest_(request);
- // Fill all scopes for this frame.
- var total_scopes = frame.scopeCount();
+DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
+ var scope_holder = this.scopeHolderForScopeRequest_(request);
+
+ // Fill all scopes for this frame or function.
+ var total_scopes = scope_holder.scopeCount();
var scopes = [];
for (var i = 0; i < total_scopes; i++) {
- scopes.push(frame.scope(i));
+ scopes.push(scope_holder.scope(i));
}
response.body = {
fromScope: 0,
@@ -1996,24 +2015,19 @@ DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
DebugCommandProcessor.prototype.scopeRequest_ = function(request, response) {
- // No frames no scopes.
- if (this.exec_state_.frameCount() == 0) {
- return response.failed('No scopes');
- }
-
- // Get the frame for which the scope is requested.
- var frame = this.frameForScopeRequest_(request);
+ // Get the frame or function for which the scope is requested.
+ var scope_holder = this.scopeHolderForScopeRequest_(request);
// With no scope argument just return top scope.
var scope_index = 0;
if (request.arguments && !IS_UNDEFINED(request.arguments.number)) {
scope_index = %ToNumber(request.arguments.number);
- if (scope_index < 0 || frame.scopeCount() <= scope_index) {
+ if (scope_index < 0 || scope_holder.scopeCount() <= scope_index) {
return response.failed('Invalid scope number');
}
}
- response.body = frame.scope(scope_index);
+ response.body = scope_holder.scope(scope_index);
};
diff --git a/src/3rdparty/v8/src/debug.cc b/src/3rdparty/v8/src/debug.cc
index 99256ba..9efb5c3 100644
--- a/src/3rdparty/v8/src/debug.cc
+++ b/src/3rdparty/v8/src/debug.cc
@@ -892,6 +892,16 @@ void Debug::Iterate(ObjectVisitor* v) {
}
+void Debug::PutValuesOnStackAndDie(int start,
+ Address c_entry_fp,
+ Address last_fp,
+ Address larger_fp,
+ int count,
+ int end) {
+ OS::Abort();
+}
+
+
Object* Debug::Break(Arguments args) {
Heap* heap = isolate_->heap();
HandleScope scope(isolate_);
@@ -984,11 +994,34 @@ Object* Debug::Break(Arguments args) {
// Count frames until target frame
int count = 0;
JavaScriptFrameIterator it(isolate_);
- while (!it.done() && it.frame()->fp() != thread_local_.last_fp_) {
+ while (!it.done() && it.frame()->fp() < thread_local_.last_fp_) {
count++;
it.Advance();
}
+ // Catch the cases that would lead to crashes and capture
+ // - C entry FP at which to start stack crawl.
+ // - FP of the frame at which we plan to stop stepping out (last FP).
+ // - current FP that's larger than last FP.
+ // - Counter for the number of steps to step out.
+ if (it.done()) {
+ // We crawled the entire stack, never reaching last_fp_.
+ PutValuesOnStackAndDie(0xBEEEEEEE,
+ frame->fp(),
+ thread_local_.last_fp_,
+ NULL,
+ count,
+ 0xFEEEEEEE);
+ } else if (it.frame()->fp() != thread_local_.last_fp_) {
+ // We crawled over last_fp_, without getting a match.
+ PutValuesOnStackAndDie(0xBEEEEEEE,
+ frame->fp(),
+ thread_local_.last_fp_,
+ it.frame()->fp(),
+ count,
+ 0xFEEEEEEE);
+ }
+
// If we found original frame
if (it.frame()->fp() == thread_local_.last_fp_) {
if (step_count > 1) {
@@ -2227,6 +2260,13 @@ void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
}
+const int Debug::FramePaddingLayout::kInitialSize = 1;
+
+
+// Any even value bigger than kInitialSize as needed for stack scanning.
+const int Debug::FramePaddingLayout::kPaddingValue = kInitialSize + 1;
+
+
bool Debug::IsDebugGlobal(GlobalObject* global) {
return IsLoaded() && global == debug_context()->global();
}
diff --git a/src/3rdparty/v8/src/debug.h b/src/3rdparty/v8/src/debug.h
index 474b90b..d9c966c 100644
--- a/src/3rdparty/v8/src/debug.h
+++ b/src/3rdparty/v8/src/debug.h
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -232,6 +232,12 @@ class Debug {
void PreemptionWhileInDebugger();
void Iterate(ObjectVisitor* v);
+ NO_INLINE(void PutValuesOnStackAndDie(int start,
+ Address c_entry_fp,
+ Address last_fp,
+ Address larger_fp,
+ int count,
+ int end));
Object* Break(Arguments args);
void SetBreakPoint(Handle<SharedFunctionInfo> shared,
Handle<Object> break_point_object,
@@ -245,6 +251,8 @@ class Debug {
bool IsBreakOnException(ExceptionBreakType type);
void PrepareStep(StepAction step_action, int step_count);
void ClearStepping();
+ void ClearStepOut();
+ bool IsStepping() { return thread_local_.step_count_ > 0; }
bool StepNextContinue(BreakLocationIterator* break_location_iterator,
JavaScriptFrame* frame);
static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared);
@@ -455,6 +463,50 @@ class Debug {
// Architecture-specific constant.
static const bool kFrameDropperSupported;
+ /**
+ * Defines layout of a stack frame that supports padding. This is a regular
+ * internal frame that has a flexible stack structure. LiveEdit can shift
+ * its lower part up the stack, taking up the 'padding' space when additional
+ * stack memory is required.
+ * Such frame is expected immediately above the topmost JavaScript frame.
+ *
+ * Stack Layout:
+ * --- Top
+ * LiveEdit routine frames
+ * ---
+ * C frames of debug handler
+ * ---
+ * ...
+ * ---
+ * An internal frame that has n padding words:
+ * - any number of words as needed by code -- upper part of frame
+ * - padding size: a Smi storing n -- current size of padding
+ * - padding: n words filled with kPaddingValue in form of Smi
+ * - 3 context/type words of a regular InternalFrame
+ * - fp
+ * ---
+ * Topmost JavaScript frame
+ * ---
+ * ...
+ * --- Bottom
+ */
+ class FramePaddingLayout : public AllStatic {
+ public:
+ // Architecture-specific constant.
+ static const bool kIsSupported;
+
+ // A size of frame base including fp. Padding words starts right above
+ // the base.
+ static const int kFrameBaseSize = 4;
+
+ // A number of words that should be reserved on stack for the LiveEdit use.
+ // Normally equals 1. Stored on stack in form of Smi.
+ static const int kInitialSize;
+ // A value that padding words are filled with (in form of Smi). Going
+ // bottom-top, the first word not having this value is a counter word.
+ static const int kPaddingValue;
+ };
+
private:
explicit Debug(Isolate* isolate);
~Debug();
@@ -464,7 +516,6 @@ class Debug {
void ActivateStepIn(StackFrame* frame);
void ClearStepIn();
void ActivateStepOut(StackFrame* frame);
- void ClearStepOut();
void ClearStepNext();
// Returns whether the compile succeeded.
void RemoveDebugInfo(Handle<DebugInfo> debug_info);
diff --git a/src/3rdparty/v8/src/double.h b/src/3rdparty/v8/src/double.h
index 16a3245..fcf6906 100644
--- a/src/3rdparty/v8/src/double.h
+++ b/src/3rdparty/v8/src/double.h
@@ -130,12 +130,6 @@ class Double {
return (d64 & kExponentMask) == kExponentMask;
}
- bool IsNan() const {
- uint64_t d64 = AsUint64();
- return ((d64 & kExponentMask) == kExponentMask) &&
- ((d64 & kSignificandMask) != 0);
- }
-
bool IsInfinite() const {
uint64_t d64 = AsUint64();
return ((d64 & kExponentMask) == kExponentMask) &&
diff --git a/src/3rdparty/v8/src/elements.cc b/src/3rdparty/v8/src/elements.cc
index 26d3dc1..d367af8 100644
--- a/src/3rdparty/v8/src/elements.cc
+++ b/src/3rdparty/v8/src/elements.cc
@@ -424,10 +424,10 @@ class ElementsAccessorBase : public ElementsAccessor {
receiver, holder, key, BackingStore::cast(backing_store));
}
- virtual MaybeObject* Get(Object* receiver,
- JSObject* holder,
- uint32_t key,
- FixedArrayBase* backing_store) {
+ MUST_USE_RESULT virtual MaybeObject* Get(Object* receiver,
+ JSObject* holder,
+ uint32_t key,
+ FixedArrayBase* backing_store) {
if (backing_store == NULL) {
backing_store = holder->elements();
}
@@ -435,62 +435,64 @@ class ElementsAccessorBase : public ElementsAccessor {
receiver, holder, key, BackingStore::cast(backing_store));
}
- static MaybeObject* GetImpl(Object* receiver,
- JSObject* obj,
- uint32_t key,
- BackingStore* backing_store) {
+ MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ BackingStore* backing_store) {
return (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store))
? backing_store->get(key)
: backing_store->GetHeap()->the_hole_value();
}
- virtual MaybeObject* SetLength(JSArray* array,
- Object* length) {
+ MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* array,
+ Object* length) {
return ElementsAccessorSubclass::SetLengthImpl(
array, length, BackingStore::cast(array->elements()));
}
- static MaybeObject* SetLengthImpl(JSObject* obj,
- Object* length,
- BackingStore* backing_store);
+ MUST_USE_RESULT static MaybeObject* SetLengthImpl(
+ JSObject* obj,
+ Object* length,
+ BackingStore* backing_store);
- virtual MaybeObject* SetCapacityAndLength(JSArray* array,
- int capacity,
- int length) {
+ MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(JSArray* array,
+ int capacity,
+ int length) {
return ElementsAccessorSubclass::SetFastElementsCapacityAndLength(
array,
capacity,
length);
}
- static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
- int capacity,
- int length) {
+ MUST_USE_RESULT static MaybeObject* SetFastElementsCapacityAndLength(
+ JSObject* obj,
+ int capacity,
+ int length) {
UNIMPLEMENTED();
return obj;
}
- virtual MaybeObject* Delete(JSObject* obj,
- uint32_t key,
- JSReceiver::DeleteMode mode) = 0;
+ MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
+ uint32_t key,
+ JSReceiver::DeleteMode mode) = 0;
- static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
- uint32_t from_start,
- FixedArrayBase* to,
- ElementsKind to_kind,
- uint32_t to_start,
- int copy_size) {
+ MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
+ uint32_t from_start,
+ FixedArrayBase* to,
+ ElementsKind to_kind,
+ uint32_t to_start,
+ int copy_size) {
UNREACHABLE();
return NULL;
}
- virtual MaybeObject* CopyElements(JSObject* from_holder,
- uint32_t from_start,
- FixedArrayBase* to,
- ElementsKind to_kind,
- uint32_t to_start,
- int copy_size,
- FixedArrayBase* from) {
+ MUST_USE_RESULT virtual MaybeObject* CopyElements(JSObject* from_holder,
+ uint32_t from_start,
+ FixedArrayBase* to,
+ ElementsKind to_kind,
+ uint32_t to_start,
+ int copy_size,
+ FixedArrayBase* from) {
if (from == NULL) {
from = from_holder->elements();
}
@@ -501,10 +503,11 @@ class ElementsAccessorBase : public ElementsAccessor {
from, from_start, to, to_kind, to_start, copy_size);
}
- virtual MaybeObject* AddElementsToFixedArray(Object* receiver,
- JSObject* holder,
- FixedArray* to,
- FixedArrayBase* from) {
+ MUST_USE_RESULT virtual MaybeObject* AddElementsToFixedArray(
+ Object* receiver,
+ JSObject* holder,
+ FixedArray* to,
+ FixedArrayBase* from) {
int len0 = to->length();
#ifdef DEBUG
if (FLAG_enable_slow_asserts) {
@@ -866,27 +869,28 @@ class ExternalElementsAccessor
friend class ElementsAccessorBase<ExternalElementsAccessorSubclass,
ElementsKindTraits<Kind> >;
- static MaybeObject* GetImpl(Object* receiver,
- JSObject* obj,
- uint32_t key,
- BackingStore* backing_store) {
+ MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ BackingStore* backing_store) {
return
key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
? backing_store->get(key)
: backing_store->GetHeap()->undefined_value();
}
- static MaybeObject* SetLengthImpl(JSObject* obj,
- Object* length,
- BackingStore* backing_store) {
+ MUST_USE_RESULT static MaybeObject* SetLengthImpl(
+ JSObject* obj,
+ Object* length,
+ BackingStore* backing_store) {
// External arrays do not support changing their length.
UNREACHABLE();
return obj;
}
- virtual MaybeObject* Delete(JSObject* obj,
- uint32_t key,
- JSReceiver::DeleteMode mode) {
+ MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
+ uint32_t key,
+ JSReceiver::DeleteMode mode) {
// External arrays always ignore deletes.
return obj->GetHeap()->true_value();
}
@@ -1002,10 +1006,11 @@ class DictionaryElementsAccessor
// Adjusts the length of the dictionary backing store and returns the new
// length according to ES5 section 15.4.5.2 behavior.
- static MaybeObject* SetLengthWithoutNormalize(SeededNumberDictionary* dict,
- JSArray* array,
- Object* length_object,
- uint32_t length) {
+ MUST_USE_RESULT static MaybeObject* SetLengthWithoutNormalize(
+ SeededNumberDictionary* dict,
+ JSArray* array,
+ Object* length_object,
+ uint32_t length) {
if (length == 0) {
// If the length of a slow array is reset to zero, we clear
// the array and flush backing storage. This has the added
@@ -1057,9 +1062,10 @@ class DictionaryElementsAccessor
return length_object;
}
- static MaybeObject* DeleteCommon(JSObject* obj,
- uint32_t key,
- JSReceiver::DeleteMode mode) {
+ MUST_USE_RESULT static MaybeObject* DeleteCommon(
+ JSObject* obj,
+ uint32_t key,
+ JSReceiver::DeleteMode mode) {
Isolate* isolate = obj->GetIsolate();
Heap* heap = isolate->heap();
FixedArray* backing_store = FixedArray::cast(obj->elements());
@@ -1102,12 +1108,12 @@ class DictionaryElementsAccessor
return heap->true_value();
}
- static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
- uint32_t from_start,
- FixedArrayBase* to,
- ElementsKind to_kind,
- uint32_t to_start,
- int copy_size) {
+ MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
+ uint32_t from_start,
+ FixedArrayBase* to,
+ ElementsKind to_kind,
+ uint32_t to_start,
+ int copy_size) {
switch (to_kind) {
case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
@@ -1131,16 +1137,17 @@ class DictionaryElementsAccessor
friend class ElementsAccessorBase<DictionaryElementsAccessor,
ElementsKindTraits<DICTIONARY_ELEMENTS> >;
- virtual MaybeObject* Delete(JSObject* obj,
- uint32_t key,
- JSReceiver::DeleteMode mode) {
+ MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
+ uint32_t key,
+ JSReceiver::DeleteMode mode) {
return DeleteCommon(obj, key, mode);
}
- static MaybeObject* GetImpl(Object* receiver,
- JSObject* obj,
- uint32_t key,
- SeededNumberDictionary* backing_store) {
+ MUST_USE_RESULT static MaybeObject* GetImpl(
+ Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ SeededNumberDictionary* backing_store) {
int entry = backing_store->FindEntry(key);
if (entry != SeededNumberDictionary::kNotFound) {
Object* element = backing_store->ValueAt(entry);
@@ -1186,10 +1193,10 @@ class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase<
NonStrictArgumentsElementsAccessor,
ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >;
- static MaybeObject* GetImpl(Object* receiver,
- JSObject* obj,
- uint32_t key,
- FixedArray* parameter_map) {
+ MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ FixedArray* parameter_map) {
Object* probe = GetParameterMapArg(obj, parameter_map, key);
if (!probe->IsTheHole()) {
Context* context = Context::cast(parameter_map->get(0));
@@ -1216,18 +1223,19 @@ class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase<
}
}
- static MaybeObject* SetLengthImpl(JSObject* obj,
- Object* length,
- FixedArray* parameter_map) {
+ MUST_USE_RESULT static MaybeObject* SetLengthImpl(
+ JSObject* obj,
+ Object* length,
+ FixedArray* parameter_map) {
// TODO(mstarzinger): This was never implemented but will be used once we
// correctly implement [[DefineOwnProperty]] on arrays.
UNIMPLEMENTED();
return obj;
}
- virtual MaybeObject* Delete(JSObject* obj,
- uint32_t key,
- JSReceiver::DeleteMode mode) {
+ MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
+ uint32_t key,
+ JSReceiver::DeleteMode mode) {
FixedArray* parameter_map = FixedArray::cast(obj->elements());
Object* probe = GetParameterMapArg(obj, parameter_map, key);
if (!probe->IsTheHole()) {
@@ -1246,12 +1254,12 @@ class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase<
return obj->GetHeap()->true_value();
}
- static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
- uint32_t from_start,
- FixedArrayBase* to,
- ElementsKind to_kind,
- uint32_t to_start,
- int copy_size) {
+ MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
+ uint32_t from_start,
+ FixedArrayBase* to,
+ ElementsKind to_kind,
+ uint32_t to_start,
+ int copy_size) {
FixedArray* parameter_map = FixedArray::cast(from);
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
@@ -1354,8 +1362,8 @@ void ElementsAccessor::TearDown() {
template <typename ElementsAccessorSubclass, typename ElementsKindTraits>
-MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass,
- ElementsKindTraits>::
+MUST_USE_RESULT MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass,
+ ElementsKindTraits>::
SetLengthImpl(JSObject* obj,
Object* length,
typename ElementsKindTraits::BackingStore* backing_store) {
diff --git a/src/3rdparty/v8/src/elements.h b/src/3rdparty/v8/src/elements.h
index 51d402d..55d6fa5 100644
--- a/src/3rdparty/v8/src/elements.h
+++ b/src/3rdparty/v8/src/elements.h
@@ -60,18 +60,19 @@ class ElementsAccessor {
// can optionally pass in the backing store to use for the check, which must
// be compatible with the ElementsKind of the ElementsAccessor. If
// backing_store is NULL, the holder->elements() is used as the backing store.
- virtual MaybeObject* Get(Object* receiver,
- JSObject* holder,
- uint32_t key,
- FixedArrayBase* backing_store = NULL) = 0;
+ MUST_USE_RESULT virtual MaybeObject* Get(
+ Object* receiver,
+ JSObject* holder,
+ uint32_t key,
+ FixedArrayBase* backing_store = NULL) = 0;
// Modifies the length data property as specified for JSArrays and resizes the
// underlying backing store accordingly. The method honors the semantics of
// changing array sizes as defined in EcmaScript 5.1 15.4.5.2, i.e. array that
// have non-deletable elements can only be shrunk to the size of highest
// element that is non-deletable.
- virtual MaybeObject* SetLength(JSArray* holder,
- Object* new_length) = 0;
+ MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* holder,
+ Object* new_length) = 0;
// Modifies both the length and capacity of a JSArray, resizing the underlying
// backing store as necessary. This method does NOT honor the semantics of
@@ -79,14 +80,14 @@ class ElementsAccessor {
// elements. This method should only be called for array expansion OR by
// runtime JavaScript code that use InternalArrays and don't care about
// EcmaScript 5.1 semantics.
- virtual MaybeObject* SetCapacityAndLength(JSArray* array,
- int capacity,
- int length) = 0;
+ MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(JSArray* array,
+ int capacity,
+ int length) = 0;
// Deletes an element in an object, returning a new elements backing store.
- virtual MaybeObject* Delete(JSObject* holder,
- uint32_t key,
- JSReceiver::DeleteMode mode) = 0;
+ MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* holder,
+ uint32_t key,
+ JSReceiver::DeleteMode mode) = 0;
// If kCopyToEnd is specified as the copy_size to CopyElements, it copies all
// of elements from source after source_start to the destination array.
@@ -101,26 +102,28 @@ class ElementsAccessor {
// the source JSObject or JSArray in source_holder. If the holder's backing
// store is available, it can be passed in source and source_holder is
// ignored.
- virtual MaybeObject* CopyElements(JSObject* source_holder,
- uint32_t source_start,
- FixedArrayBase* destination,
- ElementsKind destination_kind,
- uint32_t destination_start,
- int copy_size,
- FixedArrayBase* source = NULL) = 0;
-
- MaybeObject* CopyElements(JSObject* from_holder,
- FixedArrayBase* to,
- ElementsKind to_kind,
- FixedArrayBase* from = NULL) {
+ MUST_USE_RESULT virtual MaybeObject* CopyElements(
+ JSObject* source_holder,
+ uint32_t source_start,
+ FixedArrayBase* destination,
+ ElementsKind destination_kind,
+ uint32_t destination_start,
+ int copy_size,
+ FixedArrayBase* source = NULL) = 0;
+
+ MUST_USE_RESULT MaybeObject* CopyElements(JSObject* from_holder,
+ FixedArrayBase* to,
+ ElementsKind to_kind,
+ FixedArrayBase* from = NULL) {
return CopyElements(from_holder, 0, to, to_kind, 0,
kCopyToEndAndInitializeToHole, from);
}
- virtual MaybeObject* AddElementsToFixedArray(Object* receiver,
- JSObject* holder,
- FixedArray* to,
- FixedArrayBase* from = NULL) = 0;
+ MUST_USE_RESULT virtual MaybeObject* AddElementsToFixedArray(
+ Object* receiver,
+ JSObject* holder,
+ FixedArray* to,
+ FixedArrayBase* from = NULL) = 0;
// Returns a shared ElementsAccessor for the specified ElementsKind.
static ElementsAccessor* ForKind(ElementsKind elements_kind) {
diff --git a/src/3rdparty/v8/src/execution.cc b/src/3rdparty/v8/src/execution.cc
index 7e69abe..5618975 100644
--- a/src/3rdparty/v8/src/execution.cc
+++ b/src/3rdparty/v8/src/execution.cc
@@ -71,8 +71,7 @@ static Handle<Object> Invoke(bool is_construct,
Handle<Object> receiver,
int argc,
Handle<Object> args[],
- bool* has_pending_exception,
- Handle<Object> qml) {
+ bool* has_pending_exception) {
Isolate* isolate = function->GetIsolate();
// Entering JavaScript.
@@ -103,12 +102,6 @@ static Handle<Object> Invoke(bool is_construct,
// make the current one is indeed a global object.
ASSERT(function->context()->global()->IsGlobalObject());
- Handle<JSObject> oldqml;
- if (!qml.is_null()) {
- oldqml = Handle<JSObject>(function->context()->qml_global());
- function->context()->set_qml_global(JSObject::cast(*qml));
- }
-
{
// Save and restore context around invocation and block the
// allocation of handles without explicit handle scopes.
@@ -125,9 +118,6 @@ static Handle<Object> Invoke(bool is_construct,
CALL_GENERATED_CODE(stub_entry, function_entry, func, recv, argc, argv);
}
- if (!qml.is_null())
- function->context()->set_qml_global(*oldqml);
-
#ifdef DEBUG
value->Verify();
#endif
@@ -156,18 +146,7 @@ Handle<Object> Execution::Call(Handle<Object> callable,
int argc,
Handle<Object> argv[],
bool* pending_exception,
- bool convert_receiver)
-{
- return Call(callable, receiver, argc, argv, pending_exception, convert_receiver, Handle<Object>());
-}
-
-Handle<Object> Execution::Call(Handle<Object> callable,
- Handle<Object> receiver,
- int argc,
- Handle<Object> argv[],
- bool* pending_exception,
- bool convert_receiver,
- Handle<Object> qml) {
+ bool convert_receiver) {
*pending_exception = false;
if (!callable->IsJSFunction()) {
@@ -191,7 +170,7 @@ Handle<Object> Execution::Call(Handle<Object> callable,
if (*pending_exception) return callable;
}
- return Invoke(false, func, receiver, argc, argv, pending_exception, qml);
+ return Invoke(false, func, receiver, argc, argv, pending_exception);
}
@@ -200,7 +179,7 @@ Handle<Object> Execution::New(Handle<JSFunction> func,
Handle<Object> argv[],
bool* pending_exception) {
return Invoke(true, func, Isolate::Current()->global(), argc, argv,
- pending_exception, Handle<Object>());
+ pending_exception);
}
@@ -219,7 +198,7 @@ Handle<Object> Execution::TryCall(Handle<JSFunction> func,
*caught_exception = false;
Handle<Object> result = Invoke(false, func, receiver, argc, args,
- caught_exception, Handle<Object>());
+ caught_exception);
if (*caught_exception) {
ASSERT(catcher.HasCaught());
diff --git a/src/3rdparty/v8/src/execution.h b/src/3rdparty/v8/src/execution.h
index c33a675..01e4b9d 100644
--- a/src/3rdparty/v8/src/execution.h
+++ b/src/3rdparty/v8/src/execution.h
@@ -69,14 +69,6 @@ class Execution : public AllStatic {
bool* pending_exception,
bool convert_receiver = false);
- static Handle<Object> Call(Handle<Object> callable,
- Handle<Object> receiver,
- int argc,
- Handle<Object> argv[],
- bool* pending_exception,
- bool convert_receiver,
- Handle<Object> qml);
-
// Construct object from function, the caller supplies an array of
// arguments. Arguments are Object* type. After function returns,
// pointers in 'args' might be invalid.
diff --git a/src/3rdparty/v8/src/factory.cc b/src/3rdparty/v8/src/factory.cc
index ab0bb1f..6bb7893 100644
--- a/src/3rdparty/v8/src/factory.cc
+++ b/src/3rdparty/v8/src/factory.cc
@@ -291,6 +291,15 @@ Handle<Context> Factory::NewGlobalContext() {
}
+Handle<Context> Factory::NewModuleContext(Handle<Context> previous,
+ Handle<ScopeInfo> scope_info) {
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateModuleContext(*previous, *scope_info),
+ Context);
+}
+
+
Handle<Context> Factory::NewFunctionContext(int length,
Handle<JSFunction> function) {
CALL_HEAP_FUNCTION(
@@ -324,10 +333,9 @@ Handle<Context> Factory::NewWithContext(Handle<JSFunction> function,
}
-Handle<Context> Factory::NewBlockContext(
- Handle<JSFunction> function,
- Handle<Context> previous,
- Handle<ScopeInfo> scope_info) {
+Handle<Context> Factory::NewBlockContext(Handle<JSFunction> function,
+ Handle<Context> previous,
+ Handle<ScopeInfo> scope_info) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateBlockContext(*function,
@@ -928,6 +936,13 @@ Handle<JSObject> Factory::NewJSObject(Handle<JSFunction> constructor,
}
+Handle<JSModule> Factory::NewJSModule() {
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateJSModule(), JSModule);
+}
+
+
Handle<GlobalObject> Factory::NewGlobalObject(
Handle<JSFunction> constructor) {
CALL_HEAP_FUNCTION(isolate(),
@@ -1219,24 +1234,15 @@ Handle<JSFunction> Factory::CreateApiFunction(
Handle<Code> construct_stub = isolate()->builtins()->JSConstructStubApi();
int internal_field_count = 0;
- bool has_external_resource = false;
- bool use_user_object_comparison = false;
-
if (!obj->instance_template()->IsUndefined()) {
Handle<ObjectTemplateInfo> instance_template =
Handle<ObjectTemplateInfo>(
ObjectTemplateInfo::cast(obj->instance_template()));
internal_field_count =
Smi::cast(instance_template->internal_field_count())->value();
- has_external_resource =
- !instance_template->has_external_resource()->IsUndefined();
- use_user_object_comparison =
- !instance_template->use_user_object_comparison()->IsUndefined();
}
int instance_size = kPointerSize * internal_field_count;
- if (has_external_resource) instance_size += kPointerSize;
-
InstanceType type = INVALID_TYPE;
switch (instance_type) {
case JavaScriptObject:
@@ -1271,16 +1277,6 @@ Handle<JSFunction> Factory::CreateApiFunction(
Handle<Map> map = Handle<Map>(result->initial_map());
- // Mark as having external data object if needed
- if (has_external_resource) {
- map->set_has_external_resource(true);
- }
-
- // Mark as using user object comparison if needed
- if (use_user_object_comparison) {
- map->set_use_user_object_comparison(true);
- }
-
// Mark as undetectable if needed.
if (obj->undetectable()) {
map->set_is_undetectable();
@@ -1299,10 +1295,6 @@ Handle<JSFunction> Factory::CreateApiFunction(
// Set interceptor information in the map.
if (!obj->named_property_handler()->IsUndefined()) {
map->set_has_named_interceptor();
- InterceptorInfo *nph = InterceptorInfo::cast(obj->named_property_handler());
- bool is_fallback =
- nph->is_fallback()->IsUndefined()?false:nph->is_fallback()->value();
- map->set_named_interceptor_is_fallback(is_fallback);
}
if (!obj->indexed_property_handler()->IsUndefined()) {
map->set_has_indexed_interceptor();
diff --git a/src/3rdparty/v8/src/factory.h b/src/3rdparty/v8/src/factory.h
index 786d4a9..06aad1b 100644
--- a/src/3rdparty/v8/src/factory.h
+++ b/src/3rdparty/v8/src/factory.h
@@ -162,9 +162,12 @@ class Factory {
// Create a global (but otherwise uninitialized) context.
Handle<Context> NewGlobalContext();
+ // Create a module context.
+ Handle<Context> NewModuleContext(Handle<Context> previous,
+ Handle<ScopeInfo> scope_info);
+
// Create a function context.
- Handle<Context> NewFunctionContext(int length,
- Handle<JSFunction> function);
+ Handle<Context> NewFunctionContext(int length, Handle<JSFunction> function);
// Create a catch context.
Handle<Context> NewCatchContext(Handle<JSFunction> function,
@@ -177,7 +180,7 @@ class Factory {
Handle<Context> previous,
Handle<JSObject> extension);
- // Create a 'block' context.
+ // Create a block context.
Handle<Context> NewBlockContext(Handle<JSFunction> function,
Handle<Context> previous,
Handle<ScopeInfo> scope_info);
@@ -262,6 +265,9 @@ class Factory {
// runtime.
Handle<JSObject> NewJSObjectFromMap(Handle<Map> map);
+ // JS modules are pretenured.
+ Handle<JSModule> NewJSModule();
+
// JS arrays are pretenured when allocated by the parser.
Handle<JSArray> NewJSArray(int capacity,
ElementsKind elements_kind = FAST_ELEMENTS,
diff --git a/src/3rdparty/v8/src/flag-definitions.h b/src/3rdparty/v8/src/flag-definitions.h
index 904533f..ccba511 100644
--- a/src/3rdparty/v8/src/flag-definitions.h
+++ b/src/3rdparty/v8/src/flag-definitions.h
@@ -132,6 +132,8 @@ public:
// Flags for language modes and experimental language features.
DEFINE_bool(use_strict, false, "enforce strict mode")
+DEFINE_bool(es52_globals, false,
+ "activate new semantics for global var declarations")
DEFINE_bool(harmony_typeof, false, "enable harmony semantics for typeof")
DEFINE_bool(harmony_scoping, false, "enable harmony block scoping")
@@ -165,7 +167,12 @@ DEFINE_bool(eliminate_dead_phis, true, "eliminate dead phis")
DEFINE_bool(use_gvn, true, "use hydrogen global value numbering")
DEFINE_bool(use_canonicalizing, true, "use hydrogen instruction canonicalizing")
DEFINE_bool(use_inlining, true, "use function inlining")
-DEFINE_bool(limit_inlining, true, "limit code size growth from inlining")
+DEFINE_int(max_inlined_source_size, 600,
+ "maximum source size in bytes considered for a single inlining")
+DEFINE_int(max_inlined_nodes, 196,
+ "maximum number of AST nodes considered for a single inlining")
+DEFINE_int(max_inlined_nodes_cumulative, 196,
+ "maximum cumulative number of AST nodes considered for inlining")
DEFINE_bool(loop_invariant_code_motion, true, "loop invariant code motion")
DEFINE_bool(collect_megamorphic_maps_from_stub_cache,
true,
@@ -188,6 +195,10 @@ DEFINE_bool(trap_on_deopt, false, "put a break point before deoptimizing")
DEFINE_bool(deoptimize_uncommon_cases, true, "deoptimize uncommon cases")
DEFINE_bool(polymorphic_inlining, true, "polymorphic inlining")
DEFINE_bool(use_osr, true, "use on-stack replacement")
+DEFINE_bool(array_bounds_checks_elimination, true,
+ "perform array bounds checks elimination")
+DEFINE_bool(array_index_dehoisting, false,
+ "perform array index dehoisting")
DEFINE_bool(trace_osr, false, "trace on-stack replacement")
DEFINE_int(stress_runs, 0, "number of stress runs")
@@ -306,7 +317,6 @@ DEFINE_bool(trace_debug_json, false, "trace debugging JSON request/response")
DEFINE_bool(debugger_auto_break, true,
"automatically set the debug break flag when debugger commands are "
"in the queue")
-DEFINE_bool(breakpoint_relocation, true, "relocate breakpoints to the next executable line")
DEFINE_bool(enable_liveedit, true, "enable liveedit experimental feature")
DEFINE_bool(break_on_abort, true, "always cause a debug break before aborting")
@@ -404,7 +414,7 @@ DEFINE_bool(trace_exception, false,
DEFINE_bool(preallocate_message_memory, false,
"preallocate some memory to build stack traces.")
DEFINE_bool(randomize_hashes,
- false,
+ true,
"randomize hashes to avoid predictable hash collisions "
"(with snapshots this option cannot override the baked-in seed)")
DEFINE_int(hash_seed,
diff --git a/src/3rdparty/v8/src/frames.cc b/src/3rdparty/v8/src/frames.cc
index 5911284..e265341 100644
--- a/src/3rdparty/v8/src/frames.cc
+++ b/src/3rdparty/v8/src/frames.cc
@@ -1359,12 +1359,7 @@ InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
// -------------------------------------------------------------------------
int NumRegs(RegList reglist) {
- int n = 0;
- while (reglist != 0) {
- n++;
- reglist &= reglist - 1; // clear one bit
- }
- return n;
+ return CompilerIntrinsics::CountSetBits(reglist);
}
diff --git a/src/3rdparty/v8/src/frames.h b/src/3rdparty/v8/src/frames.h
index 7178bd4..78cdd0c 100644
--- a/src/3rdparty/v8/src/frames.h
+++ b/src/3rdparty/v8/src/frames.h
@@ -211,6 +211,9 @@ class StackFrame BASE_EMBEDDED {
virtual void SetCallerFp(Address caller_fp) = 0;
+ // Manually changes value of fp in this object.
+ void UpdateFp(Address fp) { state_.fp = fp; }
+
Address* pc_address() const { return state_.pc_address; }
// Get the id of this stack frame.
diff --git a/src/3rdparty/v8/src/full-codegen.cc b/src/3rdparty/v8/src/full-codegen.cc
index 522fd6f..9b1df4e 100644
--- a/src/3rdparty/v8/src/full-codegen.cc
+++ b/src/3rdparty/v8/src/full-codegen.cc
@@ -314,7 +314,8 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
code->set_optimizable(info->IsOptimizable() &&
- !info->function()->flags()->Contains(kDontOptimize));
+ !info->function()->flags()->Contains(kDontOptimize) &&
+ info->function()->scope()->AllowsLazyRecompilation());
cgen.PopulateDeoptimizationData(code);
cgen.PopulateTypeFeedbackInfo(code);
cgen.PopulateTypeFeedbackCells(code);
@@ -568,89 +569,91 @@ void FullCodeGenerator::DoTest(const TestContext* context) {
void FullCodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
- int save_global_count = global_count_;
- global_count_ = 0;
+ ZoneList<Handle<Object> >* saved_globals = globals_;
+ ZoneList<Handle<Object> > inner_globals(10);
+ globals_ = &inner_globals;
AstVisitor::VisitDeclarations(declarations);
-
- // Batch declare global functions and variables.
- if (global_count_ > 0) {
- Handle<FixedArray> array =
- isolate()->factory()->NewFixedArray(3 * global_count_, TENURED);
- int length = declarations->length();
- for (int j = 0, i = 0; i < length; i++) {
- Declaration* decl = declarations->at(i);
- Variable* var = decl->proxy()->var();
-
- if (var->IsUnallocated()) {
- array->set(j++, *(var->name()));
- FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration();
- if (fun_decl == NULL) {
- if (var->binding_needs_init()) {
- // In case this binding needs initialization use the hole.
- array->set_the_hole(j++);
- } else {
- array->set_undefined(j++);
- }
- } else {
- Handle<SharedFunctionInfo> function =
- Compiler::BuildFunctionInfo(fun_decl->fun(), script());
- // Check for stack-overflow exception.
- if (function.is_null()) {
- SetStackOverflow();
- return;
- }
- array->set(j++, *function);
- }
- array->set(j++, Smi::FromInt(var->is_qml_global()));
- }
- }
+ if (!globals_->is_empty()) {
// Invoke the platform-dependent code generator to do the actual
// declaration the global functions and variables.
+ Handle<FixedArray> array =
+ isolate()->factory()->NewFixedArray(globals_->length(), TENURED);
+ for (int i = 0; i < globals_->length(); ++i)
+ array->set(i, *globals_->at(i));
DeclareGlobals(array);
}
- global_count_ = save_global_count;
-}
-
-
-void FullCodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
- EmitDeclaration(decl->proxy(), decl->mode(), NULL);
+ globals_ = saved_globals;
}
-void FullCodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
- EmitDeclaration(decl->proxy(), decl->mode(), decl->fun());
-}
-
-
-void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* decl) {
- EmitDeclaration(decl->proxy(), decl->mode(), NULL);
-}
-
-
-void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* decl) {
- EmitDeclaration(decl->proxy(), decl->mode(), NULL);
-}
+void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) {
+ Handle<JSModule> instance = module->interface()->Instance();
+ ASSERT(!instance.is_null());
+ // Allocate a module context statically.
+ Block* block = module->body();
+ Scope* saved_scope = scope();
+ scope_ = block->scope();
+ Handle<ScopeInfo> scope_info = scope_->GetScopeInfo();
+
+ // Generate code for module creation and linking.
+ Comment cmnt(masm_, "[ ModuleLiteral");
+ SetStatementPosition(block);
+
+ if (scope_info->HasContext()) {
+ // Set up module context.
+ __ Push(scope_info);
+ __ Push(instance);
+ __ CallRuntime(Runtime::kPushModuleContext, 2);
+ StoreToFrameField(
+ StandardFrameConstants::kContextOffset, context_register());
+ }
-void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) {
- // TODO(rossberg)
-}
+ {
+ Comment cmnt(masm_, "[ Declarations");
+ VisitDeclarations(scope_->declarations());
+ }
+ scope_ = saved_scope;
+ if (scope_info->HasContext()) {
+ // Pop module context.
+ LoadContextField(context_register(), Context::PREVIOUS_INDEX);
+ // Update local stack frame context field.
+ StoreToFrameField(
+ StandardFrameConstants::kContextOffset, context_register());
+ }
-void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) {
- // TODO(rossberg)
+ // Populate module instance object.
+ const PropertyAttributes attr =
+ static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE | DONT_ENUM);
+ for (Interface::Iterator it = module->interface()->iterator();
+ !it.done(); it.Advance()) {
+ if (it.interface()->IsModule()) {
+ Handle<Object> value = it.interface()->Instance();
+ ASSERT(!value.is_null());
+ JSReceiver::SetProperty(instance, it.name(), value, attr, kStrictMode);
+ } else {
+ // TODO(rossberg): set proper getters instead of undefined...
+ // instance->DefineAccessor(*it.name(), ACCESSOR_GETTER, *getter, attr);
+ Handle<Object> value(isolate()->heap()->undefined_value());
+ JSReceiver::SetProperty(instance, it.name(), value, attr, kStrictMode);
+ }
+ }
+ USE(instance->PreventExtensions());
}
void FullCodeGenerator::VisitModuleVariable(ModuleVariable* module) {
- // TODO(rossberg)
+ // Noting to do.
+ // The instance object is resolved statically through the module's interface.
}
void FullCodeGenerator::VisitModulePath(ModulePath* module) {
- // TODO(rossberg)
+ // Noting to do.
+ // The instance object is resolved statically through the module's interface.
}
@@ -912,9 +915,9 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
Scope* saved_scope = scope();
// Push a block context when entering a block with block scoped variables.
- if (stmt->block_scope() != NULL) {
+ if (stmt->scope() != NULL) {
{ Comment cmnt(masm_, "[ Extend block context");
- scope_ = stmt->block_scope();
+ scope_ = stmt->scope();
Handle<ScopeInfo> scope_info = scope_->GetScopeInfo();
int heap_slots = scope_info->ContextLength() - Context::MIN_CONTEXT_SLOTS;
__ Push(scope_info);
@@ -941,7 +944,7 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
// Pop block context if necessary.
- if (stmt->block_scope() != NULL) {
+ if (stmt->scope() != NULL) {
LoadContextField(context_register(), Context::PREVIOUS_INDEX);
// Update local stack frame context field.
StoreToFrameField(StandardFrameConstants::kContextOffset,
diff --git a/src/3rdparty/v8/src/full-codegen.h b/src/3rdparty/v8/src/full-codegen.h
index 689abae..0e0ffe9 100644
--- a/src/3rdparty/v8/src/full-codegen.h
+++ b/src/3rdparty/v8/src/full-codegen.h
@@ -83,7 +83,7 @@ class FullCodeGenerator: public AstVisitor {
scope_(info->scope()),
nesting_stack_(NULL),
loop_depth_(0),
- global_count_(0),
+ globals_(NULL),
context_(NULL),
bailout_entries_(info->HasDeoptimizationSupport()
? info->function()->ast_node_count() : 0),
@@ -202,7 +202,7 @@ class FullCodeGenerator: public AstVisitor {
virtual ~NestedBlock() {}
virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
- if (statement()->AsBlock()->block_scope() != NULL) {
+ if (statement()->AsBlock()->scope() != NULL) {
++(*context_length);
}
return previous_;
@@ -413,12 +413,9 @@ class FullCodeGenerator: public AstVisitor {
Label* if_true,
Label* if_false);
- // Platform-specific code for a variable, constant, or function
- // declaration. Functions have an initial value.
- // Increments global_count_ for unallocated variables.
- void EmitDeclaration(VariableProxy* proxy,
- VariableMode mode,
- FunctionLiteral* function);
+ // If enabled, emit debug code for checking that the current context is
+ // neither a with nor a catch context.
+ void EmitDebugCheckDeclarationContext(Variable* variable);
// Platform-specific code for checking the stack limit at the back edge of
// a loop.
@@ -548,13 +545,8 @@ class FullCodeGenerator: public AstVisitor {
Handle<Script> script() { return info_->script(); }
bool is_eval() { return info_->is_eval(); }
bool is_native() { return info_->is_native(); }
- bool is_classic_mode() {
- return language_mode() == CLASSIC_MODE;
- }
- LanguageMode language_mode() {
- return function()->language_mode();
- }
- bool is_qml_mode() { return function()->qml_mode(); }
+ bool is_classic_mode() { return language_mode() == CLASSIC_MODE; }
+ LanguageMode language_mode() { return function()->language_mode(); }
FunctionLiteral* function() { return info_->function(); }
Scope* scope() { return scope_; }
@@ -786,7 +778,7 @@ class FullCodeGenerator: public AstVisitor {
Label return_label_;
NestedStatement* nesting_stack_;
int loop_depth_;
- int global_count_;
+ ZoneList<Handle<Object> >* globals_;
const ExpressionContext* context_;
ZoneList<BailoutEntry> bailout_entries_;
ZoneList<BailoutEntry> stack_checks_;
diff --git a/src/3rdparty/v8/src/globals.h b/src/3rdparty/v8/src/globals.h
index 790c6bf..97b033f 100644
--- a/src/3rdparty/v8/src/globals.h
+++ b/src/3rdparty/v8/src/globals.h
@@ -345,6 +345,9 @@ F FUNCTION_CAST(Address addr) {
#define INLINE(header) inline __attribute__((always_inline)) header
#define NO_INLINE(header) __attribute__((noinline)) header
#endif
+#elif defined(_MSC_VER) && !defined(DEBUG)
+#define INLINE(header) __forceinline header
+#define NO_INLINE(header) header
#else
#define INLINE(header) inline header
#define NO_INLINE(header) header
@@ -396,12 +399,6 @@ enum StrictModeFlag {
kStrictMode
};
-// The QML Compilation Mode
-enum QmlModeFlag {
- kNonQmlMode,
- kQmlMode
-};
-
} } // namespace v8::internal
diff --git a/src/3rdparty/v8/src/handles.cc b/src/3rdparty/v8/src/handles.cc
index 416ecbd..def1604 100644
--- a/src/3rdparty/v8/src/handles.cc
+++ b/src/3rdparty/v8/src/handles.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -729,9 +729,9 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate);
for (int i = 0; i < descs->number_of_descriptors(); i++) {
- if (descs->IsProperty(i) && !descs->IsDontEnum(i)) {
+ if (descs->IsProperty(i) && !descs->GetDetails(i).IsDontEnum()) {
storage->set(index, descs->GetKey(i));
- PropertyDetails details(descs->GetDetails(i));
+ PropertyDetails details = descs->GetDetails(i);
sort_array->set(index, Smi::FromInt(details.index()));
if (!indices.is_null()) {
if (details.type() != FIELD) {
diff --git a/src/3rdparty/v8/src/hashmap.h b/src/3rdparty/v8/src/hashmap.h
index 5aeb895..91843b8 100644
--- a/src/3rdparty/v8/src/hashmap.h
+++ b/src/3rdparty/v8/src/hashmap.h
@@ -63,7 +63,9 @@ class TemplateHashMapImpl {
Entry* Lookup(void* key, uint32_t hash, bool insert);
// Removes the entry with matching key.
- void Remove(void* key, uint32_t hash);
+ // It returns the value of the deleted entry
+ // or null if there is no value for such key.
+ void* Remove(void* key, uint32_t hash);
// Empties the hash map (occupancy() == 0).
void Clear();
@@ -146,14 +148,15 @@ typename TemplateHashMapImpl<P>::Entry* TemplateHashMapImpl<P>::Lookup(
template<class P>
-void TemplateHashMapImpl<P>::Remove(void* key, uint32_t hash) {
+void* TemplateHashMapImpl<P>::Remove(void* key, uint32_t hash) {
// Lookup the entry for the key to remove.
Entry* p = Probe(key, hash);
if (p->key == NULL) {
// Key not found nothing to remove.
- return;
+ return NULL;
}
+ void* value = p->value;
// To remove an entry we need to ensure that it does not create an empty
// entry that will cause the search for another entry to stop too soon. If all
// the entries between the entry to remove and the next empty slot have their
@@ -202,6 +205,7 @@ void TemplateHashMapImpl<P>::Remove(void* key, uint32_t hash) {
// Clear the entry which is allowed to en emptied.
p->key = NULL;
occupancy_--;
+ return value;
}
diff --git a/src/3rdparty/v8/src/heap-inl.h b/src/3rdparty/v8/src/heap-inl.h
index 72acf3d..e12895a 100644
--- a/src/3rdparty/v8/src/heap-inl.h
+++ b/src/3rdparty/v8/src/heap-inl.h
@@ -127,7 +127,6 @@ MaybeObject* Heap::AllocateAsciiSymbol(Vector<const char> str,
String* answer = String::cast(result);
answer->set_length(str.length());
answer->set_hash_field(hash_field);
- SeqString::cast(answer)->set_symbol_id(0);
ASSERT_EQ(size, answer->Size());
@@ -161,7 +160,6 @@ MaybeObject* Heap::AllocateTwoByteSymbol(Vector<const uc16> str,
String* answer = String::cast(result);
answer->set_length(str.length());
answer->set_hash_field(hash_field);
- SeqString::cast(answer)->set_symbol_id(0);
ASSERT_EQ(size, answer->Size());
@@ -246,33 +244,18 @@ MaybeObject* Heap::NumberFromUint32(
}
-void Heap::FinalizeExternalString(HeapObject* string) {
- ASSERT(string->IsExternalString() || string->map()->has_external_resource());
-
- if (string->IsExternalString()) {
- v8::String::ExternalStringResourceBase** resource_addr =
- reinterpret_cast<v8::String::ExternalStringResourceBase**>(
- reinterpret_cast<byte*>(string) +
- ExternalString::kResourceOffset -
- kHeapObjectTag);
+void Heap::FinalizeExternalString(String* string) {
+ ASSERT(string->IsExternalString());
+ v8::String::ExternalStringResourceBase** resource_addr =
+ reinterpret_cast<v8::String::ExternalStringResourceBase**>(
+ reinterpret_cast<byte*>(string) +
+ ExternalString::kResourceOffset -
+ kHeapObjectTag);
- // Dispose of the C++ object if it has not already been disposed.
- if (*resource_addr != NULL) {
- (*resource_addr)->Dispose();
- *resource_addr = NULL;
- }
- } else {
- JSObject *object = JSObject::cast(string);
- Object *value = object->GetExternalResourceObject();
- v8::Object::ExternalResource *resource = 0;
- if (value->IsSmi()) {
- resource = reinterpret_cast<v8::Object::ExternalResource*>(Internals::GetExternalPointerFromSmi(value));
- } else if (value->IsForeign()) {
- resource = reinterpret_cast<v8::Object::ExternalResource*>(Foreign::cast(value)->foreign_address());
- }
- if (resource) {
- resource->Dispose();
- }
+ // Dispose of the C++ object if it has not already been disposed.
+ if (*resource_addr != NULL) {
+ (*resource_addr)->Dispose();
+ *resource_addr = NULL;
}
}
@@ -477,15 +460,16 @@ MaybeObject* Heap::PrepareForCompare(String* str) {
}
-int Heap::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) {
+intptr_t Heap::AdjustAmountOfExternalAllocatedMemory(
+ intptr_t change_in_bytes) {
ASSERT(HasBeenSetUp());
- int amount = amount_of_external_allocated_memory_ + change_in_bytes;
+ intptr_t amount = amount_of_external_allocated_memory_ + change_in_bytes;
if (change_in_bytes >= 0) {
// Avoid overflow.
if (amount > amount_of_external_allocated_memory_) {
amount_of_external_allocated_memory_ = amount;
}
- int amount_since_last_global_gc =
+ intptr_t amount_since_last_global_gc =
amount_of_external_allocated_memory_ -
amount_of_external_allocated_memory_at_last_global_gc_;
if (amount_since_last_global_gc > external_allocation_limit_) {
@@ -594,16 +578,6 @@ void ExternalStringTable::AddString(String* string) {
}
-void ExternalStringTable::AddObject(HeapObject* object) {
- ASSERT(object->map()->has_external_resource());
- if (heap_->InNewSpace(object)) {
- new_space_strings_.Add(object);
- } else {
- old_space_strings_.Add(object);
- }
-}
-
-
void ExternalStringTable::Iterate(ObjectVisitor* v) {
if (!new_space_strings_.is_empty()) {
Object** start = &new_space_strings_[0];
@@ -632,14 +606,14 @@ void ExternalStringTable::Verify() {
}
-void ExternalStringTable::AddOldObject(HeapObject* object) {
- ASSERT(object->IsExternalString() || object->map()->has_external_resource());
- ASSERT(!heap_->InNewSpace(object));
- old_space_strings_.Add(object);
+void ExternalStringTable::AddOldString(String* string) {
+ ASSERT(string->IsExternalString());
+ ASSERT(!heap_->InNewSpace(string));
+ old_space_strings_.Add(string);
}
-void ExternalStringTable::ShrinkNewObjects(int position) {
+void ExternalStringTable::ShrinkNewStrings(int position) {
new_space_strings_.Rewind(position);
if (FLAG_verify_heap) {
Verify();
diff --git a/src/3rdparty/v8/src/heap-profiler.cc b/src/3rdparty/v8/src/heap-profiler.cc
index 8be6f27..2e971a5 100644
--- a/src/3rdparty/v8/src/heap-profiler.cc
+++ b/src/3rdparty/v8/src/heap-profiler.cc
@@ -33,7 +33,6 @@
namespace v8 {
namespace internal {
-
HeapProfiler::HeapProfiler()
: snapshots_(new HeapSnapshotsCollection()),
next_snapshot_uid_(1) {
@@ -86,6 +85,24 @@ HeapSnapshot* HeapProfiler::TakeSnapshot(String* name,
}
+void HeapProfiler::StartHeapObjectsTracking() {
+ ASSERT(Isolate::Current()->heap_profiler() != NULL);
+ Isolate::Current()->heap_profiler()->StartHeapObjectsTrackingImpl();
+}
+
+
+void HeapProfiler::StopHeapObjectsTracking() {
+ ASSERT(Isolate::Current()->heap_profiler() != NULL);
+ Isolate::Current()->heap_profiler()->StopHeapObjectsTrackingImpl();
+}
+
+
+void HeapProfiler::PushHeapObjectsStats(v8::OutputStream* stream) {
+ ASSERT(Isolate::Current()->heap_profiler() != NULL);
+ return Isolate::Current()->heap_profiler()->PushHeapObjectsStatsImpl(stream);
+}
+
+
void HeapProfiler::DefineWrapperClass(
uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback) {
ASSERT(class_id != v8::HeapProfiler::kPersistentHandleNoClassId);
@@ -136,6 +153,20 @@ HeapSnapshot* HeapProfiler::TakeSnapshotImpl(String* name,
return TakeSnapshotImpl(snapshots_->names()->GetName(name), type, control);
}
+void HeapProfiler::StartHeapObjectsTrackingImpl() {
+ snapshots_->StartHeapObjectsTracking();
+}
+
+
+void HeapProfiler::PushHeapObjectsStatsImpl(OutputStream* stream) {
+ snapshots_->PushHeapObjectsStats(stream);
+}
+
+
+void HeapProfiler::StopHeapObjectsTrackingImpl() {
+ snapshots_->StopHeapObjectsTracking();
+}
+
int HeapProfiler::GetSnapshotsCount() {
HeapProfiler* profiler = Isolate::Current()->heap_profiler();
@@ -158,6 +189,15 @@ HeapSnapshot* HeapProfiler::FindSnapshot(unsigned uid) {
}
+SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) {
+ if (!obj->IsHeapObject())
+ return v8::HeapProfiler::kUnknownObjectId;
+ HeapProfiler* profiler = Isolate::Current()->heap_profiler();
+ ASSERT(profiler != NULL);
+ return profiler->snapshots_->FindObjectId(HeapObject::cast(*obj)->address());
+}
+
+
void HeapProfiler::DeleteAllSnapshots() {
HeapProfiler* profiler = Isolate::Current()->heap_profiler();
ASSERT(profiler != NULL);
diff --git a/src/3rdparty/v8/src/heap-profiler.h b/src/3rdparty/v8/src/heap-profiler.h
index ef5c4f4..96b042d 100644
--- a/src/3rdparty/v8/src/heap-profiler.h
+++ b/src/3rdparty/v8/src/heap-profiler.h
@@ -44,8 +44,6 @@ class HeapSnapshotsCollection;
} \
} while (false)
-// The HeapProfiler writes data to the log files, which can be postprocessed
-// to generate .hp files for use by the GHC/Valgrind tool hp2ps.
class HeapProfiler {
public:
static void SetUp();
@@ -57,9 +55,14 @@ class HeapProfiler {
static HeapSnapshot* TakeSnapshot(String* name,
int type,
v8::ActivityControl* control);
+
+ static void StartHeapObjectsTracking();
+ static void StopHeapObjectsTracking();
+ static void PushHeapObjectsStats(OutputStream* stream);
static int GetSnapshotsCount();
static HeapSnapshot* GetSnapshot(int index);
static HeapSnapshot* FindSnapshot(unsigned uid);
+ static SnapshotObjectId GetSnapshotObjectId(Handle<Object> obj);
static void DeleteAllSnapshots();
void ObjectMoveEvent(Address from, Address to);
@@ -84,6 +87,10 @@ class HeapProfiler {
v8::ActivityControl* control);
void ResetSnapshots();
+ void StartHeapObjectsTrackingImpl();
+ void StopHeapObjectsTrackingImpl();
+ void PushHeapObjectsStatsImpl(OutputStream* stream);
+
HeapSnapshotsCollection* snapshots_;
unsigned next_snapshot_uid_;
List<v8::HeapProfiler::WrapperInfoCallback> wrapper_callbacks_;
diff --git a/src/3rdparty/v8/src/heap.cc b/src/3rdparty/v8/src/heap.cc
index 797bb15..d3c7f0a 100644
--- a/src/3rdparty/v8/src/heap.cc
+++ b/src/3rdparty/v8/src/heap.cc
@@ -171,6 +171,9 @@ Heap::Heap()
global_contexts_list_ = NULL;
mark_compact_collector_.heap_ = this;
external_string_table_.heap_ = this;
+ // Put a dummy entry in the remembered pages so we can find the list the
+ // minidump even if there are no real unmapped pages.
+ RememberUnmappedPage(NULL, false);
}
@@ -238,12 +241,17 @@ int Heap::GcSafeSizeOfOldObject(HeapObject* object) {
GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space,
const char** reason) {
// Is global GC requested?
- if (space != NEW_SPACE || FLAG_gc_global) {
+ if (space != NEW_SPACE) {
isolate_->counters()->gc_compactor_caused_by_request()->Increment();
*reason = "GC in old space requested";
return MARK_COMPACTOR;
}
+ if (FLAG_gc_global || (FLAG_stress_compaction && (gc_count_ & 1) != 0)) {
+ *reason = "GC in old space forced by flags";
+ return MARK_COMPACTOR;
+ }
+
// Is enough data promoted to justify a global GC?
if (OldGenerationPromotionLimitReached()) {
isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment();
@@ -800,7 +808,7 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector,
UpdateSurvivalRateTrend(start_new_space_size);
- size_of_old_gen_at_last_old_space_gc_ = PromotedSpaceSize();
+ size_of_old_gen_at_last_old_space_gc_ = PromotedSpaceSizeOfObjects();
if (high_survival_rate_during_scavenges &&
IsStableOrIncreasingSurvivalTrend()) {
@@ -1124,6 +1132,27 @@ void PromotionQueue::RelocateQueueHead() {
}
+class ScavengeWeakObjectRetainer : public WeakObjectRetainer {
+ public:
+ explicit ScavengeWeakObjectRetainer(Heap* heap) : heap_(heap) { }
+
+ virtual Object* RetainAs(Object* object) {
+ if (!heap_->InFromSpace(object)) {
+ return object;
+ }
+
+ MapWord map_word = HeapObject::cast(object)->map_word();
+ if (map_word.IsForwardingAddress()) {
+ return map_word.ToForwardingAddress();
+ }
+ return NULL;
+ }
+
+ private:
+ Heap* heap_;
+};
+
+
void Heap::Scavenge() {
#ifdef DEBUG
if (FLAG_verify_heap) VerifyNonPointerSpacePointers();
@@ -1222,6 +1251,9 @@ void Heap::Scavenge() {
}
incremental_marking()->UpdateMarkingDequeAfterScavenge();
+ ScavengeWeakObjectRetainer weak_object_retainer(this);
+ ProcessWeakReferences(&weak_object_retainer);
+
ASSERT(new_space_front == new_space_.top());
// Set age mark.
@@ -1242,18 +1274,18 @@ void Heap::Scavenge() {
}
-HeapObject* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
- Object** p) {
+String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
+ Object** p) {
MapWord first_word = HeapObject::cast(*p)->map_word();
if (!first_word.IsForwardingAddress()) {
// Unreachable external string can be finalized.
- heap->FinalizeExternalString(HeapObject::cast(*p));
+ heap->FinalizeExternalString(String::cast(*p));
return NULL;
}
// String is still reachable.
- return HeapObject::cast(first_word.ToForwardingAddress());
+ return String::cast(first_word.ToForwardingAddress());
}
@@ -1271,11 +1303,11 @@ void Heap::UpdateNewSpaceReferencesInExternalStringTable(
for (Object** p = start; p < end; ++p) {
ASSERT(InFromSpace(*p));
- HeapObject* target = updater_func(this, p);
+ String* target = updater_func(this, p);
if (target == NULL) continue;
- ASSERT(target->IsExternalString() || target->map()->has_external_resource());
+ ASSERT(target->IsExternalString());
if (InNewSpace(target)) {
// String is still in new space. Update the table entry.
@@ -1283,12 +1315,12 @@ void Heap::UpdateNewSpaceReferencesInExternalStringTable(
++last;
} else {
// String got promoted. Move it to the old string list.
- external_string_table_.AddOldObject(target);
+ external_string_table_.AddOldString(target);
}
}
ASSERT(last <= end);
- external_string_table_.ShrinkNewObjects(static_cast<int>(last - start));
+ external_string_table_.ShrinkNewStrings(static_cast<int>(last - start));
}
@@ -1308,7 +1340,8 @@ void Heap::UpdateReferencesInExternalStringTable(
static Object* ProcessFunctionWeakReferences(Heap* heap,
Object* function,
- WeakObjectRetainer* retainer) {
+ WeakObjectRetainer* retainer,
+ bool record_slots) {
Object* undefined = heap->undefined_value();
Object* head = undefined;
JSFunction* tail = NULL;
@@ -1325,6 +1358,12 @@ static Object* ProcessFunctionWeakReferences(Heap* heap,
// Subsequent elements in the list.
ASSERT(tail != NULL);
tail->set_next_function_link(retain);
+ if (record_slots) {
+ Object** next_function =
+ HeapObject::RawField(tail, JSFunction::kNextFunctionLinkOffset);
+ heap->mark_compact_collector()->RecordSlot(
+ next_function, next_function, retain);
+ }
}
// Retained function is new tail.
candidate_function = reinterpret_cast<JSFunction*>(retain);
@@ -1353,6 +1392,15 @@ void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
Object* head = undefined;
Context* tail = NULL;
Object* candidate = global_contexts_list_;
+
+ // We don't record weak slots during marking or scavenges.
+ // Instead we do it once when we complete mark-compact cycle.
+ // Note that write barrier has no effect if we are already in the middle of
+ // compacting mark-sweep cycle and we have to record slots manually.
+ bool record_slots =
+ gc_state() == MARK_COMPACT &&
+ mark_compact_collector()->is_compacting();
+
while (candidate != undefined) {
// Check whether to keep the candidate in the list.
Context* candidate_context = reinterpret_cast<Context*>(candidate);
@@ -1368,6 +1416,14 @@ void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
Context::NEXT_CONTEXT_LINK,
retain,
UPDATE_WRITE_BARRIER);
+
+ if (record_slots) {
+ Object** next_context =
+ HeapObject::RawField(
+ tail, FixedArray::SizeFor(Context::NEXT_CONTEXT_LINK));
+ mark_compact_collector()->RecordSlot(
+ next_context, next_context, retain);
+ }
}
// Retained context is new tail.
candidate_context = reinterpret_cast<Context*>(retain);
@@ -1380,11 +1436,19 @@ void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
ProcessFunctionWeakReferences(
this,
candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST),
- retainer);
+ retainer,
+ record_slots);
candidate_context->set_unchecked(this,
Context::OPTIMIZED_FUNCTIONS_LIST,
function_list_head,
UPDATE_WRITE_BARRIER);
+ if (record_slots) {
+ Object** optimized_functions =
+ HeapObject::RawField(
+ tail, FixedArray::SizeFor(Context::OPTIMIZED_FUNCTIONS_LIST));
+ mark_compact_collector()->RecordSlot(
+ optimized_functions, optimized_functions, function_list_head);
+ }
}
// Move to next element in the list.
@@ -1484,6 +1548,27 @@ Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
}
+STATIC_ASSERT((FixedDoubleArray::kHeaderSize & kDoubleAlignmentMask) == 0);
+
+
+INLINE(static HeapObject* EnsureDoubleAligned(Heap* heap,
+ HeapObject* object,
+ int size));
+
+static HeapObject* EnsureDoubleAligned(Heap* heap,
+ HeapObject* object,
+ int size) {
+ if ((OffsetFrom(object->address()) & kDoubleAlignmentMask) != 0) {
+ heap->CreateFillerObjectAt(object->address(), kPointerSize);
+ return HeapObject::FromAddress(object->address() + kPointerSize);
+ } else {
+ heap->CreateFillerObjectAt(object->address() + size - kPointerSize,
+ kPointerSize);
+ return object;
+ }
+}
+
+
enum LoggingAndProfiling {
LOGGING_AND_PROFILING_ENABLED,
LOGGING_AND_PROFILING_DISABLED
@@ -1607,7 +1692,10 @@ class ScavengingVisitor : public StaticVisitorBase {
}
}
- template<ObjectContents object_contents, SizeRestriction size_restriction>
+
+ template<ObjectContents object_contents,
+ SizeRestriction size_restriction,
+ int alignment>
static inline void EvacuateObject(Map* map,
HeapObject** slot,
HeapObject* object,
@@ -1616,19 +1704,26 @@ class ScavengingVisitor : public StaticVisitorBase {
(object_size <= Page::kMaxNonCodeHeapObjectSize));
SLOW_ASSERT(object->Size() == object_size);
+ int allocation_size = object_size;
+ if (alignment != kObjectAlignment) {
+ ASSERT(alignment == kDoubleAlignment);
+ allocation_size += kPointerSize;
+ }
+
Heap* heap = map->GetHeap();
if (heap->ShouldBePromoted(object->address(), object_size)) {
MaybeObject* maybe_result;
if ((size_restriction != SMALL) &&
- (object_size > Page::kMaxNonCodeHeapObjectSize)) {
- maybe_result = heap->lo_space()->AllocateRaw(object_size,
+ (allocation_size > Page::kMaxNonCodeHeapObjectSize)) {
+ maybe_result = heap->lo_space()->AllocateRaw(allocation_size,
NOT_EXECUTABLE);
} else {
if (object_contents == DATA_OBJECT) {
- maybe_result = heap->old_data_space()->AllocateRaw(object_size);
+ maybe_result = heap->old_data_space()->AllocateRaw(allocation_size);
} else {
- maybe_result = heap->old_pointer_space()->AllocateRaw(object_size);
+ maybe_result =
+ heap->old_pointer_space()->AllocateRaw(allocation_size);
}
}
@@ -1636,6 +1731,10 @@ class ScavengingVisitor : public StaticVisitorBase {
if (maybe_result->ToObject(&result)) {
HeapObject* target = HeapObject::cast(result);
+ 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.
@@ -1643,18 +1742,27 @@ class ScavengingVisitor : public StaticVisitorBase {
MigrateObject(heap, object, target, object_size);
if (object_contents == POINTER_OBJECT) {
- heap->promotion_queue()->insert(target, object_size);
+ if (map->instance_type() == JS_FUNCTION_TYPE) {
+ heap->promotion_queue()->insert(
+ target, JSFunction::kNonWeakFieldsEndOffset);
+ } else {
+ heap->promotion_queue()->insert(target, object_size);
+ }
}
heap->tracer()->increment_promoted_objects_size(object_size);
return;
}
}
- MaybeObject* allocation = heap->new_space()->AllocateRaw(object_size);
+ MaybeObject* allocation = heap->new_space()->AllocateRaw(allocation_size);
heap->promotion_queue()->SetNewLimit(heap->new_space()->top());
Object* result = allocation->ToObjectUnchecked();
HeapObject* target = HeapObject::cast(result);
+ 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.
@@ -1690,7 +1798,7 @@ class ScavengingVisitor : public StaticVisitorBase {
HeapObject** slot,
HeapObject* object) {
int object_size = FixedArray::BodyDescriptor::SizeOf(map, object);
- EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE>(map,
+ EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(map,
slot,
object,
object_size);
@@ -1702,10 +1810,11 @@ class ScavengingVisitor : public StaticVisitorBase {
HeapObject* object) {
int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
int object_size = FixedDoubleArray::SizeFor(length);
- EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map,
- slot,
- object,
- object_size);
+ EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kDoubleAlignment>(
+ map,
+ slot,
+ object,
+ object_size);
}
@@ -1713,7 +1822,8 @@ class ScavengingVisitor : public StaticVisitorBase {
HeapObject** slot,
HeapObject* object) {
int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize();
- EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map, slot, object, object_size);
+ EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
+ map, slot, object, object_size);
}
@@ -1722,7 +1832,8 @@ class ScavengingVisitor : public StaticVisitorBase {
HeapObject* object) {
int object_size = SeqAsciiString::cast(object)->
SeqAsciiStringSize(map->instance_type());
- EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map, slot, object, object_size);
+ EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
+ map, slot, object, object_size);
}
@@ -1731,7 +1842,8 @@ class ScavengingVisitor : public StaticVisitorBase {
HeapObject* object) {
int object_size = SeqTwoByteString::cast(object)->
SeqTwoByteStringSize(map->instance_type());
- EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map, slot, object, object_size);
+ EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
+ map, slot, object, object_size);
}
@@ -1774,7 +1886,8 @@ class ScavengingVisitor : public StaticVisitorBase {
}
int object_size = ConsString::kSize;
- EvacuateObject<POINTER_OBJECT, SMALL>(map, slot, object, object_size);
+ EvacuateObject<POINTER_OBJECT, SMALL, kObjectAlignment>(
+ map, slot, object, object_size);
}
template<ObjectContents object_contents>
@@ -1784,14 +1897,16 @@ class ScavengingVisitor : public StaticVisitorBase {
static inline void VisitSpecialized(Map* map,
HeapObject** slot,
HeapObject* object) {
- EvacuateObject<object_contents, SMALL>(map, slot, object, object_size);
+ EvacuateObject<object_contents, SMALL, kObjectAlignment>(
+ map, slot, object, object_size);
}
static inline void Visit(Map* map,
HeapObject** slot,
HeapObject* object) {
int object_size = map->instance_size();
- EvacuateObject<object_contents, SMALL>(map, slot, object, object_size);
+ EvacuateObject<object_contents, SMALL, kObjectAlignment>(
+ map, slot, object, object_size);
}
};
@@ -1908,7 +2023,7 @@ MaybeObject* Heap::AllocateMap(InstanceType instance_type,
map->set_pre_allocated_property_fields(0);
map->init_instance_descriptors();
map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
- map->set_prototype_transitions(empty_fixed_array(), SKIP_WRITE_BARRIER);
+ map->init_prototype_transitions(undefined_value());
map->set_unused_property_fields(0);
map->set_bit_field(0);
map->set_bit_field2(1 << Map::kIsExtensible);
@@ -2047,15 +2162,15 @@ bool Heap::CreateInitialMaps() {
// Fix the instance_descriptors for the existing maps.
meta_map()->init_instance_descriptors();
meta_map()->set_code_cache(empty_fixed_array());
- meta_map()->set_prototype_transitions(empty_fixed_array());
+ meta_map()->init_prototype_transitions(undefined_value());
fixed_array_map()->init_instance_descriptors();
fixed_array_map()->set_code_cache(empty_fixed_array());
- fixed_array_map()->set_prototype_transitions(empty_fixed_array());
+ fixed_array_map()->init_prototype_transitions(undefined_value());
oddball_map()->init_instance_descriptors();
oddball_map()->set_code_cache(empty_fixed_array());
- oddball_map()->set_prototype_transitions(empty_fixed_array());
+ oddball_map()->init_prototype_transitions(undefined_value());
// Fix prototype object for existing maps.
meta_map()->set_prototype(null_value());
@@ -3827,6 +3942,16 @@ MaybeObject* Heap::AllocateJSObject(JSFunction* constructor,
}
+MaybeObject* Heap::AllocateJSModule() {
+ // Allocate a fresh map. Modules do not have a prototype.
+ Map* map;
+ MaybeObject* maybe_map = AllocateMap(JS_MODULE_TYPE, JSModule::kSize);
+ if (!maybe_map->To(&map)) return maybe_map;
+ // Allocate the object based on the map.
+ return AllocateJSObjectFromMap(map, TENURED);
+}
+
+
MaybeObject* Heap::AllocateJSArrayAndStorage(
ElementsKind elements_kind,
int length,
@@ -3963,7 +4088,7 @@ MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
// Fill these accessors into the dictionary.
DescriptorArray* descs = map->instance_descriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
- PropertyDetails details(descs->GetDetails(i));
+ PropertyDetails details = descs->GetDetails(i);
ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
PropertyDetails d =
PropertyDetails(details.attributes(), CALLBACKS, details.index());
@@ -4314,7 +4439,6 @@ MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
String* answer = String::cast(result);
answer->set_length(chars);
answer->set_hash_field(hash_field);
- SeqString::cast(answer)->set_symbol_id(0);
ASSERT_EQ(size, answer->Size());
@@ -4365,7 +4489,6 @@ MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
HeapObject::cast(result)->set_map_no_write_barrier(ascii_string_map());
String::cast(result)->set_length(length);
String::cast(result)->set_hash_field(String::kEmptyHashField);
- SeqString::cast(result)->set_symbol_id(0);
ASSERT_EQ(size, HeapObject::cast(result)->Size());
return result;
}
@@ -4402,7 +4525,6 @@ MaybeObject* Heap::AllocateRawTwoByteString(int length,
HeapObject::cast(result)->set_map_no_write_barrier(string_map());
String::cast(result)->set_length(length);
String::cast(result)->set_hash_field(String::kEmptyHashField);
- SeqString::cast(result)->set_symbol_id(0);
ASSERT_EQ(size, HeapObject::cast(result)->Size());
return result;
}
@@ -4659,6 +4781,11 @@ MaybeObject* Heap::AllocateRawFixedDoubleArray(int length,
AllocationSpace space =
(pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
int size = FixedDoubleArray::SizeFor(length);
+
+#ifndef V8_HOST_ARCH_64_BIT
+ size += kPointerSize;
+#endif
+
if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
// Too big for new space.
space = LO_SPACE;
@@ -4671,7 +4798,12 @@ MaybeObject* Heap::AllocateRawFixedDoubleArray(int length,
AllocationSpace retry_space =
(size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_DATA_SPACE : LO_SPACE;
- return AllocateRaw(size, space, retry_space);
+ HeapObject* object;
+ { MaybeObject* maybe_object = AllocateRaw(size, space, retry_space);
+ if (!maybe_object->To<HeapObject>(&object)) return maybe_object;
+ }
+
+ return EnsureDoubleAligned(this, object, size);
}
@@ -4704,6 +4836,22 @@ MaybeObject* Heap::AllocateGlobalContext() {
}
+MaybeObject* Heap::AllocateModuleContext(Context* previous,
+ ScopeInfo* scope_info) {
+ Object* result;
+ { MaybeObject* maybe_result =
+ AllocateFixedArrayWithHoles(scope_info->ContextLength(), TENURED);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ Context* context = reinterpret_cast<Context*>(result);
+ context->set_map_no_write_barrier(module_context_map());
+ context->set_previous(previous);
+ context->set_extension(scope_info);
+ context->set_global(previous->global());
+ return context;
+}
+
+
MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
Object* result;
@@ -4716,7 +4864,6 @@ MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
context->set_previous(function->context());
context->set_extension(NULL);
context->set_global(function->context()->global());
- context->set_qml_global(function->context()->qml_global());
return context;
}
@@ -4737,7 +4884,6 @@ MaybeObject* Heap::AllocateCatchContext(JSFunction* function,
context->set_previous(previous);
context->set_extension(name);
context->set_global(previous->global());
- context->set_qml_global(previous->qml_global());
context->set(Context::THROWN_OBJECT_INDEX, thrown_object);
return context;
}
@@ -4756,7 +4902,6 @@ MaybeObject* Heap::AllocateWithContext(JSFunction* function,
context->set_previous(previous);
context->set_extension(extension);
context->set_global(previous->global());
- context->set_qml_global(previous->qml_global());
return context;
}
@@ -4775,7 +4920,6 @@ MaybeObject* Heap::AllocateBlockContext(JSFunction* function,
context->set_previous(previous);
context->set_extension(scope_info);
context->set_global(previous->global());
- context->set_qml_global(previous->qml_global());
return context;
}
@@ -4850,8 +4994,10 @@ void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) {
bool Heap::IdleNotification(int hint) {
const int kMaxHint = 1000;
- intptr_t size_factor = Min(Max(hint, 30), kMaxHint) / 10;
- // The size factor is in range [3..100].
+ intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4;
+ // The size factor is in range [5..250]. The numbers here are chosen from
+ // experiments. If you changes them, make sure to test with
+ // chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.*
intptr_t step_size = size_factor * IncrementalMarking::kAllocatedThreshold;
if (contexts_disposed_ > 0) {
@@ -4875,11 +5021,14 @@ bool Heap::IdleNotification(int hint) {
// Take into account that we might have decided to delay full collection
// because incremental marking is in progress.
ASSERT((contexts_disposed_ == 0) || !incremental_marking()->IsStopped());
+ // After context disposal there is likely a lot of garbage remaining, reset
+ // the idle notification counters in order to trigger more incremental GCs
+ // on subsequent idle notifications.
+ StartIdleRound();
return false;
}
- if (hint >= kMaxHint || !FLAG_incremental_marking ||
- FLAG_expose_gc || Serializer::enabled()) {
+ if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) {
return IdleGlobalGC();
}
@@ -4918,10 +5067,6 @@ bool Heap::IdleNotification(int hint) {
}
if (incremental_marking()->IsStopped()) {
- if (!WorthStartingGCWhenIdle()) {
- FinishIdleRound();
- return true;
- }
incremental_marking()->Start();
}
@@ -5559,6 +5704,11 @@ bool Heap::ConfigureHeap(int max_semispace_size,
intptr_t max_executable_size) {
if (HasBeenSetUp()) return false;
+ if (FLAG_stress_compaction) {
+ // This will cause more frequent GCs when stressing.
+ max_semispace_size_ = Page::kPageSize;
+ }
+
if (max_semispace_size > 0) {
if (max_semispace_size < Page::kPageSize) {
max_semispace_size = Page::kPageSize;
@@ -5663,16 +5813,6 @@ void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
}
-intptr_t Heap::PromotedSpaceSize() {
- return old_pointer_space_->Size()
- + old_data_space_->Size()
- + code_space_->Size()
- + map_space_->Size()
- + cell_space_->Size()
- + lo_space_->Size();
-}
-
-
intptr_t Heap::PromotedSpaceSizeOfObjects() {
return old_pointer_space_->SizeOfObjects()
+ old_data_space_->SizeOfObjects()
@@ -5683,7 +5823,7 @@ intptr_t Heap::PromotedSpaceSizeOfObjects() {
}
-int Heap::PromotedExternalMemorySize() {
+intptr_t Heap::PromotedExternalMemorySize() {
if (amount_of_external_allocated_memory_
<= amount_of_external_allocated_memory_at_last_global_gc_) return 0;
return amount_of_external_allocated_memory_
@@ -5995,6 +6135,11 @@ void Heap::SetStackLimits() {
void Heap::TearDown() {
+#ifdef DEBUG
+ if (FLAG_verify_heap) {
+ Verify();
+ }
+#endif
if (FLAG_print_cumulative_gc_stat) {
PrintF("\n\n");
PrintF("gc_count=%d ", gc_count_);
@@ -6920,19 +7065,6 @@ void ExternalStringTable::CleanUp() {
void ExternalStringTable::TearDown() {
- for (int i = 0; i < new_space_strings_.length(); ++i) {
- if (new_space_strings_[i] == heap_->raw_unchecked_null_value()) continue;
- HeapObject *object = HeapObject::cast(new_space_strings_[i]);
- if (!object->IsExternalString())
- heap_->FinalizeExternalString(object);
- }
- for (int i = 0; i < old_space_strings_.length(); ++i) {
- if (old_space_strings_[i] == heap_->raw_unchecked_null_value()) continue;
- HeapObject *object = HeapObject::cast(old_space_strings_[i]);
- if (!object->IsExternalString())
- heap_->FinalizeExternalString(object);
- }
-
new_space_strings_.Free();
old_space_strings_.Free();
}
diff --git a/src/3rdparty/v8/src/heap.h b/src/3rdparty/v8/src/heap.h
index 68fcc4a..beb1bc5 100644
--- a/src/3rdparty/v8/src/heap.h
+++ b/src/3rdparty/v8/src/heap.h
@@ -197,7 +197,6 @@ namespace internal {
V(string_symbol, "string") \
V(String_symbol, "String") \
V(Date_symbol, "Date") \
- V(Error_symbol, "Error") \
V(this_symbol, "this") \
V(to_string_symbol, "toString") \
V(char_at_symbol, "CharAt") \
@@ -244,7 +243,8 @@ namespace internal {
V(compare_ic_symbol, ".compare_ic") \
V(infinity_symbol, "Infinity") \
V(minus_infinity_symbol, "-Infinity") \
- V(hidden_stack_trace_symbol, "v8::hidden_stack_trace")
+ V(hidden_stack_trace_symbol, "v8::hidden_stack_trace") \
+ V(query_colon_symbol, "(?:)")
// Forward declarations.
class GCTracer;
@@ -253,8 +253,8 @@ class Isolate;
class WeakObjectRetainer;
-typedef HeapObject* (*ExternalStringTableUpdaterCallback)(Heap* heap,
- Object** pointer);
+typedef String* (*ExternalStringTableUpdaterCallback)(Heap* heap,
+ Object** pointer);
class StoreBufferRebuilder {
public:
@@ -390,14 +390,10 @@ typedef void (*ScavengingCallback)(Map* map,
// External strings table is a place where all external strings are
// registered. We need to keep track of such strings to properly
// finalize them.
-// The ExternalStringTable can contain both strings and objects with
-// external resources. It was not renamed to make the patch simpler.
class ExternalStringTable {
public:
// Registers an external string.
inline void AddString(String* string);
- // Registers an external object.
- inline void AddObject(HeapObject* string);
inline void Iterate(ObjectVisitor* v);
@@ -415,10 +411,10 @@ class ExternalStringTable {
inline void Verify();
- inline void AddOldObject(HeapObject* string);
+ inline void AddOldString(String* string);
// Notifies the table that only a prefix of the new list is valid.
- inline void ShrinkNewObjects(int position);
+ inline void ShrinkNewStrings(int position);
// To speed up scavenge collections new space string are kept
// separate from old space strings.
@@ -534,6 +530,8 @@ class Heap {
MUST_USE_RESULT MaybeObject* AllocateJSObject(
JSFunction* constructor, PretenureFlag pretenure = NOT_TENURED);
+ MUST_USE_RESULT MaybeObject* AllocateJSModule();
+
// Allocate a JSArray with no elements
MUST_USE_RESULT MaybeObject* AllocateEmptyJSArray(
ElementsKind elements_kind,
@@ -825,6 +823,10 @@ class Heap {
// Allocate a global (but otherwise uninitialized) context.
MUST_USE_RESULT MaybeObject* AllocateGlobalContext();
+ // Allocate a module context.
+ MUST_USE_RESULT MaybeObject* AllocateModuleContext(Context* previous,
+ ScopeInfo* scope_info);
+
// Allocate a function context.
MUST_USE_RESULT MaybeObject* AllocateFunctionContext(int length,
JSFunction* function);
@@ -958,7 +960,7 @@ class Heap {
// Finalizes an external string by deleting the associated external
// data and clearing the resource pointer.
- inline void FinalizeExternalString(HeapObject* string);
+ inline void FinalizeExternalString(String* string);
// Allocates an uninitialized object. The memory is non-executable if the
// hardware and OS allow.
@@ -1331,7 +1333,8 @@ class Heap {
// Adjusts the amount of registered external memory.
// Returns the adjusted value.
- inline int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes);
+ inline intptr_t AdjustAmountOfExternalAllocatedMemory(
+ intptr_t change_in_bytes);
// Allocate uninitialized fixed array.
MUST_USE_RESULT MaybeObject* AllocateRawFixedArray(int length);
@@ -1339,7 +1342,7 @@ class Heap {
PretenureFlag pretenure);
inline intptr_t PromotedTotalSize() {
- return PromotedSpaceSize() + PromotedExternalMemorySize();
+ return PromotedSpaceSizeOfObjects() + PromotedExternalMemorySize();
}
// True if we have reached the allocation limit in the old generation that
@@ -1360,19 +1363,6 @@ class Heap {
static const intptr_t kMinimumAllocationLimit =
8 * (Page::kPageSize > MB ? Page::kPageSize : MB);
- // When we sweep lazily we initially guess that there is no garbage on the
- // heap and set the limits for the next GC accordingly. As we sweep we find
- // out that some of the pages contained garbage and we have to adjust
- // downwards the size of the heap. This means the limits that control the
- // timing of the next GC also need to be adjusted downwards.
- void LowerOldGenLimits(intptr_t adjustment) {
- size_of_old_gen_at_last_old_space_gc_ -= adjustment;
- old_gen_promotion_limit_ =
- OldGenPromotionLimit(size_of_old_gen_at_last_old_space_gc_);
- old_gen_allocation_limit_ =
- OldGenAllocationLimit(size_of_old_gen_at_last_old_space_gc_);
- }
-
intptr_t OldGenPromotionLimit(intptr_t old_gen_size) {
const int divisor = FLAG_stress_compaction ? 10 : 3;
intptr_t limit =
@@ -1416,6 +1406,12 @@ class Heap {
kRootListLength
};
+ STATIC_CHECK(kUndefinedValueRootIndex == Internals::kUndefinedValueRootIndex);
+ STATIC_CHECK(kNullValueRootIndex == Internals::kNullValueRootIndex);
+ STATIC_CHECK(kTrueValueRootIndex == Internals::kTrueValueRootIndex);
+ STATIC_CHECK(kFalseValueRootIndex == Internals::kFalseValueRootIndex);
+ STATIC_CHECK(kempty_symbolRootIndex == Internals::kEmptySymbolRootIndex);
+
MUST_USE_RESULT MaybeObject* NumberToString(
Object* number, bool check_number_string_cache = true);
MUST_USE_RESULT MaybeObject* Uint32ToString(
@@ -1447,6 +1443,8 @@ class Heap {
inline bool NextGCIsLikelyToBeFull() {
if (FLAG_gc_global) return true;
+ if (FLAG_stress_compaction && (gc_count_ & 1) != 0) return true;
+
intptr_t total_promoted = PromotedTotalSize();
intptr_t adjusted_promotion_limit =
@@ -1457,7 +1455,7 @@ class Heap {
intptr_t adjusted_allocation_limit =
old_gen_allocation_limit_ - new_space_.Capacity() / 5;
- if (PromotedSpaceSize() >= adjusted_allocation_limit) return true;
+ if (PromotedSpaceSizeOfObjects() >= adjusted_allocation_limit) return true;
return false;
}
@@ -1495,7 +1493,6 @@ class Heap {
GCTracer* tracer() { return tracer_; }
// Returns the size of objects residing in non new spaces.
- intptr_t PromotedSpaceSize();
intptr_t PromotedSpaceSizeOfObjects();
double total_regexp_code_generated() { return total_regexp_code_generated_; }
@@ -1610,6 +1607,8 @@ class Heap {
// more expedient to get at the isolate directly from within Heap methods.
Isolate* isolate_;
+ Object* roots_[kRootListLength];
+
intptr_t code_range_size_;
int reserved_semispace_size_;
int max_semispace_size_;
@@ -1651,7 +1650,7 @@ class Heap {
int gc_post_processing_depth_;
// Returns the amount of external memory registered since last global gc.
- int PromotedExternalMemorySize();
+ intptr_t PromotedExternalMemorySize();
int ms_count_; // how many mark-sweep collections happened
unsigned int gc_count_; // how many gc happened
@@ -1716,17 +1715,15 @@ class Heap {
// The amount of external memory registered through the API kept alive
// by global handles
- int amount_of_external_allocated_memory_;
+ intptr_t amount_of_external_allocated_memory_;
// Caches the amount of external memory registered at the last global gc.
- int amount_of_external_allocated_memory_at_last_global_gc_;
+ intptr_t amount_of_external_allocated_memory_at_last_global_gc_;
// Indicates that an allocation has failed in the old generation since the
// last GC.
int old_gen_exhausted_;
- Object* roots_[kRootListLength];
-
Object* global_contexts_list_;
StoreBufferRebuilder store_buffer_rebuilder_;
@@ -1850,7 +1847,7 @@ class Heap {
// Performs a minor collection in new generation.
void Scavenge();
- static HeapObject* UpdateNewSpaceReferenceInExternalStringTableEntry(
+ static String* UpdateNewSpaceReferenceInExternalStringTableEntry(
Heap* heap,
Object** pointer);
@@ -1979,13 +1976,6 @@ class Heap {
return (scavenges_since_last_idle_round_ >= kIdleScavengeThreshold);
}
- bool WorthStartingGCWhenIdle() {
- if (contexts_disposed_ > 0) {
- return true;
- }
- return incremental_marking()->WorthActivating();
- }
-
// Estimates how many milliseconds a Mark-Sweep would take to complete.
// In idle notification handler we assume that this function will return:
// - a number less than 10 for small heaps, which are less than 8Mb.
diff --git a/src/3rdparty/v8/src/hydrogen-instructions.cc b/src/3rdparty/v8/src/hydrogen-instructions.cc
index 287fe38..c66a7a1 100644
--- a/src/3rdparty/v8/src/hydrogen-instructions.cc
+++ b/src/3rdparty/v8/src/hydrogen-instructions.cc
@@ -416,6 +416,7 @@ void HValue::Kill() {
SetFlag(kIsDead);
for (int i = 0; i < OperandCount(); ++i) {
HValue* operand = OperandAt(i);
+ if (operand == NULL) continue;
HUseListNode* first = operand->use_list_;
if (first != NULL && first->value() == this && first->index() == i) {
operand->use_list_ = first->tail();
@@ -462,7 +463,8 @@ void HValue::PrintChangesTo(StringStream* stream) {
add_comma = true; \
stream->Add(#type); \
}
- GVN_FLAG_LIST(PRINT_DO);
+ GVN_TRACKED_FLAG_LIST(PRINT_DO);
+ GVN_UNTRACKED_FLAG_LIST(PRINT_DO);
#undef PRINT_DO
}
stream->Add("]");
@@ -599,6 +601,9 @@ void HInstruction::InsertAfter(HInstruction* previous) {
SetBlock(block);
previous->next_ = this;
if (next != NULL) next->previous_ = this;
+ if (block->last() == previous) {
+ block->set_last(this);
+ }
}
@@ -608,6 +613,7 @@ void HInstruction::Verify() {
HBasicBlock* cur_block = block();
for (int i = 0; i < OperandCount(); ++i) {
HValue* other_operand = OperandAt(i);
+ if (other_operand == NULL) continue;
HBasicBlock* other_block = other_operand->block();
if (cur_block == other_block) {
if (!other_operand->IsPhi()) {
@@ -679,11 +685,6 @@ void HCallNamed::PrintDataTo(StringStream* stream) {
}
-void HGlobalObject::PrintDataTo(StringStream* stream) {
- stream->Add("qml_global: %s ", qml_global()?"true":"false");
- HUnaryOperation::PrintDataTo(stream);
-}
-
void HCallGlobal::PrintDataTo(StringStream* stream) {
stream->Add("%o ", *name());
HUnaryCall::PrintDataTo(stream);
@@ -871,6 +872,17 @@ HValue* HBitwise::Canonicalize() {
}
+HValue* HBitNot::Canonicalize() {
+ // Optimize ~~x, a common pattern used for ToInt32(x).
+ if (value()->IsBitNot()) {
+ HValue* result = HBitNot::cast(value())->value();
+ ASSERT(result->representation().IsInteger32());
+ return result;
+ }
+ return this;
+}
+
+
HValue* HAdd::Canonicalize() {
if (!representation().IsInteger32()) return this;
if (CheckUsesForFlag(kTruncatingToInt32)) ClearFlag(kCanOverflow);
@@ -921,6 +933,62 @@ void HJSArrayLength::PrintDataTo(StringStream* stream) {
}
+HValue* HUnaryMathOperation::Canonicalize() {
+ if (op() == kMathFloor) {
+ // If the input is integer32 then we replace the floor instruction
+ // with its input. This happens before the representation changes are
+ // introduced.
+ if (value()->representation().IsInteger32()) return value();
+
+#ifdef V8_TARGET_ARCH_ARM
+ if (value()->IsDiv() && (value()->UseCount() == 1)) {
+ // TODO(2038): Implement this optimization for non ARM architectures.
+ HDiv* hdiv = HDiv::cast(value());
+ HValue* left = hdiv->left();
+ HValue* right = hdiv->right();
+ // Try to simplify left and right values of the division.
+ HValue* new_left =
+ LChunkBuilder::SimplifiedDividendForMathFloorOfDiv(left);
+ HValue* new_right =
+ LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(right);
+
+ // Return if left or right are not optimizable.
+ if ((new_left == NULL) || (new_right == NULL)) return this;
+
+ // Insert the new values in the graph.
+ if (new_left->IsInstruction() &&
+ !HInstruction::cast(new_left)->IsLinked()) {
+ HInstruction::cast(new_left)->InsertBefore(this);
+ }
+ if (new_right->IsInstruction() &&
+ !HInstruction::cast(new_right)->IsLinked()) {
+ HInstruction::cast(new_right)->InsertBefore(this);
+ }
+ HMathFloorOfDiv* instr = new HMathFloorOfDiv(context(),
+ new_left,
+ new_right);
+ // Replace this HMathFloor instruction by the new HMathFloorOfDiv.
+ instr->InsertBefore(this);
+ ReplaceAllUsesWith(instr);
+ Kill();
+ // We know the division had no other uses than this HMathFloor. Delete it.
+ // Also delete the arguments of the division if they are not used any
+ // more.
+ hdiv->DeleteAndReplaceWith(NULL);
+ ASSERT(left->IsChange() || left->IsConstant());
+ ASSERT(right->IsChange() || right->IsConstant());
+ if (left->HasNoUses()) left->DeleteAndReplaceWith(NULL);
+ if (right->HasNoUses()) right->DeleteAndReplaceWith(NULL);
+
+ // Return NULL to remove this instruction from the graph.
+ return NULL;
+ }
+#endif // V8_TARGET_ARCH_ARM
+ }
+ return this;
+}
+
+
HValue* HCheckInstanceType::Canonicalize() {
if (check_ == IS_STRING &&
!value()->type().IsUninitialized() &&
@@ -1535,6 +1603,7 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context,
SetOperandAt(1, object);
set_representation(Representation::Tagged());
SetGVNFlag(kDependsOnMaps);
+ int map_transitions = 0;
for (int i = 0;
i < types->length() && types_.length() < kMaxLoadPolymorphism;
++i) {
@@ -1556,13 +1625,20 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context,
case CONSTANT_FUNCTION:
types_.Add(types->at(i));
break;
+ case MAP_TRANSITION:
+ // We should just ignore these since they are not relevant to a load
+ // operation. This means we will deopt if we actually see this map
+ // from optimized code.
+ map_transitions++;
+ break;
default:
break;
}
}
}
- if (types_.length() == types->length() && FLAG_deoptimize_uncommon_cases) {
+ if (types_.length() + map_transitions == types->length() &&
+ FLAG_deoptimize_uncommon_cases) {
SetFlag(kUseGVN);
} else {
SetAllSideEffects();
@@ -1738,6 +1814,9 @@ void HStoreNamedField::PrintDataTo(StringStream* stream) {
stream->Add(" = ");
value()->PrintNameTo(stream);
stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : "");
+ if (NeedsWriteBarrier()) {
+ stream->Add(" (write-barrier)");
+ }
if (!transition().is_null()) {
stream->Add(" (transition map %p)", *transition());
}
@@ -2091,6 +2170,17 @@ HValue* HAdd::EnsureAndPropagateNotMinusZero(BitVector* visited) {
}
+bool HStoreKeyedFastDoubleElement::NeedsCanonicalization() {
+ // If value was loaded from unboxed double backing store or
+ // converted from an integer then we don't have to canonicalize it.
+ if (value()->IsLoadKeyedFastDoubleElement() ||
+ (value()->IsChange() && HChange::cast(value())->from().IsInteger32())) {
+ return false;
+ }
+ return true;
+}
+
+
#define H_CONSTANT_INT32(val) \
new(zone) HConstant(FACTORY->NewNumberFromInt(val, TENURED), \
Representation::Integer32())
@@ -2259,6 +2349,13 @@ void HIn::PrintDataTo(StringStream* stream) {
}
+void HBitwise::PrintDataTo(StringStream* stream) {
+ stream->Add(Token::Name(op_));
+ stream->Add(" ");
+ HBitwiseBinaryOperation::PrintDataTo(stream);
+}
+
+
Representation HPhi::InferredRepresentation() {
bool double_occurred = false;
bool int32_occurred = false;
diff --git a/src/3rdparty/v8/src/hydrogen-instructions.h b/src/3rdparty/v8/src/hydrogen-instructions.h
index 3854330..4f21db7 100644
--- a/src/3rdparty/v8/src/hydrogen-instructions.h
+++ b/src/3rdparty/v8/src/hydrogen-instructions.h
@@ -140,6 +140,7 @@ class LChunkBuilder;
V(LoadNamedField) \
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
+ V(MathFloorOfDiv) \
V(Mod) \
V(Mul) \
V(ObjectLiteral) \
@@ -188,7 +189,10 @@ class LChunkBuilder;
V(DateField) \
V(WrapReceiver)
-#define GVN_FLAG_LIST(V) \
+#define GVN_TRACKED_FLAG_LIST(V) \
+ V(NewSpacePromotion)
+
+#define GVN_UNTRACKED_FLAG_LIST(V) \
V(Calls) \
V(InobjectFields) \
V(BackingStoreFields) \
@@ -506,14 +510,18 @@ class HUseIterator BASE_EMBEDDED {
// There must be one corresponding kDepends flag for every kChanges flag and
// the order of the kChanges flags must be exactly the same as of the kDepends
-// flags.
+// flags. All tracked flags should appear before untracked ones.
enum GVNFlag {
// Declare global value numbering flags.
#define DECLARE_FLAG(type) kChanges##type, kDependsOn##type,
- GVN_FLAG_LIST(DECLARE_FLAG)
+ GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
+ GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
#undef DECLARE_FLAG
kAfterLastFlag,
- kLastFlag = kAfterLastFlag - 1
+ kLastFlag = kAfterLastFlag - 1,
+#define COUNT_FLAG(type) + 1
+ kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG)
+#undef COUNT_FLAG
};
typedef EnumSet<GVNFlag> GVNFlagSet;
@@ -530,6 +538,10 @@ class HValue: public ZoneObject {
// implement DataEquals(), which will be used to determine if other
// occurrences of the instruction are indeed the same.
kUseGVN,
+ // Track instructions that are dominating side effects. If an instruction
+ // sets this flag, it must implement SetSideEffectDominator() and should
+ // indicate which side effects to track by setting GVN flags.
+ kTrackSideEffectDominators,
kCanOverflow,
kBailoutOnMinusZero,
kCanBeDivByZero,
@@ -544,6 +556,12 @@ class HValue: public ZoneObject {
static const int kChangesToDependsFlagsLeftShift = 1;
+ static GVNFlag ChangesFlagFromInt(int x) {
+ return static_cast<GVNFlag>(x * 2);
+ }
+ static GVNFlag DependsOnFlagFromInt(int x) {
+ return static_cast<GVNFlag>(x * 2 + 1);
+ }
static GVNFlagSet ConvertChangesToDependsFlags(GVNFlagSet flags) {
return GVNFlagSet(flags.ToIntegral() << kChangesToDependsFlagsLeftShift);
}
@@ -726,6 +744,13 @@ class HValue: public ZoneObject {
virtual HType CalculateInferredType();
+ // This function must be overridden for instructions which have the
+ // kTrackSideEffectDominators flag set, to track instructions that are
+ // dominating side effects.
+ virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) {
+ UNREACHABLE();
+ }
+
#ifdef DEBUG
virtual void Verify() = 0;
#endif
@@ -756,7 +781,8 @@ class HValue: public ZoneObject {
GVNFlagSet result;
// Create changes mask.
#define ADD_FLAG(type) result.Add(kDependsOn##type);
- GVN_FLAG_LIST(ADD_FLAG)
+ GVN_TRACKED_FLAG_LIST(ADD_FLAG)
+ GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
#undef ADD_FLAG
return result;
}
@@ -765,7 +791,8 @@ class HValue: public ZoneObject {
GVNFlagSet result;
// Create changes mask.
#define ADD_FLAG(type) result.Add(kChanges##type);
- GVN_FLAG_LIST(ADD_FLAG)
+ GVN_TRACKED_FLAG_LIST(ADD_FLAG)
+ GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
#undef ADD_FLAG
return result;
}
@@ -781,6 +808,7 @@ class HValue: public ZoneObject {
// an executing program (i.e. are not safe to repeat, move or remove);
static GVNFlagSet AllObservableSideEffectsFlagSet() {
GVNFlagSet result = AllChangesFlagSet();
+ result.Remove(kChangesNewSpacePromotion);
result.Remove(kChangesElementsKind);
result.Remove(kChangesElementsPointer);
result.Remove(kChangesMaps);
@@ -1196,6 +1224,7 @@ class HChange: public HUnaryOperation {
SetFlag(kUseGVN);
if (deoptimize_on_undefined) SetFlag(kDeoptimizeOnUndefined);
if (is_truncating) SetFlag(kTruncatingToInt32);
+ if (to.IsTagged()) SetGVNFlag(kChangesNewSpacePromotion);
}
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
@@ -1321,6 +1350,7 @@ class HStackCheck: public HTemplateInstruction<1> {
HStackCheck(HValue* context, Type type) : type_(type) {
SetOperandAt(0, context);
+ SetGVNFlag(kChangesNewSpacePromotion);
}
HValue* context() { return OperandAt(0); }
@@ -1354,13 +1384,15 @@ class HEnterInlined: public HTemplateInstruction<0> {
FunctionLiteral* function,
CallKind call_kind,
bool is_construct,
- Variable* arguments)
+ Variable* arguments_var,
+ ZoneList<HValue*>* arguments_values)
: closure_(closure),
arguments_count_(arguments_count),
function_(function),
call_kind_(call_kind),
is_construct_(is_construct),
- arguments_(arguments) {
+ arguments_var_(arguments_var),
+ arguments_values_(arguments_values) {
}
virtual void PrintDataTo(StringStream* stream);
@@ -1375,7 +1407,8 @@ class HEnterInlined: public HTemplateInstruction<0> {
return Representation::None();
}
- Variable* arguments() { return arguments_; }
+ Variable* arguments_var() { return arguments_var_; }
+ ZoneList<HValue*>* arguments_values() { return arguments_values_; }
DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
@@ -1385,19 +1418,28 @@ class HEnterInlined: public HTemplateInstruction<0> {
FunctionLiteral* function_;
CallKind call_kind_;
bool is_construct_;
- Variable* arguments_;
+ Variable* arguments_var_;
+ ZoneList<HValue*>* arguments_values_;
};
class HLeaveInlined: public HTemplateInstruction<0> {
public:
- HLeaveInlined() {}
+ explicit HLeaveInlined(bool arguments_pushed)
+ : arguments_pushed_(arguments_pushed) { }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
}
+ bool arguments_pushed() {
+ return arguments_pushed_;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
+
+ private:
+ bool arguments_pushed_;
};
@@ -1508,30 +1550,19 @@ class HDeclareGlobals: public HUnaryOperation {
class HGlobalObject: public HUnaryOperation {
public:
- explicit HGlobalObject(HValue* context) : HUnaryOperation(context), qml_global_(false) {
+ explicit HGlobalObject(HValue* context) : HUnaryOperation(context) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
}
- virtual void PrintDataTo(StringStream* stream);
-
DECLARE_CONCRETE_INSTRUCTION(GlobalObject)
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
- bool qml_global() { return qml_global_; }
- void set_qml_global(bool v) { qml_global_ = v; }
-
protected:
- virtual bool DataEquals(HValue* other) {
- HGlobalObject* o = HGlobalObject::cast(other);
- return o->qml_global_ == qml_global_;
- }
-
- private:
- bool qml_global_;
+ virtual bool DataEquals(HValue* other) { return true; }
};
@@ -1616,14 +1647,26 @@ class HInvokeFunction: public HBinaryCall {
: HBinaryCall(context, function, argument_count) {
}
+ HInvokeFunction(HValue* context,
+ HValue* function,
+ Handle<JSFunction> known_function,
+ int argument_count)
+ : HBinaryCall(context, function, argument_count),
+ known_function_(known_function) {
+ }
+
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
HValue* context() { return first(); }
HValue* function() { return second(); }
+ Handle<JSFunction> known_function() { return known_function_; }
DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
+
+ private:
+ Handle<JSFunction> known_function_;
};
@@ -1711,7 +1754,7 @@ class HCallFunction: public HBinaryCall {
class HCallGlobal: public HUnaryCall {
public:
HCallGlobal(HValue* context, Handle<String> name, int argument_count)
- : HUnaryCall(context, argument_count), name_(name), qml_global_(false) {
+ : HUnaryCall(context, argument_count), name_(name) {
}
virtual void PrintDataTo(StringStream* stream);
@@ -1723,14 +1766,10 @@ class HCallGlobal: public HUnaryCall {
return Representation::Tagged();
}
- bool qml_global() { return qml_global_; }
- void set_qml_global(bool v) { qml_global_ = v; }
-
DECLARE_CONCRETE_INSTRUCTION(CallGlobal)
private:
Handle<String> name_;
- bool qml_global_;
};
@@ -1880,6 +1919,8 @@ class HBitNot: public HUnaryOperation {
}
virtual HType CalculateInferredType();
+ virtual HValue* Canonicalize();
+
DECLARE_CONCRETE_INSTRUCTION(BitNot)
protected:
@@ -1902,6 +1943,7 @@ class HUnaryMathOperation: public HTemplateInstruction<2> {
case kMathAbs:
set_representation(Representation::Tagged());
SetFlag(kFlexibleRepresentation);
+ SetGVNFlag(kChangesNewSpacePromotion);
break;
case kMathSqrt:
case kMathPowHalf:
@@ -1910,6 +1952,7 @@ class HUnaryMathOperation: public HTemplateInstruction<2> {
case kMathCos:
case kMathTan:
set_representation(Representation::Double());
+ SetGVNFlag(kChangesNewSpacePromotion);
break;
default:
UNREACHABLE();
@@ -1950,15 +1993,7 @@ class HUnaryMathOperation: public HTemplateInstruction<2> {
}
}
- virtual HValue* Canonicalize() {
- // If the input is integer32 then we replace the floor instruction
- // with its inputs. This happens before the representation changes are
- // introduced.
- if (op() == kMathFloor) {
- if (value()->representation().IsInteger32()) return value();
- }
- return this;
- }
+ virtual HValue* Canonicalize();
BuiltinFunctionId op() const { return op_; }
const char* OpName() const;
@@ -2592,7 +2627,7 @@ class HApplyArguments: public HTemplateInstruction<4> {
class HArgumentsElements: public HTemplateInstruction<0> {
public:
- HArgumentsElements() {
+ explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
// The value produced by this instruction is a pointer into the stack
// that looks as if it was a smi because of alignment.
set_representation(Representation::Tagged());
@@ -2605,8 +2640,12 @@ class HArgumentsElements: public HTemplateInstruction<0> {
return Representation::None();
}
+ bool from_inlined() const { return from_inlined_; }
+
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ bool from_inlined_;
};
@@ -2712,6 +2751,25 @@ class HBitwiseBinaryOperation: public HBinaryOperation {
};
+class HMathFloorOfDiv: public HBinaryOperation {
+ public:
+ HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
+ : HBinaryOperation(context, left, right) {
+ set_representation(Representation::Integer32());
+ SetFlag(kUseGVN);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Integer32();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
+
+ protected:
+ virtual bool DataEquals(HValue* other) { return true; }
+};
+
+
class HArithmeticBinaryOperation: public HBinaryOperation {
public:
HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right)
@@ -3126,6 +3184,7 @@ class HPower: public HTemplateInstruction<2> {
SetOperandAt(1, right);
set_representation(Representation::Double());
SetFlag(kUseGVN);
+ SetGVNFlag(kChangesNewSpacePromotion);
}
HValue* left() { return OperandAt(0); }
@@ -3325,6 +3384,8 @@ class HBitwise: public HBitwiseBinaryOperation {
HValue* left,
HValue* right);
+ virtual void PrintDataTo(StringStream* stream);
+
DECLARE_CONCRETE_INSTRUCTION(Bitwise)
protected:
@@ -3572,6 +3633,12 @@ inline bool StoringValueNeedsWriteBarrier(HValue* value) {
}
+inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
+ HValue* new_space_dominator) {
+ return !object->IsAllocateObject() || (object != new_space_dominator);
+}
+
+
class HStoreGlobalCell: public HUnaryOperation {
public:
HStoreGlobalCell(HValue* value,
@@ -3879,15 +3946,27 @@ class HLoadFunctionPrototype: public HUnaryOperation {
virtual bool DataEquals(HValue* other) { return true; }
};
+class ArrayInstructionInterface {
+ public:
+ virtual HValue* GetKey() = 0;
+ virtual void SetKey(HValue* key) = 0;
+ virtual void SetIndexOffset(uint32_t index_offset) = 0;
+ virtual bool IsDehoisted() = 0;
+ virtual void SetDehoisted(bool is_dehoisted) = 0;
+ virtual ~ArrayInstructionInterface() { };
+};
-class HLoadKeyedFastElement: public HTemplateInstruction<2> {
+class HLoadKeyedFastElement
+ : public HTemplateInstruction<2>, public ArrayInstructionInterface {
public:
enum HoleCheckMode { PERFORM_HOLE_CHECK, OMIT_HOLE_CHECK };
HLoadKeyedFastElement(HValue* obj,
HValue* key,
HoleCheckMode hole_check_mode = PERFORM_HOLE_CHECK)
- : hole_check_mode_(hole_check_mode) {
+ : hole_check_mode_(hole_check_mode),
+ index_offset_(0),
+ is_dehoisted_(false) {
SetOperandAt(0, obj);
SetOperandAt(1, key);
set_representation(Representation::Tagged());
@@ -3897,6 +3976,12 @@ class HLoadKeyedFastElement: public HTemplateInstruction<2> {
HValue* object() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
+ uint32_t index_offset() { return index_offset_; }
+ void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
+ HValue* GetKey() { return key(); }
+ void SetKey(HValue* key) { SetOperandAt(1, key); }
+ bool IsDehoisted() { return is_dehoisted_; }
+ void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
virtual Representation RequiredInputRepresentation(int index) {
// The key is supposed to be Integer32.
@@ -3915,17 +4000,23 @@ class HLoadKeyedFastElement: public HTemplateInstruction<2> {
virtual bool DataEquals(HValue* other) {
if (!other->IsLoadKeyedFastElement()) return false;
HLoadKeyedFastElement* other_load = HLoadKeyedFastElement::cast(other);
+ if (is_dehoisted_ && index_offset_ != other_load->index_offset_)
+ return false;
return hole_check_mode_ == other_load->hole_check_mode_;
}
private:
HoleCheckMode hole_check_mode_;
+ uint32_t index_offset_;
+ bool is_dehoisted_;
};
-class HLoadKeyedFastDoubleElement: public HTemplateInstruction<2> {
+class HLoadKeyedFastDoubleElement
+ : public HTemplateInstruction<2>, public ArrayInstructionInterface {
public:
- HLoadKeyedFastDoubleElement(HValue* elements, HValue* key) {
+ HLoadKeyedFastDoubleElement(HValue* elements, HValue* key)
+ : index_offset_(0), is_dehoisted_(false) {
SetOperandAt(0, elements);
SetOperandAt(1, key);
set_representation(Representation::Double());
@@ -3935,6 +4026,12 @@ class HLoadKeyedFastDoubleElement: public HTemplateInstruction<2> {
HValue* elements() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
+ uint32_t index_offset() { return index_offset_; }
+ void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
+ HValue* GetKey() { return key(); }
+ void SetKey(HValue* key) { SetOperandAt(1, key); }
+ bool IsDehoisted() { return is_dehoisted_; }
+ void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
virtual Representation RequiredInputRepresentation(int index) {
// The key is supposed to be Integer32.
@@ -3949,15 +4046,22 @@ class HLoadKeyedFastDoubleElement: public HTemplateInstruction<2> {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ uint32_t index_offset_;
+ bool is_dehoisted_;
};
-class HLoadKeyedSpecializedArrayElement: public HTemplateInstruction<2> {
+class HLoadKeyedSpecializedArrayElement
+ : public HTemplateInstruction<2>, public ArrayInstructionInterface {
public:
HLoadKeyedSpecializedArrayElement(HValue* external_elements,
HValue* key,
ElementsKind elements_kind)
- : elements_kind_(elements_kind) {
+ : elements_kind_(elements_kind),
+ index_offset_(0),
+ is_dehoisted_(false) {
SetOperandAt(0, external_elements);
SetOperandAt(1, key);
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
@@ -3985,6 +4089,12 @@ class HLoadKeyedSpecializedArrayElement: public HTemplateInstruction<2> {
HValue* external_pointer() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
ElementsKind elements_kind() const { return elements_kind_; }
+ uint32_t index_offset() { return index_offset_; }
+ void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
+ HValue* GetKey() { return key(); }
+ void SetKey(HValue* key) { SetOperandAt(1, key); }
+ bool IsDehoisted() { return is_dehoisted_; }
+ void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
virtual Range* InferRange(Zone* zone);
@@ -4000,6 +4110,8 @@ class HLoadKeyedSpecializedArrayElement: public HTemplateInstruction<2> {
private:
ElementsKind elements_kind_;
+ uint32_t index_offset_;
+ bool is_dehoisted_;
};
@@ -4038,9 +4150,12 @@ class HStoreNamedField: public HTemplateInstruction<2> {
int offset)
: name_(name),
is_in_object_(in_object),
- offset_(offset) {
+ offset_(offset),
+ new_space_dominator_(NULL) {
SetOperandAt(0, obj);
SetOperandAt(1, val);
+ SetFlag(kTrackSideEffectDominators);
+ SetGVNFlag(kDependsOnNewSpacePromotion);
if (is_in_object_) {
SetGVNFlag(kChangesInobjectFields);
} else {
@@ -4053,6 +4168,10 @@ class HStoreNamedField: public HTemplateInstruction<2> {
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
+ virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) {
+ ASSERT(side_effect == kChangesNewSpacePromotion);
+ new_space_dominator_ = dominator;
+ }
virtual void PrintDataTo(StringStream* stream);
HValue* object() { return OperandAt(0); }
@@ -4063,9 +4182,11 @@ class HStoreNamedField: public HTemplateInstruction<2> {
int offset() const { return offset_; }
Handle<Map> transition() const { return transition_; }
void set_transition(Handle<Map> map) { transition_ = map; }
+ HValue* new_space_dominator() const { return new_space_dominator_; }
bool NeedsWriteBarrier() {
- return StoringValueNeedsWriteBarrier(value());
+ return StoringValueNeedsWriteBarrier(value()) &&
+ ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator());
}
private:
@@ -4073,6 +4194,7 @@ class HStoreNamedField: public HTemplateInstruction<2> {
bool is_in_object_;
int offset_;
Handle<Map> transition_;
+ HValue* new_space_dominator_;
};
@@ -4111,11 +4233,12 @@ class HStoreNamedGeneric: public HTemplateInstruction<3> {
};
-class HStoreKeyedFastElement: public HTemplateInstruction<3> {
+class HStoreKeyedFastElement
+ : public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
HStoreKeyedFastElement(HValue* obj, HValue* key, HValue* val,
ElementsKind elements_kind = FAST_ELEMENTS)
- : elements_kind_(elements_kind) {
+ : elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) {
SetOperandAt(0, obj);
SetOperandAt(1, key);
SetOperandAt(2, val);
@@ -4135,6 +4258,12 @@ class HStoreKeyedFastElement: public HTemplateInstruction<3> {
bool value_is_smi() {
return elements_kind_ == FAST_SMI_ONLY_ELEMENTS;
}
+ uint32_t index_offset() { return index_offset_; }
+ void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
+ HValue* GetKey() { return key(); }
+ void SetKey(HValue* key) { SetOperandAt(1, key); }
+ bool IsDehoisted() { return is_dehoisted_; }
+ void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
bool NeedsWriteBarrier() {
if (value_is_smi()) {
@@ -4150,14 +4279,18 @@ class HStoreKeyedFastElement: public HTemplateInstruction<3> {
private:
ElementsKind elements_kind_;
+ uint32_t index_offset_;
+ bool is_dehoisted_;
};
-class HStoreKeyedFastDoubleElement: public HTemplateInstruction<3> {
+class HStoreKeyedFastDoubleElement
+ : public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
HStoreKeyedFastDoubleElement(HValue* elements,
HValue* key,
- HValue* val) {
+ HValue* val)
+ : index_offset_(0), is_dehoisted_(false) {
SetOperandAt(0, elements);
SetOperandAt(1, key);
SetOperandAt(2, val);
@@ -4177,24 +4310,37 @@ class HStoreKeyedFastDoubleElement: public HTemplateInstruction<3> {
HValue* elements() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
HValue* value() { return OperandAt(2); }
+ uint32_t index_offset() { return index_offset_; }
+ void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
+ HValue* GetKey() { return key(); }
+ void SetKey(HValue* key) { SetOperandAt(1, key); }
+ bool IsDehoisted() { return is_dehoisted_; }
+ void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
bool NeedsWriteBarrier() {
return StoringValueNeedsWriteBarrier(value());
}
+ bool NeedsCanonicalization();
+
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement)
+
+ private:
+ uint32_t index_offset_;
+ bool is_dehoisted_;
};
-class HStoreKeyedSpecializedArrayElement: public HTemplateInstruction<3> {
+class HStoreKeyedSpecializedArrayElement
+ : public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
HStoreKeyedSpecializedArrayElement(HValue* external_elements,
HValue* key,
HValue* val,
ElementsKind elements_kind)
- : elements_kind_(elements_kind) {
+ : elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) {
SetGVNFlag(kChangesSpecializedArrayElements);
SetOperandAt(0, external_elements);
SetOperandAt(1, key);
@@ -4222,11 +4368,19 @@ class HStoreKeyedSpecializedArrayElement: public HTemplateInstruction<3> {
HValue* key() { return OperandAt(1); }
HValue* value() { return OperandAt(2); }
ElementsKind elements_kind() const { return elements_kind_; }
+ uint32_t index_offset() { return index_offset_; }
+ void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
+ HValue* GetKey() { return key(); }
+ void SetKey(HValue* key) { SetOperandAt(1, key); }
+ bool IsDehoisted() { return is_dehoisted_; }
+ void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement)
private:
ElementsKind elements_kind_;
+ uint32_t index_offset_;
+ bool is_dehoisted_;
};
@@ -4275,6 +4429,7 @@ class HTransitionElementsKind: public HTemplateInstruction<1> {
SetFlag(kUseGVN);
SetGVNFlag(kChangesElementsKind);
SetGVNFlag(kChangesElementsPointer);
+ SetGVNFlag(kChangesNewSpacePromotion);
set_representation(Representation::Tagged());
}
@@ -4336,6 +4491,7 @@ class HStringCharCodeAt: public HTemplateInstruction<3> {
set_representation(Representation::Integer32());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
+ SetGVNFlag(kChangesNewSpacePromotion);
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -4367,6 +4523,7 @@ class HStringCharFromCode: public HTemplateInstruction<2> {
SetOperandAt(1, char_code);
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
+ SetGVNFlag(kChangesNewSpacePromotion);
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -4419,6 +4576,7 @@ class HAllocateObject: public HTemplateInstruction<1> {
: constructor_(constructor) {
SetOperandAt(0, context);
set_representation(Representation::Tagged());
+ SetGVNFlag(kChangesNewSpacePromotion);
}
// Maximum instance size for which allocations will be inlined.
@@ -4467,6 +4625,7 @@ class HFastLiteral: public HMaterializedLiteral<1> {
boilerplate_(boilerplate),
total_size_(total_size) {
SetOperandAt(0, context);
+ SetGVNFlag(kChangesNewSpacePromotion);
}
// Maximum depth and total number of elements and properties for literal
@@ -4502,6 +4661,7 @@ class HArrayLiteral: public HMaterializedLiteral<1> {
length_(length),
boilerplate_object_(boilerplate_object) {
SetOperandAt(0, context);
+ SetGVNFlag(kChangesNewSpacePromotion);
}
HValue* context() { return OperandAt(0); }
@@ -4542,6 +4702,7 @@ class HObjectLiteral: public HMaterializedLiteral<1> {
fast_elements_(fast_elements),
has_function_(has_function) {
SetOperandAt(0, context);
+ SetGVNFlag(kChangesNewSpacePromotion);
}
HValue* context() { return OperandAt(0); }
@@ -4603,6 +4764,7 @@ class HFunctionLiteral: public HTemplateInstruction<1> {
: shared_info_(shared), pretenure_(pretenure) {
SetOperandAt(0, context);
set_representation(Representation::Tagged());
+ SetGVNFlag(kChangesNewSpacePromotion);
}
HValue* context() { return OperandAt(0); }
diff --git a/src/3rdparty/v8/src/hydrogen.cc b/src/3rdparty/v8/src/hydrogen.cc
index ac7944d..99beda0 100644
--- a/src/3rdparty/v8/src/hydrogen.cc
+++ b/src/3rdparty/v8/src/hydrogen.cc
@@ -113,7 +113,6 @@ void HBasicBlock::AddInstruction(HInstruction* instr) {
first_ = last_ = entry;
}
instr->InsertAfter(last_);
- last_ = instr;
}
@@ -165,11 +164,15 @@ void HBasicBlock::Finish(HControlInstruction* end) {
}
-void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) {
+void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) {
+ bool drop_extra = state != NULL && state->drop_extra();
+ bool arguments_pushed = state != NULL && state->arguments_pushed();
+
if (block->IsInlineReturnTarget()) {
- AddInstruction(new(zone()) HLeaveInlined);
+ AddInstruction(new(zone()) HLeaveInlined(arguments_pushed));
last_environment_ = last_environment()->DiscardInlined(drop_extra);
}
+
AddSimulate(AstNode::kNoNumber);
HGoto* instr = new(zone()) HGoto(block);
Finish(instr);
@@ -178,10 +181,13 @@ void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) {
void HBasicBlock::AddLeaveInlined(HValue* return_value,
HBasicBlock* target,
- bool drop_extra) {
+ FunctionState* state) {
+ bool drop_extra = state != NULL && state->drop_extra();
+ bool arguments_pushed = state != NULL && state->arguments_pushed();
+
ASSERT(target->IsInlineReturnTarget());
ASSERT(return_value != NULL);
- AddInstruction(new(zone()) HLeaveInlined);
+ AddInstruction(new(zone()) HLeaveInlined(arguments_pushed));
last_environment_ = last_environment()->DiscardInlined(drop_extra);
last_environment()->Push(return_value);
AddSimulate(AstNode::kNoNumber);
@@ -606,6 +612,7 @@ HGraphBuilder::HGraphBuilder(CompilationInfo* info,
graph_(NULL),
current_block_(NULL),
inlined_count_(0),
+ globals_(10),
zone_(info->isolate()->zone()),
inline_bailout_(false) {
// This is not initialized in the initializer list because the
@@ -1143,14 +1150,39 @@ void HRangeAnalysis::AddRange(HValue* value, Range* range) {
void TraceGVN(const char* msg, ...) {
- if (FLAG_trace_gvn) {
- va_list arguments;
- va_start(arguments, msg);
- OS::VPrint(msg, arguments);
- va_end(arguments);
- }
+ va_list arguments;
+ va_start(arguments, msg);
+ OS::VPrint(msg, arguments);
+ va_end(arguments);
}
+// Wrap TraceGVN in macros to avoid the expense of evaluating its arguments when
+// --trace-gvn is off.
+#define TRACE_GVN_1(msg, a1) \
+ if (FLAG_trace_gvn) { \
+ TraceGVN(msg, a1); \
+ }
+
+#define TRACE_GVN_2(msg, a1, a2) \
+ if (FLAG_trace_gvn) { \
+ TraceGVN(msg, a1, a2); \
+ }
+
+#define TRACE_GVN_3(msg, a1, a2, a3) \
+ if (FLAG_trace_gvn) { \
+ TraceGVN(msg, a1, a2, a3); \
+ }
+
+#define TRACE_GVN_4(msg, a1, a2, a3, a4) \
+ if (FLAG_trace_gvn) { \
+ TraceGVN(msg, a1, a2, a3, a4); \
+ }
+
+#define TRACE_GVN_5(msg, a1, a2, a3, a4, a5) \
+ if (FLAG_trace_gvn) { \
+ TraceGVN(msg, a1, a2, a3, a4, a5); \
+ }
+
HValueMap::HValueMap(Zone* zone, const HValueMap* other)
: array_size_(other->array_size_),
@@ -1321,6 +1353,38 @@ void HValueMap::Insert(HValue* value) {
}
+HSideEffectMap::HSideEffectMap() : count_(0) {
+ memset(data_, 0, kNumberOfTrackedSideEffects * kPointerSize);
+}
+
+
+HSideEffectMap::HSideEffectMap(HSideEffectMap* other) : count_(other->count_) {
+ memcpy(data_, other->data_, kNumberOfTrackedSideEffects * kPointerSize);
+}
+
+
+void HSideEffectMap::Kill(GVNFlagSet flags) {
+ for (int i = 0; i < kNumberOfTrackedSideEffects; i++) {
+ GVNFlag changes_flag = HValue::ChangesFlagFromInt(i);
+ if (flags.Contains(changes_flag)) {
+ if (data_[i] != NULL) count_--;
+ data_[i] = NULL;
+ }
+ }
+}
+
+
+void HSideEffectMap::Store(GVNFlagSet flags, HInstruction* instr) {
+ for (int i = 0; i < kNumberOfTrackedSideEffects; i++) {
+ GVNFlag changes_flag = HValue::ChangesFlagFromInt(i);
+ if (flags.Contains(changes_flag)) {
+ if (data_[i] == NULL) count_++;
+ data_[i] = instr;
+ }
+ }
+}
+
+
class HStackCheckEliminator BASE_EMBEDDED {
public:
explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { }
@@ -1427,7 +1491,9 @@ class HGlobalValueNumberer BASE_EMBEDDED {
GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock(
HBasicBlock* dominator,
HBasicBlock* dominated);
- void AnalyzeBlock(HBasicBlock* block, HValueMap* map);
+ void AnalyzeBlock(HBasicBlock* block,
+ HValueMap* map,
+ HSideEffectMap* dominators);
void ComputeBlockSideEffects();
void LoopInvariantCodeMotion();
void ProcessLoopBlock(HBasicBlock* block,
@@ -1465,7 +1531,8 @@ bool HGlobalValueNumberer::Analyze() {
LoopInvariantCodeMotion();
}
HValueMap* map = new(zone()) HValueMap();
- AnalyzeBlock(graph_->entry_block(), map);
+ HSideEffectMap side_effect_dominators;
+ AnalyzeBlock(graph_->entry_block(), map, &side_effect_dominators);
return removed_side_effects_;
}
@@ -1510,14 +1577,100 @@ void HGlobalValueNumberer::ComputeBlockSideEffects() {
}
+SmartArrayPointer<char> GetGVNFlagsString(GVNFlagSet flags) {
+ char underlying_buffer[kLastFlag * 128];
+ Vector<char> buffer(underlying_buffer, sizeof(underlying_buffer));
+#if DEBUG
+ int offset = 0;
+ const char* separator = "";
+ const char* comma = ", ";
+ buffer[0] = 0;
+ uint32_t set_depends_on = 0;
+ uint32_t set_changes = 0;
+ for (int bit = 0; bit < kLastFlag; ++bit) {
+ if ((flags.ToIntegral() & (1 << bit)) != 0) {
+ if (bit % 2 == 0) {
+ set_changes++;
+ } else {
+ set_depends_on++;
+ }
+ }
+ }
+ bool positive_changes = set_changes < (kLastFlag / 2);
+ bool positive_depends_on = set_depends_on < (kLastFlag / 2);
+ if (set_changes > 0) {
+ if (positive_changes) {
+ offset += OS::SNPrintF(buffer + offset, "changes [");
+ } else {
+ offset += OS::SNPrintF(buffer + offset, "changes all except [");
+ }
+ for (int bit = 0; bit < kLastFlag; ++bit) {
+ if (((flags.ToIntegral() & (1 << bit)) != 0) == positive_changes) {
+ switch (static_cast<GVNFlag>(bit)) {
+#define DECLARE_FLAG(type) \
+ case kChanges##type: \
+ offset += OS::SNPrintF(buffer + offset, separator); \
+ offset += OS::SNPrintF(buffer + offset, #type); \
+ separator = comma; \
+ break;
+GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
+GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
+#undef DECLARE_FLAG
+ default:
+ break;
+ }
+ }
+ }
+ offset += OS::SNPrintF(buffer + offset, "]");
+ }
+ if (set_depends_on > 0) {
+ separator = "";
+ if (set_changes > 0) {
+ offset += OS::SNPrintF(buffer + offset, ", ");
+ }
+ if (positive_depends_on) {
+ offset += OS::SNPrintF(buffer + offset, "depends on [");
+ } else {
+ offset += OS::SNPrintF(buffer + offset, "depends on all except [");
+ }
+ for (int bit = 0; bit < kLastFlag; ++bit) {
+ if (((flags.ToIntegral() & (1 << bit)) != 0) == positive_depends_on) {
+ switch (static_cast<GVNFlag>(bit)) {
+#define DECLARE_FLAG(type) \
+ case kDependsOn##type: \
+ offset += OS::SNPrintF(buffer + offset, separator); \
+ offset += OS::SNPrintF(buffer + offset, #type); \
+ separator = comma; \
+ break;
+GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
+GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
+#undef DECLARE_FLAG
+ default:
+ break;
+ }
+ }
+ }
+ offset += OS::SNPrintF(buffer + offset, "]");
+ }
+#else
+ OS::SNPrintF(buffer, "0x%08X", flags.ToIntegral());
+#endif
+ size_t string_len = strlen(underlying_buffer) + 1;
+ ASSERT(string_len <= sizeof(underlying_buffer));
+ char* result = new char[strlen(underlying_buffer) + 1];
+ memcpy(result, underlying_buffer, string_len);
+ return SmartArrayPointer<char>(result);
+}
+
+
void HGlobalValueNumberer::LoopInvariantCodeMotion() {
for (int i = graph_->blocks()->length() - 1; i >= 0; --i) {
HBasicBlock* block = graph_->blocks()->at(i);
if (block->IsLoopHeader()) {
GVNFlagSet side_effects = loop_side_effects_[block->block_id()];
- TraceGVN("Try loop invariant motion for block B%d effects=0x%x\n",
- block->block_id(),
- side_effects.ToIntegral());
+ TRACE_GVN_2("Try loop invariant motion for block B%d %s\n",
+ block->block_id(),
+ *GetGVNFlagsString(side_effects));
GVNFlagSet accumulated_first_time_depends;
GVNFlagSet accumulated_first_time_changes;
@@ -1540,20 +1693,19 @@ void HGlobalValueNumberer::ProcessLoopBlock(
GVNFlagSet* first_time_changes) {
HBasicBlock* pre_header = loop_header->predecessors()->at(0);
GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills);
- TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n",
- block->block_id(),
- depends_flags.ToIntegral());
+ TRACE_GVN_2("Loop invariant motion for B%d %s\n",
+ block->block_id(),
+ *GetGVNFlagsString(depends_flags));
HInstruction* instr = block->first();
while (instr != NULL) {
HInstruction* next = instr->next();
bool hoisted = false;
if (instr->CheckFlag(HValue::kUseGVN)) {
- TraceGVN("Checking instruction %d (%s) instruction GVN flags 0x%X, "
- "loop kills 0x%X\n",
- instr->id(),
- instr->Mnemonic(),
- instr->gvn_flags().ToIntegral(),
- depends_flags.ToIntegral());
+ TRACE_GVN_4("Checking instruction %d (%s) %s. Loop %s\n",
+ instr->id(),
+ instr->Mnemonic(),
+ *GetGVNFlagsString(instr->gvn_flags()),
+ *GetGVNFlagsString(loop_kills));
bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags);
if (instr->IsTransitionElementsKind()) {
// It's possible to hoist transitions out of a loop as long as the
@@ -1576,15 +1728,19 @@ void HGlobalValueNumberer::ProcessLoopBlock(
if (trans->transitioned_map()->has_fast_double_elements()) {
hoist_change_blockers.Add(kChangesArrayElements);
}
- TraceGVN("Checking dependencies on HTransitionElementsKind %d (%s) "
- "hoist depends blockers 0x%X, hoist change blockers 0x%X, "
- "accumulated depends 0x%X, accumulated changes 0x%X\n",
- instr->id(),
- instr->Mnemonic(),
- hoist_depends_blockers.ToIntegral(),
- hoist_change_blockers.ToIntegral(),
- first_time_depends->ToIntegral(),
- first_time_changes->ToIntegral());
+ if (FLAG_trace_gvn) {
+ GVNFlagSet hoist_blockers = hoist_depends_blockers;
+ hoist_blockers.Add(hoist_change_blockers);
+ GVNFlagSet first_time = *first_time_changes;
+ first_time.Add(*first_time_depends);
+ TRACE_GVN_4("Checking dependencies on HTransitionElementsKind "
+ "%d (%s) hoist blockers: %s; "
+ "first-time accumulated: %s\n",
+ instr->id(),
+ instr->Mnemonic(),
+ *GetGVNFlagsString(hoist_blockers),
+ *GetGVNFlagsString(first_time));
+ }
// It's possible to hoist transition from the current loop loop only if
// they dominate all of the successor blocks in the same loop and there
// are not any instructions that have Changes/DependsOn that intervene
@@ -1607,7 +1763,7 @@ void HGlobalValueNumberer::ProcessLoopBlock(
}
if (inputs_loop_invariant && ShouldMove(instr, loop_header)) {
- TraceGVN("Hoisting loop invariant instruction %d\n", instr->id());
+ TRACE_GVN_1("Hoisting loop invariant instruction %d\n", instr->id());
// Move the instruction out of the loop.
instr->Unlink();
instr->InsertBefore(pre_header->end());
@@ -1619,8 +1775,18 @@ void HGlobalValueNumberer::ProcessLoopBlock(
if (!hoisted) {
// If an instruction is not hoisted, we have to account for its side
// effects when hoisting later HTransitionElementsKind instructions.
+ GVNFlagSet previous_depends = *first_time_depends;
+ GVNFlagSet previous_changes = *first_time_changes;
first_time_depends->Add(instr->DependsOnFlags());
first_time_changes->Add(instr->ChangesFlags());
+ if (!(previous_depends == *first_time_depends)) {
+ TRACE_GVN_1("Updated first-time accumulated %s\n",
+ *GetGVNFlagsString(*first_time_depends));
+ }
+ if (!(previous_changes == *first_time_changes)) {
+ TRACE_GVN_1("Updated first-time accumulated %s\n",
+ *GetGVNFlagsString(*first_time_changes));
+ }
}
instr = next;
}
@@ -1660,10 +1826,12 @@ GVNFlagSet HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock(
}
-void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
- TraceGVN("Analyzing block B%d%s\n",
- block->block_id(),
- block->IsLoopHeader() ? " (loop header)" : "");
+void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block,
+ HValueMap* map,
+ HSideEffectMap* dominators) {
+ TRACE_GVN_2("Analyzing block B%d%s\n",
+ block->block_id(),
+ block->IsLoopHeader() ? " (loop header)" : "");
// If this is a loop header kill everything killed by the loop.
if (block->IsLoopHeader()) {
@@ -1677,25 +1845,45 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
GVNFlagSet flags = instr->ChangesFlags();
if (!flags.IsEmpty()) {
// Clear all instructions in the map that are affected by side effects.
+ // Store instruction as the dominating one for tracked side effects.
map->Kill(flags);
- TraceGVN("Instruction %d kills\n", instr->id());
+ dominators->Store(flags, instr);
+ TRACE_GVN_2("Instruction %d %s\n", instr->id(),
+ *GetGVNFlagsString(flags));
}
if (instr->CheckFlag(HValue::kUseGVN)) {
ASSERT(!instr->HasObservableSideEffects());
HValue* other = map->Lookup(instr);
if (other != NULL) {
ASSERT(instr->Equals(other) && other->Equals(instr));
- TraceGVN("Replacing value %d (%s) with value %d (%s)\n",
- instr->id(),
- instr->Mnemonic(),
- other->id(),
- other->Mnemonic());
+ TRACE_GVN_4("Replacing value %d (%s) with value %d (%s)\n",
+ instr->id(),
+ instr->Mnemonic(),
+ other->id(),
+ other->Mnemonic());
if (instr->HasSideEffects()) removed_side_effects_ = true;
instr->DeleteAndReplaceWith(other);
} else {
map->Add(instr);
}
}
+ if (instr->CheckFlag(HValue::kTrackSideEffectDominators)) {
+ for (int i = 0; i < kNumberOfTrackedSideEffects; i++) {
+ HValue* other = dominators->at(i);
+ GVNFlag changes_flag = HValue::ChangesFlagFromInt(i);
+ GVNFlag depends_on_flag = HValue::DependsOnFlagFromInt(i);
+ if (instr->DependsOnFlags().Contains(depends_on_flag) &&
+ (other != NULL)) {
+ TRACE_GVN_5("Side-effect #%d in %d (%s) is dominated by %d (%s)\n",
+ i,
+ instr->id(),
+ instr->Mnemonic(),
+ other->id(),
+ other->Mnemonic());
+ instr->SetSideEffectDominator(changes_flag, other);
+ }
+ }
+ }
instr = next;
}
@@ -1705,20 +1893,22 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
HBasicBlock* dominated = block->dominated_blocks()->at(i);
// No need to copy the map for the last child in the dominator tree.
HValueMap* successor_map = (i == length - 1) ? map : map->Copy(zone());
+ HSideEffectMap successor_dominators(dominators);
// Kill everything killed on any path between this block and the
- // dominated block.
- // We don't have to traverse these paths if the value map is
- // already empty.
- // If the range of block ids (block_id, dominated_id) is empty
- // there are no such paths.
- if (!successor_map->IsEmpty() &&
+ // dominated block. We don't have to traverse these paths if the
+ // value map and the dominators list is already empty. If the range
+ // of block ids (block_id, dominated_id) is empty there are no such
+ // paths.
+ if ((!successor_map->IsEmpty() || !successor_dominators.IsEmpty()) &&
block->block_id() + 1 < dominated->block_id()) {
visited_on_paths_.Clear();
- successor_map->Kill(CollectSideEffectsOnPathsToDominatedBlock(block,
- dominated));
+ GVNFlagSet side_effects_on_all_paths =
+ CollectSideEffectsOnPathsToDominatedBlock(block, dominated);
+ successor_map->Kill(side_effects_on_all_paths);
+ successor_dominators.Kill(side_effects_on_all_paths);
}
- AnalyzeBlock(dominated, successor_map);
+ AnalyzeBlock(dominated, successor_map, &successor_dominators);
}
}
@@ -2178,6 +2368,8 @@ FunctionState::FunctionState(HGraphBuilder* owner,
return_handling_(return_handling),
function_return_(NULL),
test_context_(NULL),
+ entry_(NULL),
+ arguments_elements_(NULL),
outer_(owner->function_state()) {
if (outer_ != NULL) {
// State for an inline function.
@@ -2337,8 +2529,8 @@ void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) {
instr->SetSuccessorAt(0, empty_true);
instr->SetSuccessorAt(1, empty_false);
owner()->current_block()->Finish(instr);
- empty_true->Goto(if_true(), owner()->function_state()->drop_extra());
- empty_false->Goto(if_false(), owner()->function_state()->drop_extra());
+ empty_true->Goto(if_true(), owner()->function_state());
+ empty_false->Goto(if_false(), owner()->function_state());
owner()->set_current_block(NULL);
}
@@ -2359,8 +2551,8 @@ void TestContext::BuildBranch(HValue* value) {
HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected);
builder->current_block()->Finish(test);
- empty_true->Goto(if_true(), owner()->function_state()->drop_extra());
- empty_false->Goto(if_false(), owner()->function_state()->drop_extra());
+ empty_true->Goto(if_true(), owner()->function_state());
+ empty_false->Goto(if_false(), owner()->function_state());
builder->set_current_block(NULL);
}
@@ -2454,6 +2646,10 @@ HGraph* HGraphBuilder::CreateGraph() {
Bailout("function with illegal redeclaration");
return NULL;
}
+ if (scope->calls_eval()) {
+ Bailout("function calls eval");
+ return NULL;
+ }
SetUpScope(scope);
// Add an edge to the body entry. This is warty: the graph's start
@@ -2480,7 +2676,7 @@ HGraph* HGraphBuilder::CreateGraph() {
// Handle implicit declaration of the function name in named function
// expressions before other declarations.
if (scope->is_function_scope() && scope->function() != NULL) {
- HandleDeclaration(scope->function(), CONST, NULL, NULL);
+ VisitVariableDeclaration(scope->function());
}
VisitDeclarations(scope->declarations());
AddSimulate(AstNode::kDeclarationsId);
@@ -2561,27 +2757,411 @@ HGraph* HGraphBuilder::CreateGraph() {
HStackCheckEliminator sce(graph());
sce.Process();
- // Replace the results of check instructions with the original value, if the
- // result is used. This is safe now, since we don't do code motion after this
- // point. It enables better register allocation since the value produced by
- // check instructions is really a copy of the original value.
- graph()->ReplaceCheckedValues();
+ graph()->EliminateRedundantBoundsChecks();
+ graph()->DehoistSimpleArrayIndexComputations();
return graph();
}
-void HGraph::ReplaceCheckedValues() {
- HPhase phase("H_Replace checked values", this);
+// We try to "factor up" HBoundsCheck instructions towards the root of the
+// dominator tree.
+// For now we handle checks where the index is like "exp + int32value".
+// If in the dominator tree we check "exp + v1" and later (dominated)
+// "exp + v2", if v2 <= v1 we can safely remove the second check, and if
+// v2 > v1 we can use v2 in the 1st check and again remove the second.
+// To do so we keep a dictionary of all checks where the key if the pair
+// "exp, length".
+// The class BoundsCheckKey represents this key.
+class BoundsCheckKey : public ZoneObject {
+ public:
+ HValue* IndexBase() const { return index_base_; }
+ HValue* Length() const { return length_; }
+
+ uint32_t Hash() {
+ return static_cast<uint32_t>(index_base_->Hashcode() ^ length_->Hashcode());
+ }
+
+ static BoundsCheckKey* Create(Zone* zone,
+ HBoundsCheck* check,
+ int32_t* offset) {
+ HValue* index_base = NULL;
+ HConstant* constant = NULL;
+ bool is_sub = false;
+
+ if (check->index()->IsAdd()) {
+ HAdd* index = HAdd::cast(check->index());
+ if (index->left()->IsConstant()) {
+ constant = HConstant::cast(index->left());
+ index_base = index->right();
+ } else if (index->right()->IsConstant()) {
+ constant = HConstant::cast(index->right());
+ index_base = index->left();
+ }
+ } else if (check->index()->IsSub()) {
+ HSub* index = HSub::cast(check->index());
+ is_sub = true;
+ if (index->left()->IsConstant()) {
+ constant = HConstant::cast(index->left());
+ index_base = index->right();
+ } else if (index->right()->IsConstant()) {
+ constant = HConstant::cast(index->right());
+ index_base = index->left();
+ }
+ }
+
+ if (constant != NULL && constant->HasInteger32Value()) {
+ *offset = is_sub ? - constant->Integer32Value()
+ : constant->Integer32Value();
+ } else {
+ *offset = 0;
+ index_base = check->index();
+ }
+
+ return new(zone) BoundsCheckKey(index_base, check->length());
+ }
+
+ private:
+ BoundsCheckKey(HValue* index_base, HValue* length)
+ : index_base_(index_base),
+ length_(length) { }
+
+ HValue* index_base_;
+ HValue* length_;
+};
+
+
+// Data about each HBoundsCheck that can be eliminated or moved.
+// It is the "value" in the dictionary indexed by "base-index, length"
+// (the key is BoundsCheckKey).
+// We scan the code with a dominator tree traversal.
+// Traversing the dominator tree we keep a stack (implemented as a singly
+// linked list) of "data" for each basic block that contains a relevant check
+// with the same key (the dictionary holds the head of the list).
+// We also keep all the "data" created for a given basic block in a list, and
+// use it to "clean up" the dictionary when backtracking in the dominator tree
+// traversal.
+// Doing this each dictionary entry always directly points to the check that
+// is dominating the code being examined now.
+// We also track the current "offset" of the index expression and use it to
+// decide if any check is already "covered" (so it can be removed) or not.
+class BoundsCheckBbData: public ZoneObject {
+ public:
+ BoundsCheckKey* Key() const { return key_; }
+ int32_t LowerOffset() const { return lower_offset_; }
+ int32_t UpperOffset() const { return upper_offset_; }
+ HBasicBlock* BasicBlock() const { return basic_block_; }
+ HBoundsCheck* Check() const { return check_; }
+ BoundsCheckBbData* NextInBasicBlock() const { return next_in_bb_; }
+ BoundsCheckBbData* FatherInDominatorTree() const { return father_in_dt_; }
+
+ bool OffsetIsCovered(int32_t offset) const {
+ return offset >= LowerOffset() && offset <= UpperOffset();
+ }
+
+ // This method removes new_check and modifies the current check so that it
+ // also "covers" what new_check covered.
+ // The obvious precondition is that new_check follows Check() in the
+ // same basic block, and that new_offset is not covered (otherwise we
+ // could simply remove new_check).
+ // As a consequence LowerOffset() or UpperOffset() change (the covered
+ // range grows).
+ //
+ // In the general case the check covering the current range should be like
+ // these two checks:
+ // 0 <= Key()->IndexBase() + LowerOffset()
+ // Key()->IndexBase() + UpperOffset() < Key()->Length()
+ //
+ // We can transform the second check like this:
+ // Key()->IndexBase() + LowerOffset() <
+ // Key()->Length() + (LowerOffset() - UpperOffset())
+ // so we can handle both checks with a single unsigned comparison.
+ //
+ // The bulk of this method changes Check()->index() and Check()->length()
+ // replacing them with new HAdd instructions to perform the transformation
+ // described above.
+ void CoverCheck(HBoundsCheck* new_check,
+ int32_t new_offset) {
+ ASSERT(new_check->index()->representation().IsInteger32());
+
+ if (new_offset > upper_offset_) {
+ upper_offset_ = new_offset;
+ } else if (new_offset < lower_offset_) {
+ lower_offset_ = new_offset;
+ } else {
+ ASSERT(false);
+ }
+
+ BuildOffsetAdd(&added_index_,
+ &added_index_offset_,
+ Key()->IndexBase(),
+ new_check->index()->representation(),
+ lower_offset_);
+ Check()->SetOperandAt(0, added_index_);
+ BuildOffsetAdd(&added_length_,
+ &added_length_offset_,
+ Key()->Length(),
+ new_check->length()->representation(),
+ lower_offset_ - upper_offset_);
+ Check()->SetOperandAt(1, added_length_);
+
+ new_check->DeleteAndReplaceWith(NULL);
+ }
+
+ void RemoveZeroOperations() {
+ RemoveZeroAdd(&added_index_, &added_index_offset_);
+ RemoveZeroAdd(&added_length_, &added_length_offset_);
+ }
+
+ BoundsCheckBbData(BoundsCheckKey* key,
+ int32_t lower_offset,
+ int32_t upper_offset,
+ HBasicBlock* bb,
+ HBoundsCheck* check,
+ BoundsCheckBbData* next_in_bb,
+ BoundsCheckBbData* father_in_dt)
+ : key_(key),
+ lower_offset_(lower_offset),
+ upper_offset_(upper_offset),
+ basic_block_(bb),
+ check_(check),
+ added_index_offset_(NULL),
+ added_index_(NULL),
+ added_length_offset_(NULL),
+ added_length_(NULL),
+ next_in_bb_(next_in_bb),
+ father_in_dt_(father_in_dt) { }
+
+ private:
+ BoundsCheckKey* key_;
+ int32_t lower_offset_;
+ int32_t upper_offset_;
+ HBasicBlock* basic_block_;
+ HBoundsCheck* check_;
+ HConstant* added_index_offset_;
+ HAdd* added_index_;
+ HConstant* added_length_offset_;
+ HAdd* added_length_;
+ BoundsCheckBbData* next_in_bb_;
+ BoundsCheckBbData* father_in_dt_;
+
+ void BuildOffsetAdd(HAdd** add,
+ HConstant** constant,
+ HValue* original_value,
+ Representation representation,
+ int32_t new_offset) {
+ HConstant* new_constant = new(BasicBlock()->zone())
+ HConstant(Handle<Object>(Smi::FromInt(new_offset)),
+ Representation::Integer32());
+ if (*add == NULL) {
+ new_constant->InsertBefore(Check());
+ *add = new(BasicBlock()->zone()) HAdd(NULL,
+ original_value,
+ new_constant);
+ (*add)->AssumeRepresentation(representation);
+ (*add)->InsertBefore(Check());
+ } else {
+ new_constant->InsertBefore(*add);
+ (*constant)->DeleteAndReplaceWith(new_constant);
+ }
+ *constant = new_constant;
+ }
+
+ void RemoveZeroAdd(HAdd** add, HConstant** constant) {
+ if (*add != NULL && (*constant)->Integer32Value() == 0) {
+ (*add)->DeleteAndReplaceWith((*add)->left());
+ (*constant)->DeleteAndReplaceWith(NULL);
+ }
+ }
+};
+
+
+static bool BoundsCheckKeyMatch(void* key1, void* key2) {
+ BoundsCheckKey* k1 = static_cast<BoundsCheckKey*>(key1);
+ BoundsCheckKey* k2 = static_cast<BoundsCheckKey*>(key2);
+ return k1->IndexBase() == k2->IndexBase() && k1->Length() == k2->Length();
+}
+
+
+class BoundsCheckTable : private ZoneHashMap {
+ public:
+ BoundsCheckBbData** LookupOrInsert(BoundsCheckKey* key) {
+ return reinterpret_cast<BoundsCheckBbData**>(
+ &(Lookup(key, key->Hash(), true)->value));
+ }
+
+ void Insert(BoundsCheckKey* key, BoundsCheckBbData* data) {
+ Lookup(key, key->Hash(), true)->value = data;
+ }
+
+ void Delete(BoundsCheckKey* key) {
+ Remove(key, key->Hash());
+ }
+
+ BoundsCheckTable() : ZoneHashMap(BoundsCheckKeyMatch) { }
+};
+
+
+// Eliminates checks in bb and recursively in the dominated blocks.
+// Also replace the results of check instructions with the original value, if
+// the result is used. This is safe now, since we don't do code motion after
+// this point. It enables better register allocation since the value produced
+// by check instructions is really a copy of the original value.
+void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb,
+ BoundsCheckTable* table) {
+ BoundsCheckBbData* bb_data_list = NULL;
+
+ for (HInstruction* i = bb->first(); i != NULL; i = i->next()) {
+ if (!i->IsBoundsCheck()) continue;
+
+ HBoundsCheck* check = HBoundsCheck::cast(i);
+ check->ReplaceAllUsesWith(check->index());
+
+ if (!FLAG_array_bounds_checks_elimination) continue;
+
+ int32_t offset;
+ BoundsCheckKey* key =
+ BoundsCheckKey::Create(bb->zone(), check, &offset);
+ BoundsCheckBbData** data_p = table->LookupOrInsert(key);
+ BoundsCheckBbData* data = *data_p;
+ if (data == NULL) {
+ bb_data_list = new(zone()) BoundsCheckBbData(key,
+ offset,
+ offset,
+ bb,
+ check,
+ bb_data_list,
+ NULL);
+ *data_p = bb_data_list;
+ } else if (data->OffsetIsCovered(offset)) {
+ check->DeleteAndReplaceWith(NULL);
+ } else if (data->BasicBlock() == bb) {
+ data->CoverCheck(check, offset);
+ } else {
+ int32_t new_lower_offset = offset < data->LowerOffset()
+ ? offset
+ : data->LowerOffset();
+ int32_t new_upper_offset = offset > data->UpperOffset()
+ ? offset
+ : data->UpperOffset();
+ bb_data_list = new(bb->zone()) BoundsCheckBbData(key,
+ new_lower_offset,
+ new_upper_offset,
+ bb,
+ check,
+ bb_data_list,
+ data);
+ table->Insert(key, bb_data_list);
+ }
+ }
+
+ for (int i = 0; i < bb->dominated_blocks()->length(); ++i) {
+ EliminateRedundantBoundsChecks(bb->dominated_blocks()->at(i), table);
+ }
+
+ for (BoundsCheckBbData* data = bb_data_list;
+ data != NULL;
+ data = data->NextInBasicBlock()) {
+ data->RemoveZeroOperations();
+ if (data->FatherInDominatorTree()) {
+ table->Insert(data->Key(), data->FatherInDominatorTree());
+ } else {
+ table->Delete(data->Key());
+ }
+ }
+}
+
+
+void HGraph::EliminateRedundantBoundsChecks() {
+ HPhase phase("H_Eliminate bounds checks", this);
+ AssertNoAllocation no_gc;
+ BoundsCheckTable checks_table;
+ EliminateRedundantBoundsChecks(entry_block(), &checks_table);
+}
+
+
+static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) {
+ HValue* index = array_operation->GetKey();
+
+ HConstant* constant;
+ HValue* subexpression;
+ int32_t sign;
+ if (index->IsAdd()) {
+ sign = 1;
+ HAdd* add = HAdd::cast(index);
+ if (add->left()->IsConstant()) {
+ subexpression = add->right();
+ constant = HConstant::cast(add->left());
+ } else if (add->right()->IsConstant()) {
+ subexpression = add->left();
+ constant = HConstant::cast(add->right());
+ } else {
+ return;
+ }
+ } else if (index->IsSub()) {
+ sign = -1;
+ HSub* sub = HSub::cast(index);
+ if (sub->left()->IsConstant()) {
+ subexpression = sub->right();
+ constant = HConstant::cast(sub->left());
+ } else if (sub->right()->IsConstant()) {
+ subexpression = sub->left();
+ constant = HConstant::cast(sub->right());
+ } return;
+ } else {
+ return;
+ }
+
+ if (!constant->HasInteger32Value()) return;
+ int32_t value = constant->Integer32Value() * sign;
+ // We limit offset values to 30 bits because we want to avoid the risk of
+ // overflows when the offset is added to the object header size.
+ if (value >= 1 << 30 || value < 0) return;
+ array_operation->SetKey(subexpression);
+ if (index->HasNoUses()) {
+ index->DeleteAndReplaceWith(NULL);
+ }
+ ASSERT(value >= 0);
+ array_operation->SetIndexOffset(static_cast<uint32_t>(value));
+ array_operation->SetDehoisted(true);
+}
+
+
+void HGraph::DehoistSimpleArrayIndexComputations() {
+ if (!FLAG_array_index_dehoisting) return;
+
+ HPhase phase("H_Dehoist index computations", this);
for (int i = 0; i < blocks()->length(); ++i) {
- HInstruction* instr = blocks()->at(i)->first();
- while (instr != NULL) {
- if (instr->IsBoundsCheck()) {
- // Replace all uses of the checked value with the original input.
- ASSERT(instr->UseCount() > 0);
- instr->ReplaceAllUsesWith(HBoundsCheck::cast(instr)->index());
+ for (HInstruction* instr = blocks()->at(i)->first();
+ instr != NULL;
+ instr = instr->next()) {
+ ArrayInstructionInterface* array_instruction = NULL;
+ if (instr->IsLoadKeyedFastElement()) {
+ HLoadKeyedFastElement* op = HLoadKeyedFastElement::cast(instr);
+ array_instruction = static_cast<ArrayInstructionInterface*>(op);
+ } else if (instr->IsLoadKeyedFastDoubleElement()) {
+ HLoadKeyedFastDoubleElement* op =
+ HLoadKeyedFastDoubleElement::cast(instr);
+ array_instruction = static_cast<ArrayInstructionInterface*>(op);
+ } else if (instr->IsLoadKeyedSpecializedArrayElement()) {
+ HLoadKeyedSpecializedArrayElement* op =
+ HLoadKeyedSpecializedArrayElement::cast(instr);
+ array_instruction = static_cast<ArrayInstructionInterface*>(op);
+ } else if (instr->IsStoreKeyedFastElement()) {
+ HStoreKeyedFastElement* op = HStoreKeyedFastElement::cast(instr);
+ array_instruction = static_cast<ArrayInstructionInterface*>(op);
+ } else if (instr->IsStoreKeyedFastDoubleElement()) {
+ HStoreKeyedFastDoubleElement* op =
+ HStoreKeyedFastDoubleElement::cast(instr);
+ array_instruction = static_cast<ArrayInstructionInterface*>(op);
+ } else if (instr->IsStoreKeyedSpecializedArrayElement()) {
+ HStoreKeyedSpecializedArrayElement* op =
+ HStoreKeyedSpecializedArrayElement::cast(instr);
+ array_instruction = static_cast<ArrayInstructionInterface*>(op);
+ } else {
+ continue;
}
- instr = instr->next();
+ DehoistArrayIndex(array_instruction);
}
}
}
@@ -2697,7 +3277,7 @@ void HGraphBuilder::VisitBlock(Block* stmt) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- if (stmt->block_scope() != NULL) {
+ if (stmt->scope() != NULL) {
return Bailout("ScopedBlock");
}
BreakAndContinueInfo break_info(stmt);
@@ -2851,10 +3431,10 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
if (context->IsTest()) {
TestContext* test = TestContext::cast(context);
CHECK_ALIVE(VisitForEffect(stmt->expression()));
- current_block()->Goto(test->if_true(), function_state()->drop_extra());
+ current_block()->Goto(test->if_true(), function_state());
} else if (context->IsEffect()) {
CHECK_ALIVE(VisitForEffect(stmt->expression()));
- current_block()->Goto(function_return(), function_state()->drop_extra());
+ current_block()->Goto(function_return(), function_state());
} else {
ASSERT(context->IsValue());
CHECK_ALIVE(VisitForValue(stmt->expression()));
@@ -2871,10 +3451,10 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
current_block()->Finish(typecheck);
if_spec_object->AddLeaveInlined(return_value,
function_return(),
- function_state()->drop_extra());
+ function_state());
not_spec_object->AddLeaveInlined(receiver,
function_return(),
- function_state()->drop_extra());
+ function_state());
}
} else {
// Return from an inlined function, visit the subexpression in the
@@ -2886,14 +3466,14 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
test->if_false());
} else if (context->IsEffect()) {
CHECK_ALIVE(VisitForEffect(stmt->expression()));
- current_block()->Goto(function_return(), function_state()->drop_extra());
+ current_block()->Goto(function_return(), function_state());
} else {
ASSERT(context->IsValue());
CHECK_ALIVE(VisitForValue(stmt->expression()));
HValue* return_value = Pop();
current_block()->AddLeaveInlined(return_value,
function_return(),
- function_state()->drop_extra());
+ function_state());
}
}
set_current_block(NULL);
@@ -3603,7 +4183,6 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
} else {
HValue* context = environment()->LookupContext();
HGlobalObject* global_object = new(zone()) HGlobalObject(context);
- if (variable->is_qml_global()) global_object->set_qml_global(true);
AddInstruction(global_object);
HLoadGlobalGeneric* instr =
new(zone()) HLoadGlobalGeneric(context,
@@ -3679,10 +4258,11 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate,
if (boilerplate->HasFastDoubleElements()) {
*total_size += FixedDoubleArray::SizeFor(elements->length());
} else if (boilerplate->HasFastElements()) {
+ Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
int length = elements->length();
for (int i = 0; i < length; i++) {
if ((*max_properties)-- == 0) return false;
- Handle<Object> value = JSObject::GetElement(boilerplate, i);
+ Handle<Object> value(fast_elements->get(i));
if (value->IsJSObject()) {
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
if (!IsFastLiteral(value_object,
@@ -4231,7 +4811,6 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
} else {
HValue* context = environment()->LookupContext();
HGlobalObject* global_object = new(zone()) HGlobalObject(context);
- if (var->is_qml_global()) global_object->set_qml_global(true);
AddInstruction(global_object);
HStoreGlobalGeneric* instr =
new(zone()) HStoreGlobalGeneric(context,
@@ -4982,6 +5561,34 @@ HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
function_strict_mode_flag());
}
+
+void HGraphBuilder::EnsureArgumentsArePushedForAccess() {
+ // Outermost function already has arguments on the stack.
+ if (function_state()->outer() == NULL) return;
+
+ if (function_state()->arguments_pushed()) return;
+
+ // Push arguments when entering inlined function.
+ HEnterInlined* entry = function_state()->entry();
+
+ ZoneList<HValue*>* arguments_values = entry->arguments_values();
+
+ HInstruction* insert_after = entry;
+ for (int i = 0; i < arguments_values->length(); i++) {
+ HValue* argument = arguments_values->at(i);
+ HInstruction* push_argument = new(zone()) HPushArgument(argument);
+ push_argument->InsertAfter(insert_after);
+ insert_after = push_argument;
+ }
+
+ HArgumentsElements* arguments_elements =
+ new(zone()) HArgumentsElements(true);
+ arguments_elements->ClearFlag(HValue::kUseGVN);
+ arguments_elements->InsertAfter(insert_after);
+ function_state()->set_arguments_elements(arguments_elements);
+}
+
+
bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
VariableProxy* proxy = expr->obj()->AsVariableProxy();
if (proxy == NULL) return false;
@@ -4990,31 +5597,51 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
return false;
}
- // Our implementation of arguments (based on this stack frame or an
- // adapter below it) does not work for inlined functions.
- if (function_state()->outer() != NULL) {
- Bailout("arguments access in inlined function");
- return true;
- }
-
HInstruction* result = NULL;
if (expr->key()->IsPropertyName()) {
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
if (!name->IsEqualTo(CStrVector("length"))) return false;
- HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
- result = new(zone()) HArgumentsLength(elements);
+
+ if (function_state()->outer() == NULL) {
+ HInstruction* elements = AddInstruction(
+ new(zone()) HArgumentsElements(false));
+ result = new(zone()) HArgumentsLength(elements);
+ } else {
+ // Number of arguments without receiver.
+ int argument_count = environment()->
+ arguments_environment()->parameter_count() - 1;
+ result = new(zone()) HConstant(
+ Handle<Object>(Smi::FromInt(argument_count)),
+ Representation::Integer32());
+ }
} else {
Push(graph()->GetArgumentsObject());
VisitForValue(expr->key());
if (HasStackOverflow() || current_block() == NULL) return true;
HValue* key = Pop();
Drop(1); // Arguments object.
- HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
- HInstruction* length = AddInstruction(
- new(zone()) HArgumentsLength(elements));
- HInstruction* checked_key =
- AddInstruction(new(zone()) HBoundsCheck(key, length));
- result = new(zone()) HAccessArgumentsAt(elements, length, checked_key);
+ if (function_state()->outer() == NULL) {
+ HInstruction* elements = AddInstruction(
+ new(zone()) HArgumentsElements(false));
+ HInstruction* length = AddInstruction(
+ new(zone()) HArgumentsLength(elements));
+ HInstruction* checked_key =
+ AddInstruction(new(zone()) HBoundsCheck(key, length));
+ result = new(zone()) HAccessArgumentsAt(elements, length, checked_key);
+ } else {
+ EnsureArgumentsArePushedForAccess();
+
+ // Number of arguments without receiver.
+ HInstruction* elements = function_state()->arguments_elements();
+ int argument_count = environment()->
+ arguments_environment()->parameter_count() - 1;
+ HInstruction* length = AddInstruction(new(zone()) HConstant(
+ Handle<Object>(Smi::FromInt(argument_count)),
+ Representation::Integer32()));
+ HInstruction* checked_key =
+ AddInstruction(new(zone()) HBoundsCheck(key, length));
+ result = new(zone()) HAccessArgumentsAt(elements, length, checked_key);
+ }
}
ast_context()->ReturnInstruction(result, expr->id());
return true;
@@ -5120,6 +5747,39 @@ void HGraphBuilder::AddCheckConstantFunction(Call* expr,
}
+class FunctionSorter {
+ public:
+ FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { }
+ FunctionSorter(int index, int ticks, int ast_length, int src_length)
+ : index_(index),
+ ticks_(ticks),
+ ast_length_(ast_length),
+ src_length_(src_length) { }
+
+ int index() const { return index_; }
+ int ticks() const { return ticks_; }
+ int ast_length() const { return ast_length_; }
+ int src_length() const { return src_length_; }
+
+ private:
+ int index_;
+ int ticks_;
+ int ast_length_;
+ int src_length_;
+};
+
+
+static int CompareHotness(void const* a, void const* b) {
+ FunctionSorter const* function1 = reinterpret_cast<FunctionSorter const*>(a);
+ FunctionSorter const* function2 = reinterpret_cast<FunctionSorter const*>(b);
+ int diff = function1->ticks() - function2->ticks();
+ if (diff != 0) return -diff;
+ diff = function1->ast_length() - function2->ast_length();
+ if (diff != 0) return diff;
+ return function1->src_length() - function2->src_length();
+}
+
+
void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
HValue* receiver,
SmallMapList* types,
@@ -5128,51 +5788,73 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
// maps are identical. In that case we can avoid repeatedly generating the
// same prototype map checks.
int argument_count = expr->arguments()->length() + 1; // Includes receiver.
- int count = 0;
HBasicBlock* join = NULL;
- for (int i = 0; i < types->length() && count < kMaxCallPolymorphism; ++i) {
+ FunctionSorter order[kMaxCallPolymorphism];
+ int ordered_functions = 0;
+ for (int i = 0;
+ i < types->length() && ordered_functions < kMaxCallPolymorphism;
+ ++i) {
Handle<Map> map = types->at(i);
if (expr->ComputeTarget(map, name)) {
- if (count == 0) {
- // Only needed once.
- AddInstruction(new(zone()) HCheckNonSmi(receiver));
- join = graph()->CreateBasicBlock();
- }
- ++count;
- HBasicBlock* if_true = graph()->CreateBasicBlock();
- HBasicBlock* if_false = graph()->CreateBasicBlock();
- HCompareMap* compare =
- new(zone()) HCompareMap(receiver, map, if_true, if_false);
- current_block()->Finish(compare);
+ order[ordered_functions++] =
+ FunctionSorter(i,
+ expr->target()->shared()->profiler_ticks(),
+ InliningAstSize(expr->target()),
+ expr->target()->shared()->SourceSize());
+ }
+ }
- set_current_block(if_true);
- AddCheckConstantFunction(expr, receiver, map, false);
- if (FLAG_trace_inlining && FLAG_polymorphic_inlining) {
- PrintF("Trying to inline the polymorphic call to %s\n",
- *name->ToCString());
- }
- if (FLAG_polymorphic_inlining && TryInlineCall(expr)) {
- // Trying to inline will signal that we should bailout from the
- // entire compilation by setting stack overflow on the visitor.
- if (HasStackOverflow()) return;
- } else {
- HCallConstantFunction* call =
- new(zone()) HCallConstantFunction(expr->target(), argument_count);
- call->set_position(expr->position());
- PreProcessCall(call);
- AddInstruction(call);
- if (!ast_context()->IsEffect()) Push(call);
- }
+ qsort(reinterpret_cast<void*>(&order[0]),
+ ordered_functions,
+ sizeof(order[0]),
+ &CompareHotness);
- if (current_block() != NULL) current_block()->Goto(join);
- set_current_block(if_false);
+ for (int fn = 0; fn < ordered_functions; ++fn) {
+ int i = order[fn].index();
+ Handle<Map> map = types->at(i);
+ if (fn == 0) {
+ // Only needed once.
+ AddInstruction(new(zone()) HCheckNonSmi(receiver));
+ join = graph()->CreateBasicBlock();
+ }
+ HBasicBlock* if_true = graph()->CreateBasicBlock();
+ HBasicBlock* if_false = graph()->CreateBasicBlock();
+ HCompareMap* compare =
+ new(zone()) HCompareMap(receiver, map, if_true, if_false);
+ current_block()->Finish(compare);
+
+ set_current_block(if_true);
+ expr->ComputeTarget(map, name);
+ AddCheckConstantFunction(expr, receiver, map, false);
+ if (FLAG_trace_inlining && FLAG_polymorphic_inlining) {
+ Handle<JSFunction> caller = info()->closure();
+ SmartArrayPointer<char> caller_name =
+ caller->shared()->DebugName()->ToCString();
+ PrintF("Trying to inline the polymorphic call to %s from %s\n",
+ *name->ToCString(),
+ *caller_name);
+ }
+ if (FLAG_polymorphic_inlining && TryInlineCall(expr)) {
+ // Trying to inline will signal that we should bailout from the
+ // entire compilation by setting stack overflow on the visitor.
+ if (HasStackOverflow()) return;
+ } else {
+ HCallConstantFunction* call =
+ new(zone()) HCallConstantFunction(expr->target(), argument_count);
+ call->set_position(expr->position());
+ PreProcessCall(call);
+ AddInstruction(call);
+ if (!ast_context()->IsEffect()) Push(call);
}
+
+ if (current_block() != NULL) current_block()->Goto(join);
+ set_current_block(if_false);
}
// Finish up. Unconditionally deoptimize if we've handled all the maps we
// know about and do not want to handle ones we've never seen. Otherwise
// use a generic IC.
- if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
+ if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) {
current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
} else {
HValue* context = environment()->LookupContext();
@@ -5221,14 +5903,11 @@ void HGraphBuilder::TraceInline(Handle<JSFunction> target,
}
-bool HGraphBuilder::TryInline(CallKind call_kind,
- Handle<JSFunction> target,
- ZoneList<Expression*>* arguments,
- HValue* receiver,
- int ast_id,
- int return_id,
- ReturnHandlingFlag return_handling) {
- if (!FLAG_use_inlining) return false;
+static const int kNotInlinable = 1000000000;
+
+
+int HGraphBuilder::InliningAstSize(Handle<JSFunction> target) {
+ if (!FLAG_use_inlining) return kNotInlinable;
// Precondition: call is monomorphic and we have found a target with the
// appropriate arity.
@@ -5237,29 +5916,46 @@ bool HGraphBuilder::TryInline(CallKind call_kind,
// Do a quick check on source code length to avoid parsing large
// inlining candidates.
- if ((FLAG_limit_inlining && target_shared->SourceSize() > kMaxSourceSize)
- || target_shared->SourceSize() > kUnlimitedMaxSourceSize) {
+ if (target_shared->SourceSize() >
+ Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) {
TraceInline(target, caller, "target text too big");
- return false;
+ return kNotInlinable;
}
// Target must be inlineable.
if (!target->IsInlineable()) {
TraceInline(target, caller, "target not inlineable");
- return false;
+ return kNotInlinable;
}
if (target_shared->dont_inline() || target_shared->dont_optimize()) {
TraceInline(target, caller, "target contains unsupported syntax [early]");
- return false;
+ return kNotInlinable;
}
int nodes_added = target_shared->ast_node_count();
- if ((FLAG_limit_inlining && nodes_added > kMaxInlinedSize) ||
- nodes_added > kUnlimitedMaxInlinedSize) {
+ return nodes_added;
+}
+
+
+bool HGraphBuilder::TryInline(CallKind call_kind,
+ Handle<JSFunction> target,
+ ZoneList<Expression*>* arguments,
+ HValue* receiver,
+ int ast_id,
+ int return_id,
+ ReturnHandlingFlag return_handling) {
+ int nodes_added = InliningAstSize(target);
+ if (nodes_added == kNotInlinable) return false;
+
+ Handle<JSFunction> caller = info()->closure();
+
+ if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
TraceInline(target, caller, "target AST is too large [early]");
return false;
}
+ Handle<SharedFunctionInfo> target_shared(target->shared());
+
#if !defined(V8_TARGET_ARCH_IA32)
// Target must be able to use caller's context.
CompilationInfo* outer_info = info();
@@ -5297,8 +5993,8 @@ bool HGraphBuilder::TryInline(CallKind call_kind,
}
// We don't want to add more than a certain number of nodes from inlining.
- if ((FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) ||
- inlined_count_ > kUnlimitedMaxInlinedNodes) {
+ if (inlined_count_ > Min(FLAG_max_inlined_nodes_cumulative,
+ kUnlimitedMaxInlinedNodesCumulative)) {
TraceInline(target, caller, "cumulative AST node limit reached");
return false;
}
@@ -5325,8 +6021,7 @@ bool HGraphBuilder::TryInline(CallKind call_kind,
// The following conditions must be checked again after re-parsing, because
// earlier the information might not have been complete due to lazy parsing.
nodes_added = function->ast_node_count();
- if ((FLAG_limit_inlining && nodes_added > kMaxInlinedSize) ||
- nodes_added > kUnlimitedMaxInlinedSize) {
+ if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
TraceInline(target, caller, "target AST is too large [late]");
return false;
}
@@ -5421,20 +6116,42 @@ bool HGraphBuilder::TryInline(CallKind call_kind,
AddInstruction(context);
inner_env->BindContext(context);
#endif
+
AddSimulate(return_id);
current_block()->UpdateEnvironment(inner_env);
- AddInstruction(new(zone()) HEnterInlined(target,
- arguments->length(),
- function,
- call_kind,
- function_state()->is_construct(),
- function->scope()->arguments()));
+
+ ZoneList<HValue*>* arguments_values = NULL;
+
+ // If the function uses arguments copy current arguments values
+ // to use them for materialization.
+ if (function->scope()->arguments() != NULL) {
+ HEnvironment* arguments_env = inner_env->arguments_environment();
+ int arguments_count = arguments_env->parameter_count();
+ arguments_values = new(zone()) ZoneList<HValue*>(arguments_count);
+ for (int i = 0; i < arguments_count; i++) {
+ arguments_values->Add(arguments_env->Lookup(i));
+ }
+ }
+
+ HEnterInlined* enter_inlined =
+ new(zone()) HEnterInlined(target,
+ arguments->length(),
+ function,
+ call_kind,
+ function_state()->is_construct(),
+ function->scope()->arguments(),
+ arguments_values);
+ function_state()->set_entry(enter_inlined);
+ AddInstruction(enter_inlined);
+
// If the function uses arguments object create and bind one.
if (function->scope()->arguments() != NULL) {
ASSERT(function->scope()->arguments()->IsStackAllocated());
- environment()->Bind(function->scope()->arguments(),
- graph()->GetArgumentsObject());
+ inner_env->Bind(function->scope()->arguments(),
+ graph()->GetArgumentsObject());
}
+
+
VisitDeclarations(target_info.scope()->declarations());
VisitStatements(function->body());
if (HasStackOverflow()) {
@@ -5463,17 +6180,17 @@ bool HGraphBuilder::TryInline(CallKind call_kind,
: undefined;
current_block()->AddLeaveInlined(return_value,
function_return(),
- function_state()->drop_extra());
+ function_state());
} else if (call_context()->IsEffect()) {
ASSERT(function_return() != NULL);
- current_block()->Goto(function_return(), function_state()->drop_extra());
+ current_block()->Goto(function_return(), function_state());
} else {
ASSERT(call_context()->IsTest());
ASSERT(inlined_test_context() != NULL);
HBasicBlock* target = function_state()->is_construct()
? inlined_test_context()->if_true()
: inlined_test_context()->if_false();
- current_block()->Goto(target, function_state()->drop_extra());
+ current_block()->Goto(target, function_state());
}
}
@@ -5491,12 +6208,12 @@ bool HGraphBuilder::TryInline(CallKind call_kind,
if (if_true->HasPredecessor()) {
if_true->SetJoinId(ast_id);
HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
- if_true->Goto(true_target, function_state()->drop_extra());
+ if_true->Goto(true_target, function_state());
}
if (if_false->HasPredecessor()) {
if_false->SetJoinId(ast_id);
HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
- if_false->Goto(false_target, function_state()->drop_extra());
+ if_false->Goto(false_target, function_state());
}
set_current_block(NULL);
return true;
@@ -5805,7 +6522,8 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
HValue* receiver = Pop();
if (function_state()->outer() == NULL) {
- HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
+ HInstruction* elements = AddInstruction(
+ new(zone()) HArgumentsElements(false));
HInstruction* length =
AddInstruction(new(zone()) HArgumentsLength(elements));
HValue* wrapped_receiver =
@@ -5938,6 +6656,10 @@ void HGraphBuilder::VisitCall(Call* expr) {
VariableProxy* proxy = expr->expression()->AsVariableProxy();
bool global_call = proxy != NULL && proxy->var()->IsUnallocated();
+ if (proxy != NULL && proxy->var()->is_possibly_eval()) {
+ return Bailout("possible direct call to eval");
+ }
+
if (global_call) {
Variable* var = proxy->var();
bool known_global_function = false;
@@ -5987,13 +6709,11 @@ void HGraphBuilder::VisitCall(Call* expr) {
} else {
HValue* context = environment()->LookupContext();
HGlobalObject* receiver = new(zone()) HGlobalObject(context);
- if (var->is_qml_global()) receiver->set_qml_global(true);
AddInstruction(receiver);
PushAndAdd(new(zone()) HPushArgument(receiver));
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
call = new(zone()) HCallGlobal(context, var->name(), argument_count);
- if (var->is_qml_global()) static_cast<HCallGlobal*>(call)->set_qml_global(true);
Drop(argument_count);
}
@@ -6022,9 +6742,11 @@ void HGraphBuilder::VisitCall(Call* expr) {
if (TryInlineCall(expr, true)) { // Drop function from environment.
return;
} else {
- call = PreProcessCall(new(zone()) HInvokeFunction(context,
- function,
- argument_count));
+ call = PreProcessCall(
+ new(zone()) HInvokeFunction(context,
+ function,
+ expr->target(),
+ argument_count));
Drop(1); // The function.
}
@@ -7019,91 +7741,50 @@ void HGraphBuilder::VisitThisFunction(ThisFunction* expr) {
void HGraphBuilder::VisitDeclarations(ZoneList<Declaration*>* declarations) {
- int length = declarations->length();
- int global_count = 0;
- for (int i = 0; i < declarations->length(); i++) {
- Declaration* decl = declarations->at(i);
- FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration();
- HandleDeclaration(decl->proxy(),
- decl->mode(),
- fun_decl != NULL ? fun_decl->fun() : NULL,
- &global_count);
- }
-
- // Batch declare global functions and variables.
- if (global_count > 0) {
+ ASSERT(globals_.is_empty());
+ AstVisitor::VisitDeclarations(declarations);
+ if (!globals_.is_empty()) {
Handle<FixedArray> array =
- isolate()->factory()->NewFixedArray(3 * global_count, TENURED);
- for (int j = 0, i = 0; i < length; i++) {
- Declaration* decl = declarations->at(i);
- Variable* var = decl->proxy()->var();
-
- if (var->IsUnallocated()) {
- array->set(j++, *(var->name()));
- FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration();
- if (fun_decl == NULL) {
- if (var->binding_needs_init()) {
- // In case this binding needs initialization use the hole.
- array->set_the_hole(j++);
- } else {
- array->set_undefined(j++);
- }
- } else {
- Handle<SharedFunctionInfo> function =
- Compiler::BuildFunctionInfo(fun_decl->fun(), info()->script());
- // Check for stack-overflow exception.
- if (function.is_null()) {
- SetStackOverflow();
- return;
- }
- array->set(j++, *function);
- }
- }
- array->set(j++, Smi::FromInt(var->is_qml_global()));
- }
+ isolate()->factory()->NewFixedArray(globals_.length(), TENURED);
+ for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i));
int flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
DeclareGlobalsNativeFlag::encode(info()->is_native()) |
DeclareGlobalsLanguageMode::encode(info()->language_mode());
- HInstruction* result =
- new(zone()) HDeclareGlobals(environment()->LookupContext(),
- array,
- flags);
+ HInstruction* result = new(zone()) HDeclareGlobals(
+ environment()->LookupContext(), array, flags);
AddInstruction(result);
+ globals_.Clear();
}
}
-void HGraphBuilder::HandleDeclaration(VariableProxy* proxy,
- VariableMode mode,
- FunctionLiteral* function,
- int* global_count) {
- Variable* var = proxy->var();
- bool binding_needs_init =
- (mode == CONST || mode == CONST_HARMONY || mode == LET);
- switch (var->location()) {
+void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ VariableMode mode = declaration->mode();
+ Variable* variable = proxy->var();
+ bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
+ switch (variable->location()) {
case Variable::UNALLOCATED:
- ++(*global_count);
+ globals_.Add(variable->name());
+ globals_.Add(variable->binding_needs_init()
+ ? isolate()->factory()->the_hole_value()
+ : isolate()->factory()->undefined_value());
return;
case Variable::PARAMETER:
case Variable::LOCAL:
+ if (hole_init) {
+ HValue* value = graph()->GetConstantHole();
+ environment()->Bind(variable, value);
+ }
+ break;
case Variable::CONTEXT:
- if (binding_needs_init || function != NULL) {
- HValue* value = NULL;
- if (function != NULL) {
- CHECK_ALIVE(VisitForValue(function));
- value = Pop();
- } else {
- value = graph()->GetConstantHole();
- }
- if (var->IsContextSlot()) {
- HValue* context = environment()->LookupContext();
- HStoreContextSlot* store = new HStoreContextSlot(
- context, var->index(), HStoreContextSlot::kNoCheck, value);
- AddInstruction(store);
- if (store->HasObservableSideEffects()) AddSimulate(proxy->id());
- } else {
- environment()->Bind(var, value);
- }
+ if (hole_init) {
+ HValue* value = graph()->GetConstantHole();
+ HValue* context = environment()->LookupContext();
+ HStoreContextSlot* store = new HStoreContextSlot(
+ context, variable->index(), HStoreContextSlot::kNoCheck, value);
+ AddInstruction(store);
+ if (store->HasObservableSideEffects()) AddSimulate(proxy->id());
}
break;
case Variable::LOOKUP:
@@ -7112,48 +7793,74 @@ void HGraphBuilder::HandleDeclaration(VariableProxy* proxy,
}
-void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) {
- UNREACHABLE();
-}
-
-
-void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) {
- UNREACHABLE();
+void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED: {
+ globals_.Add(variable->name());
+ Handle<SharedFunctionInfo> function =
+ Compiler::BuildFunctionInfo(declaration->fun(), info()->script());
+ // Check for stack-overflow exception.
+ if (function.is_null()) return SetStackOverflow();
+ globals_.Add(function);
+ return;
+ }
+ case Variable::PARAMETER:
+ case Variable::LOCAL: {
+ CHECK_ALIVE(VisitForValue(declaration->fun()));
+ HValue* value = Pop();
+ environment()->Bind(variable, value);
+ break;
+ }
+ case Variable::CONTEXT: {
+ CHECK_ALIVE(VisitForValue(declaration->fun()));
+ HValue* value = Pop();
+ HValue* context = environment()->LookupContext();
+ HStoreContextSlot* store = new HStoreContextSlot(
+ context, variable->index(), HStoreContextSlot::kNoCheck, value);
+ AddInstruction(store);
+ if (store->HasObservableSideEffects()) AddSimulate(proxy->id());
+ break;
+ }
+ case Variable::LOOKUP:
+ return Bailout("unsupported lookup slot in declaration");
+ }
}
-void HGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* decl) {
+void HGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* declaration) {
UNREACHABLE();
}
-void HGraphBuilder::VisitImportDeclaration(ImportDeclaration* decl) {
+void HGraphBuilder::VisitImportDeclaration(ImportDeclaration* declaration) {
UNREACHABLE();
}
-void HGraphBuilder::VisitExportDeclaration(ExportDeclaration* decl) {
+void HGraphBuilder::VisitExportDeclaration(ExportDeclaration* declaration) {
UNREACHABLE();
}
void HGraphBuilder::VisitModuleLiteral(ModuleLiteral* module) {
- // TODO(rossberg)
+ UNREACHABLE();
}
void HGraphBuilder::VisitModuleVariable(ModuleVariable* module) {
- // TODO(rossberg)
+ UNREACHABLE();
}
void HGraphBuilder::VisitModulePath(ModulePath* module) {
- // TODO(rossberg)
+ UNREACHABLE();
}
void HGraphBuilder::VisitModuleUrl(ModuleUrl* module) {
- // TODO(rossberg)
+ UNREACHABLE();
}
@@ -7274,7 +7981,8 @@ void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) {
// function is blacklisted by AstNode::IsInlineable.
ASSERT(function_state()->outer() == NULL);
ASSERT(call->arguments()->length() == 0);
- HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
+ HInstruction* elements = AddInstruction(
+ new(zone()) HArgumentsElements(false));
HArgumentsLength* result = new(zone()) HArgumentsLength(elements);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -7288,7 +7996,8 @@ void HGraphBuilder::GenerateArguments(CallRuntime* call) {
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* index = Pop();
- HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
+ HInstruction* elements = AddInstruction(
+ new(zone()) HArgumentsElements(false));
HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements));
HAccessArgumentsAt* result =
new(zone()) HAccessArgumentsAt(elements, length, index);
@@ -7511,14 +8220,6 @@ void HGraphBuilder::GenerateNumberToString(CallRuntime* call) {
}
-// Fast swapping of elements. Takes three expressions, the object and two
-// indices. This should only be used if the indices are known to be
-// non-negative and within bounds of the elements array at the call site.
-void HGraphBuilder::GenerateSwapElements(CallRuntime* call) {
- return Bailout("inlined runtime function: SwapElements");
-}
-
-
// Fast call for custom callbacks.
void HGraphBuilder::GenerateCallFunction(CallRuntime* call) {
// 1 ~ The function to call is not itself an argument to the call.
diff --git a/src/3rdparty/v8/src/hydrogen.h b/src/3rdparty/v8/src/hydrogen.h
index bc9bc9d..b56a5af 100644
--- a/src/3rdparty/v8/src/hydrogen.h
+++ b/src/3rdparty/v8/src/hydrogen.h
@@ -42,6 +42,7 @@ namespace internal {
// Forward declarations.
class BitVector;
+class FunctionState;
class HEnvironment;
class HGraph;
class HLoopInformation;
@@ -121,7 +122,7 @@ class HBasicBlock: public ZoneObject {
void Finish(HControlInstruction* last);
void FinishExit(HControlInstruction* instruction);
- void Goto(HBasicBlock* block, bool drop_extra = false);
+ void Goto(HBasicBlock* block, FunctionState* state = NULL);
int PredecessorIndexOf(HBasicBlock* predecessor) const;
void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); }
@@ -136,7 +137,7 @@ class HBasicBlock: public ZoneObject {
// instruction and updating the bailout environment.
void AddLeaveInlined(HValue* return_value,
HBasicBlock* target,
- bool drop_extra = false);
+ FunctionState* state = NULL);
// If a target block is tagged as an inline function return, all
// predecessors should contain the inlined exit sequence:
@@ -240,7 +241,7 @@ class HLoopInformation: public ZoneObject {
HStackCheck* stack_check_;
};
-
+class BoundsCheckTable;
class HGraph: public ZoneObject {
public:
explicit HGraph(CompilationInfo* info);
@@ -265,6 +266,8 @@ class HGraph: public ZoneObject {
void OrderBlocks();
void AssignDominators();
void ReplaceCheckedValues();
+ void EliminateRedundantBoundsChecks();
+ void DehoistSimpleArrayIndexComputations();
void PropagateDeoptimizingMark();
// Returns false if there are phi-uses of the arguments-object
@@ -357,6 +360,7 @@ class HGraph: public ZoneObject {
void InferTypes(ZoneList<HValue*>* worklist);
void InitializeInferredTypes(int from_inclusive, int to_inclusive);
void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
+ void EliminateRedundantBoundsChecks(HBasicBlock* bb, BoundsCheckTable* table);
Isolate* isolate_;
int next_block_id_;
@@ -715,6 +719,16 @@ class FunctionState {
FunctionState* outer() { return outer_; }
+ HEnterInlined* entry() { return entry_; }
+ void set_entry(HEnterInlined* entry) { entry_ = entry; }
+
+ HArgumentsElements* arguments_elements() { return arguments_elements_; }
+ void set_arguments_elements(HArgumentsElements* arguments_elements) {
+ arguments_elements_ = arguments_elements;
+ }
+
+ bool arguments_pushed() { return arguments_elements() != NULL; }
+
private:
HGraphBuilder* owner_;
@@ -741,6 +755,12 @@ class FunctionState {
// return blocks. NULL in all other cases.
TestContext* test_context_;
+ // When inlining HEnterInlined instruction corresponding to the function
+ // entry.
+ HEnterInlined* entry_;
+
+ HArgumentsElements* arguments_elements_;
+
FunctionState* outer_;
};
@@ -851,15 +871,11 @@ class HGraphBuilder: public AstVisitor {
static const int kMaxLoadPolymorphism = 4;
static const int kMaxStorePolymorphism = 4;
- static const int kMaxInlinedNodes = 196;
- static const int kMaxInlinedSize = 196;
- static const int kMaxSourceSize = 600;
-
// Even in the 'unlimited' case we have to have some limit in order not to
// overflow the stack.
- static const int kUnlimitedMaxInlinedNodes = 1000;
- static const int kUnlimitedMaxInlinedSize = 1000;
- static const int kUnlimitedMaxSourceSize = 600;
+ static const int kUnlimitedMaxInlinedSourceSize = 100000;
+ static const int kUnlimitedMaxInlinedNodes = 10000;
+ static const int kUnlimitedMaxInlinedNodesCumulative = 10000;
// Simple accessors.
void set_function_state(FunctionState* state) { function_state_ = state; }
@@ -896,11 +912,6 @@ class HGraphBuilder: public AstVisitor {
INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
#undef INLINE_FUNCTION_GENERATOR_DECLARATION
- void HandleDeclaration(VariableProxy* proxy,
- VariableMode mode,
- FunctionLiteral* function,
- int* global_count);
-
void VisitDelete(UnaryOperation* expr);
void VisitVoid(UnaryOperation* expr);
void VisitTypeof(UnaryOperation* expr);
@@ -994,11 +1005,13 @@ class HGraphBuilder: public AstVisitor {
LookupResult* lookup,
bool is_store);
+ void EnsureArgumentsArePushedForAccess();
bool TryArgumentsAccess(Property* expr);
// Try to optimize fun.apply(receiver, arguments) pattern.
bool TryCallApply(Call* expr);
+ int InliningAstSize(Handle<JSFunction> target);
bool TryInline(CallKind call_kind,
Handle<JSFunction> target,
ZoneList<Expression*>* arguments,
@@ -1149,6 +1162,7 @@ class HGraphBuilder: public AstVisitor {
HBasicBlock* current_block_;
int inlined_count_;
+ ZoneList<Handle<Object> > globals_;
Zone* zone_;
@@ -1223,6 +1237,30 @@ class HValueMap: public ZoneObject {
};
+class HSideEffectMap BASE_EMBEDDED {
+ public:
+ HSideEffectMap();
+ explicit HSideEffectMap(HSideEffectMap* other);
+
+ void Kill(GVNFlagSet flags);
+
+ void Store(GVNFlagSet flags, HInstruction* instr);
+
+ bool IsEmpty() const { return count_ == 0; }
+
+ inline HInstruction* operator[](int i) const {
+ ASSERT(0 <= i);
+ ASSERT(i < kNumberOfTrackedSideEffects);
+ return data_[i];
+ }
+ inline HInstruction* at(int i) const { return operator[](i); }
+
+ private:
+ int count_;
+ HInstruction* data_[kNumberOfTrackedSideEffects];
+};
+
+
class HStatistics: public Malloced {
public:
void Initialize(CompilationInfo* info);
diff --git a/src/3rdparty/v8/src/ia32/assembler-ia32.h b/src/3rdparty/v8/src/ia32/assembler-ia32.h
index 929b485..4ead80b 100644
--- a/src/3rdparty/v8/src/ia32/assembler-ia32.h
+++ b/src/3rdparty/v8/src/ia32/assembler-ia32.h
@@ -640,6 +640,9 @@ class Assembler : public AssemblerBase {
static const byte kJccShortPrefix = 0x70;
static const byte kJncShortOpcode = kJccShortPrefix | not_carry;
static const byte kJcShortOpcode = kJccShortPrefix | carry;
+ static const byte kJnzShortOpcode = kJccShortPrefix | not_zero;
+ static const byte kJzShortOpcode = kJccShortPrefix | zero;
+
// ---------------------------------------------------------------------------
// Code generation
diff --git a/src/3rdparty/v8/src/ia32/builtins-ia32.cc b/src/3rdparty/v8/src/ia32/builtins-ia32.cc
index a5d42cf..a36763d 100644
--- a/src/3rdparty/v8/src/ia32/builtins-ia32.cc
+++ b/src/3rdparty/v8/src/ia32/builtins-ia32.cc
@@ -831,7 +831,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
// Copy all arguments from the array to the stack.
Label entry, loop;
- __ mov(eax, Operand(ebp, kIndexOffset));
+ __ mov(ecx, Operand(ebp, kIndexOffset));
__ jmp(&entry);
__ bind(&loop);
__ mov(edx, Operand(ebp, kArgumentsOffset)); // load arguments
@@ -848,16 +848,17 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ push(eax);
// Update the index on the stack and in register eax.
- __ mov(eax, Operand(ebp, kIndexOffset));
- __ add(eax, Immediate(1 << kSmiTagSize));
- __ mov(Operand(ebp, kIndexOffset), eax);
+ __ mov(ecx, Operand(ebp, kIndexOffset));
+ __ add(ecx, Immediate(1 << kSmiTagSize));
+ __ mov(Operand(ebp, kIndexOffset), ecx);
__ bind(&entry);
- __ cmp(eax, Operand(ebp, kLimitOffset));
+ __ cmp(ecx, Operand(ebp, kLimitOffset));
__ j(not_equal, &loop);
// Invoke the function.
Label call_proxy;
+ __ mov(eax, ecx);
ParameterCount actual(eax);
__ SmiUntag(eax);
__ mov(edi, Operand(ebp, kFunctionOffset));
diff --git a/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc b/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc
index 2568dae..a1c6edd 100644
--- a/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc
+++ b/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc
@@ -145,11 +145,6 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
__ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx);
- // Copy the qml global object from the previous context.
- __ mov(ebx, Operand(esi, Context::SlotOffset(Context::QML_GLOBAL_INDEX)));
- __ mov(Operand(eax, Context::SlotOffset(Context::QML_GLOBAL_INDEX)), ebx);
-
-
// Initialize the rest of the slots to undefined.
__ mov(ebx, factory->undefined_value());
for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
@@ -216,10 +211,6 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
__ mov(ebx, ContextOperand(esi, Context::GLOBAL_INDEX));
__ mov(ContextOperand(eax, Context::GLOBAL_INDEX), ebx);
- // Copy the qml global object from the previous context.
- __ mov(ebx, ContextOperand(esi, Context::QML_GLOBAL_INDEX));
- __ mov(ContextOperand(eax, Context::QML_GLOBAL_INDEX), ebx);
-
// Initialize the rest of the slots to the hole value.
if (slots_ == 1) {
__ mov(ContextOperand(eax, Context::MIN_CONTEXT_SLOTS),
@@ -1690,6 +1681,11 @@ void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
}
+// Input:
+// edx: left operand (tagged)
+// eax: right operand (tagged)
+// Output:
+// eax: result (tagged)
void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
Label call_runtime;
ASSERT(operands_type_ == BinaryOpIC::INT32);
@@ -1699,31 +1695,37 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
case Token::ADD:
case Token::SUB:
case Token::MUL:
- case Token::DIV: {
+ case Token::DIV:
+ case Token::MOD: {
Label not_floats;
Label not_int32;
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx);
- switch (op_) {
- case Token::ADD: __ addsd(xmm0, xmm1); break;
- case Token::SUB: __ subsd(xmm0, xmm1); break;
- case Token::MUL: __ mulsd(xmm0, xmm1); break;
- case Token::DIV: __ divsd(xmm0, xmm1); break;
- default: UNREACHABLE();
- }
- // Check result type if it is currently Int32.
- if (result_type_ <= BinaryOpIC::INT32) {
- __ cvttsd2si(ecx, Operand(xmm0));
- __ cvtsi2sd(xmm2, ecx);
- __ ucomisd(xmm0, xmm2);
- __ j(not_zero, &not_int32);
- __ j(carry, &not_int32);
+ if (op_ == Token::MOD) {
+ GenerateRegisterArgsPush(masm);
+ __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
+ } else {
+ switch (op_) {
+ case Token::ADD: __ addsd(xmm0, xmm1); break;
+ case Token::SUB: __ subsd(xmm0, xmm1); break;
+ case Token::MUL: __ mulsd(xmm0, xmm1); break;
+ case Token::DIV: __ divsd(xmm0, xmm1); break;
+ default: UNREACHABLE();
+ }
+ // Check result type if it is currently Int32.
+ if (result_type_ <= BinaryOpIC::INT32) {
+ __ cvttsd2si(ecx, Operand(xmm0));
+ __ cvtsi2sd(xmm2, ecx);
+ __ ucomisd(xmm0, xmm2);
+ __ j(not_zero, &not_int32);
+ __ j(carry, &not_int32);
+ }
+ GenerateHeapResultAllocation(masm, &call_runtime);
+ __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
+ __ ret(0);
}
- GenerateHeapResultAllocation(masm, &call_runtime);
- __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
- __ ret(0);
} else { // SSE2 not available, use FPU.
FloatingPointHelper::CheckFloatOperands(masm, &not_floats, ebx);
FloatingPointHelper::LoadFloatOperands(
@@ -1731,20 +1733,28 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
ecx,
FloatingPointHelper::ARGS_IN_REGISTERS);
FloatingPointHelper::CheckFloatOperandsAreInt32(masm, &not_int32);
- switch (op_) {
- case Token::ADD: __ faddp(1); break;
- case Token::SUB: __ fsubp(1); break;
- case Token::MUL: __ fmulp(1); break;
- case Token::DIV: __ fdivp(1); break;
- default: UNREACHABLE();
+ if (op_ == Token::MOD) {
+ // The operands are now on the FPU stack, but we don't need them.
+ __ fstp(0);
+ __ fstp(0);
+ GenerateRegisterArgsPush(masm);
+ __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
+ } else {
+ switch (op_) {
+ case Token::ADD: __ faddp(1); break;
+ case Token::SUB: __ fsubp(1); break;
+ case Token::MUL: __ fmulp(1); break;
+ case Token::DIV: __ fdivp(1); break;
+ default: UNREACHABLE();
+ }
+ Label after_alloc_failure;
+ GenerateHeapResultAllocation(masm, &after_alloc_failure);
+ __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
+ __ ret(0);
+ __ bind(&after_alloc_failure);
+ __ fstp(0); // Pop FPU stack before calling runtime.
+ __ jmp(&call_runtime);
}
- Label after_alloc_failure;
- GenerateHeapResultAllocation(masm, &after_alloc_failure);
- __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
- __ ret(0);
- __ bind(&after_alloc_failure);
- __ ffree();
- __ jmp(&call_runtime);
}
__ bind(&not_floats);
@@ -1753,10 +1763,6 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
break;
}
- case Token::MOD: {
- // For MOD we go directly to runtime in the non-smi case.
- break;
- }
case Token::BIT_OR:
case Token::BIT_AND:
case Token::BIT_XOR:
@@ -1767,11 +1773,6 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
Label not_floats;
Label not_int32;
Label non_smi_result;
- /* {
- CpuFeatures::Scope use_sse2(SSE2);
- FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
- FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx);
- }*/
FloatingPointHelper::LoadUnknownsAsIntegers(masm,
use_sse3_,
&not_floats);
@@ -1842,8 +1843,8 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
default: UNREACHABLE(); break;
}
- // If an allocation fails, or SHR or MOD hit a hard case,
- // use the runtime system to get the correct result.
+ // If an allocation fails, or SHR hits a hard case, use the runtime system to
+ // get the correct result.
__ bind(&call_runtime);
switch (op_) {
@@ -1864,8 +1865,6 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
__ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
break;
case Token::MOD:
- GenerateRegisterArgsPush(masm);
- __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
break;
case Token::BIT_OR:
__ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
@@ -1966,7 +1965,7 @@ void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ ret(0);
__ bind(&after_alloc_failure);
- __ ffree();
+ __ fstp(0); // Pop FPU stack before calling runtime.
__ jmp(&call_runtime);
}
@@ -2170,8 +2169,8 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ ret(0);
__ bind(&after_alloc_failure);
- __ ffree();
- __ jmp(&call_runtime);
+ __ fstp(0); // Pop FPU stack before calling runtime.
+ __ jmp(&call_runtime);
}
__ bind(&not_floats);
break;
@@ -4261,39 +4260,6 @@ void CompareStub::Generate(MacroAssembler* masm) {
// NOTICE! This code is only reached after a smi-fast-case check, so
// it is certain that at least one operand isn't a smi.
- {
- Label not_user_equal, user_equal;
- __ test(eax, Immediate(kSmiTagMask));
- __ j(zero, &not_user_equal);
- __ test(edx, Immediate(kSmiTagMask));
- __ j(zero, &not_user_equal);
-
- __ CmpObjectType(eax, JS_OBJECT_TYPE, ebx);
- __ j(not_equal, &not_user_equal);
-
- __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
- __ j(not_equal, &not_user_equal);
-
- __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
- 1 << Map::kUseUserObjectComparison);
- __ j(not_zero, &user_equal);
- __ test_b(FieldOperand(ecx, Map::kBitField2Offset),
- 1 << Map::kUseUserObjectComparison);
- __ j(not_zero, &user_equal);
-
- __ jmp(&not_user_equal);
-
- __ bind(&user_equal);
-
- __ pop(ebx); // Return address.
- __ push(eax);
- __ push(edx);
- __ push(ebx);
- __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
-
- __ bind(&not_user_equal);
- }
-
// Identical objects can be compared fast, but there are some tricky cases
// for NaN and undefined.
{
@@ -5048,11 +5014,9 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
__ j(not_equal, &not_outermost_js, Label::kNear);
__ mov(Operand::StaticVariable(js_entry_sp), ebp);
__ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
- Label cont;
- __ jmp(&cont, Label::kNear);
+ __ jmp(&invoke, Label::kNear);
__ bind(&not_outermost_js);
__ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)));
- __ bind(&cont);
// Jump to a faked try block that does the invoke, with a faked catch
// block that sets the pending exception.
@@ -6204,7 +6168,11 @@ void SubStringStub::Generate(MacroAssembler* masm) {
__ sub(ecx, edx);
__ cmp(ecx, FieldOperand(eax, String::kLengthOffset));
Label not_original_string;
- __ j(not_equal, &not_original_string, Label::kNear);
+ // Shorter than original string's length: an actual substring.
+ __ j(below, &not_original_string, Label::kNear);
+ // Longer than original string's length or negative: unsafe arguments.
+ __ j(above, &runtime);
+ // Return original string.
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->sub_string_native(), 1);
__ ret(3 * kPointerSize);
@@ -6783,14 +6751,8 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
__ j(not_equal, &miss, Label::kNear);
- __ test_b(FieldOperand(ecx, Map::kBitField2Offset),
- 1 << Map::kUseUserObjectComparison);
- __ j(not_zero, &miss, Label::kNear);
__ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
__ j(not_equal, &miss, Label::kNear);
- __ test_b(FieldOperand(ecx, Map::kBitField2Offset),
- 1 << Map::kUseUserObjectComparison);
- __ j(not_zero, &miss, Label::kNear);
ASSERT(GetCondition() == equal);
__ sub(eax, edx);
@@ -6811,14 +6773,8 @@ void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
__ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
__ cmp(ecx, known_map_);
__ j(not_equal, &miss, Label::kNear);
- __ test_b(FieldOperand(ecx, Map::kBitField2Offset),
- 1 << Map::kUseUserObjectComparison);
- __ j(not_zero, &miss, Label::kNear);
__ cmp(ebx, known_map_);
__ j(not_equal, &miss, Label::kNear);
- __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
- 1 << Map::kUseUserObjectComparison);
- __ j(not_zero, &miss, Label::kNear);
__ sub(eax, edx);
__ ret(0);
diff --git a/src/3rdparty/v8/src/ia32/codegen-ia32.cc b/src/3rdparty/v8/src/ia32/codegen-ia32.cc
index ea61910..cff6454 100644
--- a/src/3rdparty/v8/src/ia32/codegen-ia32.cc
+++ b/src/3rdparty/v8/src/ia32/codegen-ia32.cc
@@ -397,9 +397,25 @@ void ElementsTransitionGenerator::GenerateSmiOnlyToDouble(
// Allocate new FixedDoubleArray.
// edx: receiver
// edi: length of source FixedArray (smi-tagged)
- __ lea(esi, Operand(edi, times_4, FixedDoubleArray::kHeaderSize));
+ __ lea(esi, Operand(edi,
+ times_4,
+ FixedDoubleArray::kHeaderSize + kPointerSize));
__ AllocateInNewSpace(esi, eax, ebx, no_reg, &gc_required, TAG_OBJECT);
+ Label aligned, aligned_done;
+ __ test(eax, Immediate(kDoubleAlignmentMask - kHeapObjectTag));
+ __ j(zero, &aligned, Label::kNear);
+ __ mov(FieldOperand(eax, 0),
+ Immediate(masm->isolate()->factory()->one_pointer_filler_map()));
+ __ add(eax, Immediate(kPointerSize));
+ __ jmp(&aligned_done);
+
+ __ bind(&aligned);
+ __ mov(Operand(eax, esi, times_1, -kPointerSize-1),
+ Immediate(masm->isolate()->factory()->one_pointer_filler_map()));
+
+ __ bind(&aligned_done);
+
// eax: destination FixedDoubleArray
// edi: number of elements
// edx: receiver
diff --git a/src/3rdparty/v8/src/ia32/debug-ia32.cc b/src/3rdparty/v8/src/ia32/debug-ia32.cc
index d13fa75..d153e18 100644
--- a/src/3rdparty/v8/src/ia32/debug-ia32.cc
+++ b/src/3rdparty/v8/src/ia32/debug-ia32.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -91,9 +91,11 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() {
rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
}
+// All debug break stubs support padding for LiveEdit.
+const bool Debug::FramePaddingLayout::kIsSupported = true;
-#define __ ACCESS_MASM(masm)
+#define __ ACCESS_MASM(masm)
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
RegList object_regs,
@@ -103,6 +105,13 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
{
FrameScope scope(masm, StackFrame::INTERNAL);
+ // Load padding words on stack.
+ for (int i = 0; i < Debug::FramePaddingLayout::kInitialSize; i++) {
+ __ push(Immediate(Smi::FromInt(
+ Debug::FramePaddingLayout::kPaddingValue)));
+ }
+ __ push(Immediate(Smi::FromInt(Debug::FramePaddingLayout::kInitialSize)));
+
// Store the registers containing live values on the expression stack to
// make sure that these are correctly updated during GC. Non object values
// are stored as a smi causing it to be untouched by GC.
@@ -134,6 +143,10 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
CEntryStub ceb(1);
__ CallStub(&ceb);
+ // Automatically find register that could be used after register restore.
+ // We need one register for padding skip instructions.
+ Register unused_reg = { -1 };
+
// Restore the register values containing object pointers from the
// expression stack.
for (int i = kNumJSCallerSaved; --i >= 0;) {
@@ -142,15 +155,29 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
if (FLAG_debug_code) {
__ Set(reg, Immediate(kDebugZapValue));
}
+ bool taken = reg.code() == esi.code();
if ((object_regs & (1 << r)) != 0) {
__ pop(reg);
+ taken = true;
}
if ((non_object_regs & (1 << r)) != 0) {
__ pop(reg);
__ SmiUntag(reg);
+ taken = true;
+ }
+ if (!taken) {
+ unused_reg = reg;
}
}
+ ASSERT(unused_reg.code() != -1);
+
+ // Read current padding counter and skip corresponding number of words.
+ __ pop(unused_reg);
+ // We divide stored value by 2 (untagging) and multiply it by word's size.
+ STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0);
+ __ lea(esp, Operand(esp, unused_reg, times_half_pointer_size, 0));
+
// Get rid of the internal frame.
}
@@ -172,10 +199,10 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
// Register state for IC load call (from ic-ia32.cc).
// ----------- S t a t e -------------
- // -- eax : receiver
// -- ecx : name
+ // -- edx : receiver
// -----------------------------------
- Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit(), 0, false);
+ Generate_DebugBreakCallHelper(masm, ecx.bit() | edx.bit(), 0, false);
}
@@ -194,10 +221,10 @@ void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
// Register state for keyed IC load call (from ic-ia32.cc).
// ----------- S t a t e -------------
+ // -- ecx : key
// -- edx : receiver
- // -- eax : key
// -----------------------------------
- Generate_DebugBreakCallHelper(masm, eax.bit() | edx.bit(), 0, false);
+ Generate_DebugBreakCallHelper(masm, ecx.bit() | edx.bit(), 0, false);
}
diff --git a/src/3rdparty/v8/src/ia32/deoptimizer-ia32.cc b/src/3rdparty/v8/src/ia32/deoptimizer-ia32.cc
index 3f10c09..73961e1 100644
--- a/src/3rdparty/v8/src/ia32/deoptimizer-ia32.cc
+++ b/src/3rdparty/v8/src/ia32/deoptimizer-ia32.cc
@@ -548,6 +548,8 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
int frame_index) {
+ Builtins* builtins = isolate_->builtins();
+ Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
unsigned height = iterator->Next();
unsigned height_in_bytes = height * kPointerSize;
@@ -555,7 +557,7 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
PrintF(" translating construct stub => height=%d\n", height_in_bytes);
}
- unsigned fixed_frame_size = 6 * kPointerSize;
+ unsigned fixed_frame_size = 7 * kPointerSize;
unsigned output_frame_size = height_in_bytes + fixed_frame_size;
// Allocate and store the output frame description.
@@ -620,6 +622,15 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
top_address + output_offset, output_offset, value);
}
+ // The output frame reflects a JSConstructStubGeneric frame.
+ output_offset -= kPointerSize;
+ value = reinterpret_cast<intptr_t>(construct_stub);
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; code object\n",
+ top_address + output_offset, output_offset, value);
+ }
+
// Number of incoming arguments.
output_offset -= kPointerSize;
value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1));
@@ -641,8 +652,6 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
ASSERT(0 == output_offset);
- Builtins* builtins = isolate_->builtins();
- Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
uint32_t pc = reinterpret_cast<uint32_t>(
construct_stub->instruction_start() +
isolate_->heap()->construct_stub_deopt_pc_offset()->value());
diff --git a/src/3rdparty/v8/src/ia32/full-codegen-ia32.cc b/src/3rdparty/v8/src/ia32/full-codegen-ia32.cc
index 203aa36..266afce 100644
--- a/src/3rdparty/v8/src/ia32/full-codegen-ia32.cc
+++ b/src/3rdparty/v8/src/ia32/full-codegen-ia32.cc
@@ -175,13 +175,12 @@ void FullCodeGenerator::Generate() {
// Possibly allocate a local context.
int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
- if (heap_slots > 0 ||
- (scope()->is_qml_mode() && scope()->is_global_scope())) {
+ if (heap_slots > 0) {
Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is still in edi.
__ push(edi);
if (heap_slots <= FastNewContextStub::kMaximumSlots) {
- FastNewContextStub stub((heap_slots < 0)?0:heap_slots);
+ FastNewContextStub stub(heap_slots);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kNewFunctionContext, 1);
@@ -263,11 +262,11 @@ void FullCodeGenerator::Generate() {
// For named function expressions, declare the function name as a
// constant.
if (scope()->is_function_scope() && scope()->function() != NULL) {
- VariableProxy* proxy = scope()->function();
- ASSERT(proxy->var()->mode() == CONST ||
- proxy->var()->mode() == CONST_HARMONY);
- ASSERT(proxy->var()->location() != Variable::UNALLOCATED);
- EmitDeclaration(proxy, proxy->var()->mode(), NULL);
+ VariableDeclaration* function = scope()->function();
+ ASSERT(function->proxy()->var()->mode() == CONST ||
+ function->proxy()->var()->mode() == CONST_HARMONY);
+ ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED);
+ VisitVariableDeclaration(function);
}
VisitDeclarations(scope()->declarations());
}
@@ -757,60 +756,51 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
}
-void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
- VariableMode mode,
- FunctionLiteral* function) {
+void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
+ // The variable in the declaration always resides in the current function
+ // context.
+ ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
+ if (FLAG_debug_code) {
+ // Check that we're not inside a with or catch context.
+ __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
+ __ cmp(ebx, isolate()->factory()->with_context_map());
+ __ Check(not_equal, "Declaration in with context.");
+ __ cmp(ebx, isolate()->factory()->catch_context_map());
+ __ Check(not_equal, "Declaration in catch context.");
+ }
+}
+
+
+void FullCodeGenerator::VisitVariableDeclaration(
+ VariableDeclaration* declaration) {
// If it was not possible to allocate the variable at compile time, we
// need to "declare" it at runtime to make sure it actually exists in the
// local context.
+ VariableProxy* proxy = declaration->proxy();
+ VariableMode mode = declaration->mode();
Variable* variable = proxy->var();
- bool binding_needs_init = (function == NULL) &&
- (mode == CONST || mode == CONST_HARMONY || mode == LET);
+ bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
switch (variable->location()) {
case Variable::UNALLOCATED:
- ++global_count_;
+ globals_->Add(variable->name());
+ globals_->Add(variable->binding_needs_init()
+ ? isolate()->factory()->the_hole_value()
+ : isolate()->factory()->undefined_value());
break;
case Variable::PARAMETER:
case Variable::LOCAL:
- if (function != NULL) {
- Comment cmnt(masm_, "[ Declaration");
- VisitForAccumulatorValue(function);
- __ mov(StackOperand(variable), result_register());
- } else if (binding_needs_init) {
- Comment cmnt(masm_, "[ Declaration");
+ if (hole_init) {
+ Comment cmnt(masm_, "[ VariableDeclaration");
__ mov(StackOperand(variable),
Immediate(isolate()->factory()->the_hole_value()));
}
break;
case Variable::CONTEXT:
- // The variable in the decl always resides in the current function
- // context.
- ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
- if (FLAG_debug_code) {
- // Check that we're not inside a with or catch context.
- __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
- __ cmp(ebx, isolate()->factory()->with_context_map());
- __ Check(not_equal, "Declaration in with context.");
- __ cmp(ebx, isolate()->factory()->catch_context_map());
- __ Check(not_equal, "Declaration in catch context.");
- }
- if (function != NULL) {
- Comment cmnt(masm_, "[ Declaration");
- VisitForAccumulatorValue(function);
- __ mov(ContextOperand(esi, variable->index()), result_register());
- // We know that we have written a function, which is not a smi.
- __ RecordWriteContextSlot(esi,
- Context::SlotOffset(variable->index()),
- result_register(),
- ecx,
- kDontSaveFPRegs,
- EMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
- } else if (binding_needs_init) {
- Comment cmnt(masm_, "[ Declaration");
+ if (hole_init) {
+ Comment cmnt(masm_, "[ VariableDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
__ mov(ContextOperand(esi, variable->index()),
Immediate(isolate()->factory()->the_hole_value()));
// No write barrier since the hole value is in old space.
@@ -819,14 +809,12 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
break;
case Variable::LOOKUP: {
- Comment cmnt(masm_, "[ Declaration");
+ Comment cmnt(masm_, "[ VariableDeclaration");
__ push(esi);
__ push(Immediate(variable->name()));
- // Declaration nodes are always introduced in one of four modes.
- ASSERT(mode == VAR ||
- mode == CONST ||
- mode == CONST_HARMONY ||
- mode == LET);
+ // VariableDeclaration nodes are always introduced in one of four modes.
+ ASSERT(mode == VAR || mode == LET ||
+ mode == CONST || mode == CONST_HARMONY);
PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY)
? READ_ONLY : NONE;
__ push(Immediate(Smi::FromInt(attr)));
@@ -834,9 +822,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
// Note: For variables we must not push an initial value (such as
// 'undefined') because we may have a (legal) redeclaration and we
// must not destroy the current value.
- if (function != NULL) {
- VisitForStackValue(function);
- } else if (binding_needs_init) {
+ if (hole_init) {
__ push(Immediate(isolate()->factory()->the_hole_value()));
} else {
__ push(Immediate(Smi::FromInt(0))); // Indicates no initial value.
@@ -848,6 +834,118 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
}
+void FullCodeGenerator::VisitFunctionDeclaration(
+ FunctionDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED: {
+ globals_->Add(variable->name());
+ Handle<SharedFunctionInfo> function =
+ Compiler::BuildFunctionInfo(declaration->fun(), script());
+ // Check for stack-overflow exception.
+ if (function.is_null()) return SetStackOverflow();
+ globals_->Add(function);
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ VisitForAccumulatorValue(declaration->fun());
+ __ mov(StackOperand(variable), result_register());
+ break;
+ }
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ VisitForAccumulatorValue(declaration->fun());
+ __ mov(ContextOperand(esi, variable->index()), result_register());
+ // We know that we have written a function, which is not a smi.
+ __ RecordWriteContextSlot(esi,
+ Context::SlotOffset(variable->index()),
+ result_register(),
+ ecx,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
+ break;
+ }
+
+ case Variable::LOOKUP: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ __ push(esi);
+ __ push(Immediate(variable->name()));
+ __ push(Immediate(Smi::FromInt(NONE)));
+ VisitForStackValue(declaration->fun());
+ __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ break;
+ }
+ }
+}
+
+
+void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ Handle<JSModule> instance = declaration->module()->interface()->Instance();
+ ASSERT(!instance.is_null());
+
+ switch (variable->location()) {
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "[ ModuleDeclaration");
+ globals_->Add(variable->name());
+ globals_->Add(instance);
+ Visit(declaration->module());
+ break;
+ }
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ ModuleDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ __ mov(ContextOperand(esi, variable->index()), Immediate(instance));
+ Visit(declaration->module());
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::LOOKUP:
+ UNREACHABLE();
+ }
+}
+
+
+void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ // TODO(rossberg)
+ break;
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ ImportDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ // TODO(rossberg)
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::LOOKUP:
+ UNREACHABLE();
+ }
+}
+
+
+void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
+ // TODO(rossberg)
+}
+
+
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
__ push(esi); // The context is the first argument.
@@ -1188,7 +1286,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
// All extension objects were empty and it is safe to use a global
// load IC call.
- __ mov(eax, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ mov(edx, GlobalObjectOperand());
__ mov(ecx, var->name());
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
@@ -1272,7 +1370,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
Comment cmnt(masm_, "Global variable");
// Use inline caching. Variable name is passed in ecx and the global
// object in eax.
- __ mov(eax, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ mov(edx, GlobalObjectOperand());
__ mov(ecx, var->name());
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
@@ -1666,9 +1764,9 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
break;
case NAMED_PROPERTY:
if (expr->is_compound()) {
- // We need the receiver both on the stack and in the accumulator.
- VisitForAccumulatorValue(property->obj());
- __ push(result_register());
+ // We need the receiver both on the stack and in edx.
+ VisitForStackValue(property->obj());
+ __ mov(edx, Operand(esp, 0));
} else {
VisitForStackValue(property->obj());
}
@@ -1676,9 +1774,9 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
case KEYED_PROPERTY: {
if (expr->is_compound()) {
VisitForStackValue(property->obj());
- VisitForAccumulatorValue(property->key());
- __ mov(edx, Operand(esp, 0));
- __ push(eax);
+ VisitForStackValue(property->key());
+ __ mov(edx, Operand(esp, kPointerSize)); // Object.
+ __ mov(ecx, Operand(esp, 0)); // Key.
} else {
VisitForStackValue(property->obj());
VisitForStackValue(property->key());
@@ -1921,7 +2019,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
VisitForStackValue(prop->obj());
VisitForAccumulatorValue(prop->key());
__ mov(ecx, eax);
- __ pop(edx);
+ __ pop(edx); // Receiver.
__ pop(eax); // Restore value.
Handle<Code> ic = is_classic_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize()
@@ -1939,7 +2037,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
if (var->IsUnallocated()) {
// Global var, const, or let.
__ mov(ecx, var->name());
- __ mov(edx, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ mov(edx, GlobalObjectOperand());
Handle<Code> ic = is_classic_mode()
? isolate()->builtins()->StoreIC_Initialize()
: isolate()->builtins()->StoreIC_Initialize_Strict();
@@ -2027,6 +2125,9 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
// Assignment to a property, using a named store IC.
+ // eax : value
+ // esp[0] : receiver
+
Property* prop = expr->target()->AsProperty();
ASSERT(prop != NULL);
ASSERT(prop->key()->AsLiteral() != NULL);
@@ -2069,6 +2170,9 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
// Assignment to a property, using a keyed store IC.
+ // eax : value
+ // esp[0] : key
+ // esp[kPointerSize] : receiver
// If the assignment starts a block of assignments to the same object,
// change to slow case to avoid the quadratic behavior of repeatedly
@@ -2081,7 +2185,7 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
__ pop(result_register());
}
- __ pop(ecx);
+ __ pop(ecx); // Key.
if (expr->ends_initialization_block()) {
__ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later.
} else {
@@ -2114,12 +2218,14 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
if (key->IsPropertyName()) {
VisitForAccumulatorValue(expr->obj());
+ __ mov(edx, result_register());
EmitNamedPropertyLoad(expr);
context()->Plug(eax);
} else {
VisitForStackValue(expr->obj());
VisitForAccumulatorValue(expr->key());
- __ pop(edx);
+ __ pop(edx); // Object.
+ __ mov(ecx, result_register()); // Key.
EmitKeyedPropertyLoad(expr);
context()->Plug(eax);
}
@@ -2242,11 +2348,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
// Push the start position of the scope the calls resides in.
__ push(Immediate(Smi::FromInt(scope()->start_position())));
- // Push the qml mode flag
- __ push(Immediate(Smi::FromInt(is_qml_mode())));
-
// Do the runtime call.
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
}
@@ -2299,7 +2402,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} else if (proxy != NULL && proxy->var()->IsUnallocated()) {
// Push global object as receiver for the call IC.
- __ push(proxy->var()->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ push(GlobalObjectOperand());
EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
} else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
@@ -3302,99 +3405,6 @@ void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
}
-void FullCodeGenerator::EmitSwapElements(CallRuntime* expr) {
- ZoneList<Expression*>* args = expr->arguments();
- ASSERT(args->length() == 3);
- VisitForStackValue(args->at(0));
- VisitForStackValue(args->at(1));
- VisitForStackValue(args->at(2));
- Label done;
- Label slow_case;
- Register object = eax;
- Register index_1 = ebx;
- Register index_2 = ecx;
- Register elements = edi;
- Register temp = edx;
- __ mov(object, Operand(esp, 2 * kPointerSize));
- // Fetch the map and check if array is in fast case.
- // Check that object doesn't require security checks and
- // has no indexed interceptor.
- __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
- __ j(not_equal, &slow_case);
- __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
- KeyedLoadIC::kSlowCaseBitFieldMask);
- __ j(not_zero, &slow_case);
-
- // Check the object's elements are in fast case and writable.
- __ mov(elements, FieldOperand(object, JSObject::kElementsOffset));
- __ cmp(FieldOperand(elements, HeapObject::kMapOffset),
- Immediate(isolate()->factory()->fixed_array_map()));
- __ j(not_equal, &slow_case);
-
- // Check that both indices are smis.
- __ mov(index_1, Operand(esp, 1 * kPointerSize));
- __ mov(index_2, Operand(esp, 0));
- __ mov(temp, index_1);
- __ or_(temp, index_2);
- __ JumpIfNotSmi(temp, &slow_case);
-
- // Check that both indices are valid.
- __ mov(temp, FieldOperand(object, JSArray::kLengthOffset));
- __ cmp(temp, index_1);
- __ j(below_equal, &slow_case);
- __ cmp(temp, index_2);
- __ j(below_equal, &slow_case);
-
- // Bring addresses into index1 and index2.
- __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1));
- __ lea(index_2, CodeGenerator::FixedArrayElementOperand(elements, index_2));
-
- // Swap elements. Use object and temp as scratch registers.
- __ mov(object, Operand(index_1, 0));
- __ mov(temp, Operand(index_2, 0));
- __ mov(Operand(index_2, 0), object);
- __ mov(Operand(index_1, 0), temp);
-
- Label no_remembered_set;
- __ CheckPageFlag(elements,
- temp,
- 1 << MemoryChunk::SCAN_ON_SCAVENGE,
- not_zero,
- &no_remembered_set,
- Label::kNear);
- // Possible optimization: do a check that both values are Smis
- // (or them and test against Smi mask.)
-
- // We are swapping two objects in an array and the incremental marker never
- // pauses in the middle of scanning a single object. Therefore the
- // incremental marker is not disturbed, so we don't need to call the
- // RecordWrite stub that notifies the incremental marker.
- __ RememberedSetHelper(elements,
- index_1,
- temp,
- kDontSaveFPRegs,
- MacroAssembler::kFallThroughAtEnd);
- __ RememberedSetHelper(elements,
- index_2,
- temp,
- kDontSaveFPRegs,
- MacroAssembler::kFallThroughAtEnd);
-
- __ bind(&no_remembered_set);
-
- // We are done. Drop elements from the stack, and return undefined.
- __ add(esp, Immediate(3 * kPointerSize));
- __ mov(eax, isolate()->factory()->undefined_value());
- __ jmp(&done);
-
- __ bind(&slow_case);
- __ CallRuntime(Runtime::kSwapElements, 3);
-
- __ bind(&done);
- context()->Plug(eax);
-}
-
-
void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(2, args->length());
@@ -3849,7 +3859,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
// but "delete this" is allowed.
ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
if (var->IsUnallocated()) {
- __ push(var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ __ push(GlobalObjectOperand());
__ push(Immediate(var->name()));
__ push(Immediate(Smi::FromInt(kNonStrictMode)));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
@@ -4014,15 +4024,16 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
__ push(Immediate(Smi::FromInt(0)));
}
if (assign_type == NAMED_PROPERTY) {
- // Put the object both on the stack and in the accumulator.
+ // Put the object both on the stack and in edx.
VisitForAccumulatorValue(prop->obj());
__ push(eax);
+ __ mov(edx, eax);
EmitNamedPropertyLoad(prop);
} else {
VisitForStackValue(prop->obj());
- VisitForAccumulatorValue(prop->key());
- __ mov(edx, Operand(esp, 0));
- __ push(eax);
+ VisitForStackValue(prop->key());
+ __ mov(edx, Operand(esp, kPointerSize)); // Object.
+ __ mov(ecx, Operand(esp, 0)); // Key.
EmitKeyedPropertyLoad(prop);
}
}
@@ -4169,7 +4180,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
if (proxy != NULL && proxy->var()->IsUnallocated()) {
Comment cmnt(masm_, "Global variable");
- __ mov(eax, proxy->var()->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ __ mov(edx, GlobalObjectOperand());
__ mov(ecx, Immediate(proxy->name()));
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
// Use a regular load, not a contextual load, to avoid a reference
@@ -4434,7 +4445,8 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
Scope* declaration_scope = scope()->DeclarationScope();
- if (declaration_scope->is_global_scope()) {
+ if (declaration_scope->is_global_scope() ||
+ declaration_scope->is_module_scope()) {
// Contexts nested in the global context have a canonical empty function
// as their closure, not the anonymous closure containing the global
// code. Pass a smi sentinel and let the runtime look up the empty
diff --git a/src/3rdparty/v8/src/ia32/ic-ia32.cc b/src/3rdparty/v8/src/ia32/ic-ia32.cc
index 33f247a..dc64a09 100644
--- a/src/3rdparty/v8/src/ia32/ic-ia32.cc
+++ b/src/3rdparty/v8/src/ia32/ic-ia32.cc
@@ -218,13 +218,13 @@ static void GenerateDictionaryStore(MacroAssembler* masm,
void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- eax : receiver
// -- ecx : name
+ // -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
- StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
+ StubCompiler::GenerateLoadArrayLength(masm, edx, eax, &miss);
__ bind(&miss);
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
}
@@ -233,13 +233,13 @@ void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
void LoadIC::GenerateStringLength(MacroAssembler* masm,
bool support_wrappers) {
// ----------- S t a t e -------------
- // -- eax : receiver
// -- ecx : name
+ // -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
- StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss,
+ StubCompiler::GenerateLoadStringLength(masm, edx, eax, ebx, &miss,
support_wrappers);
__ bind(&miss);
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
@@ -248,13 +248,13 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm,
void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- eax : receiver
// -- ecx : name
+ // -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
- StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
+ StubCompiler::GenerateLoadFunctionPrototype(masm, edx, eax, ebx, &miss);
__ bind(&miss);
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
}
@@ -383,7 +383,7 @@ static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm,
__ j(below, slow_case);
// Check that the key is a positive smi.
- __ test(key, Immediate(0x8000001));
+ __ test(key, Immediate(0x80000001));
__ j(not_zero, slow_case);
// Load the elements into scratch1 and check its map.
@@ -396,7 +396,7 @@ static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm,
__ mov(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset));
__ sub(scratch2, Immediate(Smi::FromInt(2)));
__ cmp(key, scratch2);
- __ j(greater_equal, unmapped_case);
+ __ j(above_equal, unmapped_case);
// Load element index and check whether it is the hole.
const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize;
@@ -443,7 +443,7 @@ static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -451,39 +451,34 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
Label probe_dictionary, check_number_dictionary;
// Check that the key is a smi.
- __ JumpIfNotSmi(eax, &check_string);
+ __ JumpIfNotSmi(ecx, &check_string);
__ bind(&index_smi);
// Now the key is known to be a smi. This place is also jumped to from
// where a numeric string is converted to a smi.
GenerateKeyedLoadReceiverCheck(
- masm, edx, ecx, Map::kHasIndexedInterceptor, &slow);
+ masm, edx, eax, Map::kHasIndexedInterceptor, &slow);
// Check the receiver's map to see if it has fast elements.
- __ CheckFastElements(ecx, &check_number_dictionary);
-
- GenerateFastArrayLoad(masm,
- edx,
- eax,
- ecx,
- eax,
- NULL,
- &slow);
+ __ CheckFastElements(eax, &check_number_dictionary);
+
+ GenerateFastArrayLoad(masm, edx, ecx, eax, eax, NULL, &slow);
Isolate* isolate = masm->isolate();
Counters* counters = isolate->counters();
__ IncrementCounter(counters->keyed_load_generic_smi(), 1);
__ ret(0);
+
__ bind(&check_number_dictionary);
- __ mov(ebx, eax);
+ __ mov(ebx, ecx);
__ SmiUntag(ebx);
- __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
// Check whether the elements is a number dictionary.
// edx: receiver
// ebx: untagged index
- // eax: key
- // ecx: elements
- __ CheckMap(ecx,
+ // ecx: key
+ // eax: elements
+ __ CheckMap(eax,
isolate->factory()->hash_table_map(),
&slow,
DONT_DO_SMI_CHECK);
@@ -491,13 +486,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// Push receiver on the stack to free up a register for the dictionary
// probing.
__ push(edx);
- __ LoadFromNumberDictionary(&slow_pop_receiver,
- ecx,
- eax,
- ebx,
- edx,
- edi,
- eax);
+ __ LoadFromNumberDictionary(&slow_pop_receiver, eax, ecx, ebx, edx, edi, eax);
// Pop receiver before returning.
__ pop(edx);
__ ret(0);
@@ -509,15 +498,15 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ bind(&slow);
// Slow case: jump to runtime.
// edx: receiver
- // eax: key
+ // ecx: key
__ IncrementCounter(counters->keyed_load_generic_slow(), 1);
GenerateRuntimeGetProperty(masm);
__ bind(&check_string);
- GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow);
+ GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow);
GenerateKeyedLoadReceiverCheck(
- masm, edx, ecx, Map::kHasNamedInterceptor, &slow);
+ masm, edx, eax, Map::kHasNamedInterceptor, &slow);
// If the receiver is a fast-case object, check the keyed lookup
// cache. Otherwise probe the dictionary.
@@ -526,15 +515,18 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
Immediate(isolate->factory()->hash_table_map()));
__ j(equal, &probe_dictionary);
- // Load the map of the receiver, compute the keyed lookup cache hash
+ // The receiver's map is still in eax, compute the keyed lookup cache hash
// based on 32 bits of the map pointer and the string hash.
- __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
- __ mov(ecx, ebx);
- __ shr(ecx, KeyedLookupCache::kMapHashShift);
- __ mov(edi, FieldOperand(eax, String::kHashFieldOffset));
+ if (FLAG_debug_code) {
+ __ cmp(eax, FieldOperand(edx, HeapObject::kMapOffset));
+ __ Check(equal, "Map is no longer in eax.");
+ }
+ __ mov(ebx, eax); // Keep the map around for later.
+ __ shr(eax, KeyedLookupCache::kMapHashShift);
+ __ mov(edi, FieldOperand(ecx, String::kHashFieldOffset));
__ shr(edi, String::kHashShift);
- __ xor_(ecx, edi);
- __ and_(ecx, KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
+ __ xor_(eax, edi);
+ __ and_(eax, KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
// Load the key (consisting of map and symbol) from the cache and
// check for match.
@@ -546,7 +538,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
for (int i = 0; i < kEntriesPerBucket - 1; i++) {
Label try_next_entry;
- __ mov(edi, ecx);
+ __ mov(edi, eax);
__ shl(edi, kPointerSizeLog2 + 1);
if (i != 0) {
__ add(edi, Immediate(kPointerSize * i * 2));
@@ -554,25 +546,25 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
__ j(not_equal, &try_next_entry);
__ add(edi, Immediate(kPointerSize));
- __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys));
+ __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys));
__ j(equal, &hit_on_nth_entry[i]);
__ bind(&try_next_entry);
}
- __ lea(edi, Operand(ecx, 1));
+ __ lea(edi, Operand(eax, 1));
__ shl(edi, kPointerSizeLog2 + 1);
__ add(edi, Immediate(kPointerSize * (kEntriesPerBucket - 1) * 2));
__ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
__ j(not_equal, &slow);
__ add(edi, Immediate(kPointerSize));
- __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys));
+ __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys));
__ j(not_equal, &slow);
// Get field offset.
// edx : receiver
// ebx : receiver's map
- // eax : key
- // ecx : lookup cache index
+ // ecx : key
+ // eax : lookup cache index
ExternalReference cache_field_offsets =
ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
@@ -580,12 +572,12 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
__ bind(&hit_on_nth_entry[i]);
if (i != 0) {
- __ add(ecx, Immediate(i));
+ __ add(eax, Immediate(i));
}
__ mov(edi,
- Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets));
- __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
- __ sub(edi, ecx);
+ Operand::StaticArray(eax, times_pointer_size, cache_field_offsets));
+ __ movzx_b(eax, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
+ __ sub(edi, eax);
__ j(above_equal, &property_array_property);
if (i != 0) {
__ jmp(&load_in_object_property);
@@ -594,9 +586,9 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// Load in-object property.
__ bind(&load_in_object_property);
- __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
- __ add(ecx, edi);
- __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0));
+ __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceSizeOffset));
+ __ add(eax, edi);
+ __ mov(eax, FieldOperand(edx, eax, times_pointer_size, 0));
__ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
__ ret(0);
@@ -612,16 +604,16 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// exists.
__ bind(&probe_dictionary);
- __ mov(ecx, FieldOperand(edx, JSObject::kMapOffset));
- __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
- GenerateGlobalInstanceTypeCheck(masm, ecx, &slow);
+ __ mov(eax, FieldOperand(edx, JSObject::kMapOffset));
+ __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
+ GenerateGlobalInstanceTypeCheck(masm, eax, &slow);
- GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax);
+ GenerateDictionaryLoad(masm, &slow, ebx, ecx, eax, edi, eax);
__ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
__ ret(0);
__ bind(&index_string);
- __ IndexFromHash(ebx, eax);
+ __ IndexFromHash(ebx, ecx);
// Now jump to the place where smi keys are handled.
__ jmp(&index_smi);
}
@@ -629,15 +621,15 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- eax : key (index)
+ // -- ecx : key (index)
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
Register receiver = edx;
- Register index = eax;
- Register scratch = ecx;
+ Register index = ecx;
+ Register scratch = ebx;
Register result = eax;
StringCharAtGenerator char_at_generator(receiver,
@@ -661,7 +653,7 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -671,24 +663,24 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
__ JumpIfSmi(edx, &slow);
// Check that the key is an array index, that is Uint32.
- __ test(eax, Immediate(kSmiTagMask | kSmiSignMask));
+ __ test(ecx, Immediate(kSmiTagMask | kSmiSignMask));
__ j(not_zero, &slow);
// Get the map of the receiver.
- __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+ __ mov(eax, FieldOperand(edx, HeapObject::kMapOffset));
// Check that it has indexed interceptor and access checks
// are not enabled for this object.
- __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
- __ and_(ecx, Immediate(kSlowCaseBitFieldMask));
- __ cmp(ecx, Immediate(1 << Map::kHasIndexedInterceptor));
+ __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset));
+ __ and_(eax, Immediate(kSlowCaseBitFieldMask));
+ __ cmp(eax, Immediate(1 << Map::kHasIndexedInterceptor));
__ j(not_zero, &slow);
// Everything is fine, call runtime.
- __ pop(ecx);
+ __ pop(eax);
__ push(edx); // receiver
- __ push(eax); // key
- __ push(ecx); // return address
+ __ push(ecx); // key
+ __ push(eax); // return address
// Perform tail call to the entry.
ExternalReference ref =
@@ -703,20 +695,20 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label slow, notin;
Factory* factory = masm->isolate()->factory();
Operand mapped_location =
- GenerateMappedArgumentsLookup(masm, edx, eax, ebx, ecx, &notin, &slow);
+ GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, &notin, &slow);
__ mov(eax, mapped_location);
__ Ret();
__ bind(&notin);
// The unmapped lookup expects that the parameter map is in ebx.
Operand unmapped_location =
- GenerateUnmappedArgumentsLookup(masm, eax, ebx, ecx, &slow);
+ GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow);
__ cmp(unmapped_location, factory->the_hole_value());
__ j(equal, &slow);
__ mov(eax, unmapped_location);
@@ -1308,15 +1300,15 @@ void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- eax : receiver
// -- ecx : name
+ // -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
// Probe the stub cache.
Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
- Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, eax, ecx, ebx,
- edx);
+ Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
+ eax);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
@@ -1325,17 +1317,17 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
void LoadIC::GenerateNormal(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- eax : receiver
// -- ecx : name
+ // -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
- GenerateStringDictionaryReceiverCheck(masm, eax, edx, ebx, &miss);
+ GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
- // edx: elements
+ // eax: elements
// Search the dictionary placing the result in eax.
- GenerateDictionaryLoad(masm, &miss, edx, ecx, edi, ebx, eax);
+ GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, eax);
__ ret(0);
// Cache miss: Jump to runtime.
@@ -1346,15 +1338,15 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
void LoadIC::GenerateMiss(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- eax : receiver
// -- ecx : name
+ // -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
__ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
__ pop(ebx);
- __ push(eax); // receiver
+ __ push(edx); // receiver
__ push(ecx); // name
__ push(ebx); // return address
@@ -1367,7 +1359,7 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -1376,7 +1368,7 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
__ pop(ebx);
__ push(edx); // receiver
- __ push(eax); // name
+ __ push(ecx); // name
__ push(ebx); // return address
// Perform tail call to the entry.
@@ -1390,14 +1382,14 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
__ pop(ebx);
__ push(edx); // receiver
- __ push(eax); // name
+ __ push(ecx); // name
__ push(ebx); // return address
// Perform tail call to the entry.
@@ -1735,12 +1727,12 @@ void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
// Activate inlined smi code.
if (previous_state == UNINITIALIZED) {
- PatchInlinedSmiCode(address());
+ PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
}
}
-void PatchInlinedSmiCode(Address address) {
+void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
// The address of the instruction following the call.
Address test_instruction_address =
address + Assembler::kCallTargetAddressOffset;
@@ -1761,14 +1753,18 @@ void PatchInlinedSmiCode(Address address) {
address, test_instruction_address, delta);
}
- // Patch with a short conditional jump. There must be a
- // short jump-if-carry/not-carry at this position.
+ // Patch with a short conditional jump. Enabling means switching from a short
+ // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the
+ // reverse operation of that.
Address jmp_address = test_instruction_address - delta;
- ASSERT(*jmp_address == Assembler::kJncShortOpcode ||
- *jmp_address == Assembler::kJcShortOpcode);
- Condition cc = *jmp_address == Assembler::kJncShortOpcode
- ? not_zero
- : zero;
+ ASSERT((check == ENABLE_INLINED_SMI_CHECK)
+ ? (*jmp_address == Assembler::kJncShortOpcode ||
+ *jmp_address == Assembler::kJcShortOpcode)
+ : (*jmp_address == Assembler::kJnzShortOpcode ||
+ *jmp_address == Assembler::kJzShortOpcode));
+ Condition cc = (check == ENABLE_INLINED_SMI_CHECK)
+ ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero)
+ : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry);
*jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
}
diff --git a/src/3rdparty/v8/src/ia32/lithium-codegen-ia32.cc b/src/3rdparty/v8/src/ia32/lithium-codegen-ia32.cc
index 2b68539..fa58146 100644
--- a/src/3rdparty/v8/src/ia32/lithium-codegen-ia32.cc
+++ b/src/3rdparty/v8/src/ia32/lithium-codegen-ia32.cc
@@ -186,13 +186,12 @@ bool LCodeGen::GeneratePrologue() {
// Possibly allocate a local context.
int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
- if (heap_slots > 0 ||
- (scope()->is_qml_mode() && scope()->is_global_scope())) {
+ if (heap_slots > 0) {
Comment(";;; Allocate local context");
// Argument to NewContext is the function, which is still in edi.
__ push(edi);
if (heap_slots <= FastNewContextStub::kMaximumSlots) {
- FastNewContextStub stub((heap_slots < 0)?0:heap_slots);
+ FastNewContextStub stub(heap_slots);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kNewFunctionContext, 1);
@@ -2060,8 +2059,9 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
RelocInfo::CODE_TARGET,
instr,
RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
- ASSERT(instr->HasDeoptimizationEnvironment());
- LEnvironment* env = instr->deoptimization_environment();
+ // Get the deoptimization index of the LLazyBailout-environment that
+ // corresponds to this instruction.
+ LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
// Put the result value into the eax slot and restore all registers.
@@ -2115,7 +2115,7 @@ void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
- ASSERT(ToRegister(instr->global_object()).is(eax));
+ ASSERT(ToRegister(instr->global_object()).is(edx));
ASSERT(ToRegister(instr->result()).is(eax));
__ mov(ecx, instr->name());
@@ -2274,46 +2274,41 @@ void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
Register result = ToRegister(instr->result());
int map_count = instr->hydrogen()->types()->length();
+ bool need_generic = instr->hydrogen()->need_generic();
+
+ if (map_count == 0 && !need_generic) {
+ DeoptimizeIf(no_condition, instr->environment());
+ return;
+ }
Handle<String> name = instr->hydrogen()->name();
- if (map_count == 0) {
- ASSERT(instr->hydrogen()->need_generic());
- __ mov(ecx, name);
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- CallCode(ic, RelocInfo::CODE_TARGET, instr);
- } else {
- Label done;
- for (int i = 0; i < map_count - 1; ++i) {
- Handle<Map> map = instr->hydrogen()->types()->at(i);
+ Label done;
+ for (int i = 0; i < map_count; ++i) {
+ bool last = (i == map_count - 1);
+ Handle<Map> map = instr->hydrogen()->types()->at(i);
+ __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
+ if (last && !need_generic) {
+ DeoptimizeIf(not_equal, instr->environment());
+ EmitLoadFieldOrConstantFunction(result, object, map, name);
+ } else {
Label next;
- __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
__ j(not_equal, &next, Label::kNear);
EmitLoadFieldOrConstantFunction(result, object, map, name);
__ jmp(&done, Label::kNear);
__ bind(&next);
}
- Handle<Map> map = instr->hydrogen()->types()->last();
- __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
- if (instr->hydrogen()->need_generic()) {
- Label generic;
- __ j(not_equal, &generic, Label::kNear);
- EmitLoadFieldOrConstantFunction(result, object, map, name);
- __ jmp(&done, Label::kNear);
- __ bind(&generic);
- __ mov(ecx, name);
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- CallCode(ic, RelocInfo::CODE_TARGET, instr);
- } else {
- DeoptimizeIf(not_equal, instr->environment());
- EmitLoadFieldOrConstantFunction(result, object, map, name);
- }
- __ bind(&done);
}
+ if (need_generic) {
+ __ mov(ecx, name);
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ }
+ __ bind(&done);
}
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
- ASSERT(ToRegister(instr->object()).is(eax));
+ ASSERT(ToRegister(instr->object()).is(edx));
ASSERT(ToRegister(instr->result()).is(eax));
__ mov(ecx, instr->name());
@@ -2426,9 +2421,11 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
// Load the result.
__ mov(result,
- BuildFastArrayOperand(instr->elements(), instr->key(),
+ BuildFastArrayOperand(instr->elements(),
+ instr->key(),
FAST_ELEMENTS,
- FixedArray::kHeaderSize - kHeapObjectTag));
+ FixedArray::kHeaderSize - kHeapObjectTag,
+ instr->additional_index()));
// Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) {
@@ -2447,13 +2444,17 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
Operand hole_check_operand = BuildFastArrayOperand(
instr->elements(), instr->key(),
FAST_DOUBLE_ELEMENTS,
- offset);
+ offset,
+ instr->additional_index());
__ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
DeoptimizeIf(equal, instr->environment());
Operand double_load_operand = BuildFastArrayOperand(
- instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
- FixedDoubleArray::kHeaderSize - kHeapObjectTag);
+ instr->elements(),
+ instr->key(),
+ FAST_DOUBLE_ELEMENTS,
+ FixedDoubleArray::kHeaderSize - kHeapObjectTag,
+ instr->additional_index());
__ movdbl(result, double_load_operand);
}
@@ -2462,7 +2463,8 @@ Operand LCodeGen::BuildFastArrayOperand(
LOperand* elements_pointer,
LOperand* key,
ElementsKind elements_kind,
- uint32_t offset) {
+ uint32_t offset,
+ uint32_t additional_index) {
Register elements_pointer_reg = ToRegister(elements_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind);
if (key->IsConstantOperand()) {
@@ -2471,10 +2473,14 @@ Operand LCodeGen::BuildFastArrayOperand(
Abort("array index constant value too big");
}
return Operand(elements_pointer_reg,
- constant_value * (1 << shift_size) + offset);
+ ((constant_value + additional_index) << shift_size)
+ + offset);
} else {
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
- return Operand(elements_pointer_reg, ToRegister(key), scale_factor, offset);
+ return Operand(elements_pointer_reg,
+ ToRegister(key),
+ scale_factor,
+ offset + (additional_index << shift_size));
}
}
@@ -2483,7 +2489,10 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
- instr->key(), elements_kind, 0));
+ instr->key(),
+ elements_kind,
+ 0,
+ instr->additional_index()));
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand);
@@ -2534,7 +2543,7 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->object()).is(edx));
- ASSERT(ToRegister(instr->key()).is(eax));
+ ASSERT(ToRegister(instr->key()).is(ecx));
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
@@ -2544,25 +2553,29 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
Register result = ToRegister(instr->result());
- // Check for arguments adapter frame.
- Label done, adapted;
- __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
- __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
- __ cmp(Operand(result),
- Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
- __ j(equal, &adapted, Label::kNear);
-
- // No arguments adaptor frame.
- __ mov(result, Operand(ebp));
- __ jmp(&done, Label::kNear);
+ if (instr->hydrogen()->from_inlined()) {
+ __ lea(result, Operand(esp, -2 * kPointerSize));
+ } else {
+ // Check for arguments adapter frame.
+ Label done, adapted;
+ __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
+ __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
+ __ cmp(Operand(result),
+ Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
+ __ j(equal, &adapted, Label::kNear);
+
+ // No arguments adaptor frame.
+ __ mov(result, Operand(ebp));
+ __ jmp(&done, Label::kNear);
- // Arguments adaptor frame present.
- __ bind(&adapted);
- __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
+ // Arguments adaptor frame present.
+ __ bind(&adapted);
+ __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
- // Result is the frame pointer for the frame if not adapted and for the real
- // frame below the adaptor frame if adapted.
- __ bind(&done);
+ // Result is the frame pointer for the frame if not adapted and for the real
+ // frame below the adaptor frame if adapted.
+ __ bind(&done);
+ }
}
@@ -2667,7 +2680,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
// Invoke the function.
__ bind(&invoke);
- ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ ASSERT(instr->HasPointerMap());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator safepoint_generator(
@@ -2684,6 +2697,11 @@ void LCodeGen::DoPushArgument(LPushArgument* instr) {
}
+void LCodeGen::DoDrop(LDrop* instr) {
+ __ Drop(instr->count());
+}
+
+
void LCodeGen::DoThisFunction(LThisFunction* instr) {
Register result = ToRegister(instr->result());
__ LoadHeapObject(result, instr->hydrogen()->closure());
@@ -2716,7 +2734,7 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
Register context = ToRegister(instr->context());
Register result = ToRegister(instr->result());
- __ mov(result, Operand(context, Context::SlotOffset(instr->qml_global()?Context::QML_GLOBAL_INDEX:Context::GLOBAL_INDEX)));
+ __ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX)));
}
@@ -2730,7 +2748,8 @@ void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
- CallKind call_kind) {
+ CallKind call_kind,
+ EDIState edi_state) {
bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
function->shared()->formal_parameter_count() == arity;
@@ -2738,7 +2757,9 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
RecordPosition(pointers->position());
if (can_invoke_directly) {
- __ LoadHeapObject(edi, function);
+ if (edi_state == EDI_UNINITIALIZED) {
+ __ LoadHeapObject(edi, function);
+ }
// Change context if needed.
bool change_context =
@@ -2781,7 +2802,8 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
CallKnownFunction(instr->function(),
instr->arity(),
instr,
- CALL_AS_METHOD);
+ CALL_AS_METHOD,
+ EDI_UNINITIALIZED);
}
@@ -2912,11 +2934,13 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
__ cmp(output_reg, 0x80000000u);
DeoptimizeIf(equal, instr->environment());
} else {
+ Label negative_sign;
Label done;
- // Deoptimize on negative numbers.
+ // Deoptimize on unordered.
__ xorps(xmm_scratch, xmm_scratch); // Zero the register.
__ ucomisd(input_reg, xmm_scratch);
- DeoptimizeIf(below, instr->environment());
+ DeoptimizeIf(parity_even, instr->environment());
+ __ j(below, &negative_sign, Label::kNear);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Check for negative zero.
@@ -2932,10 +2956,21 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
// Use truncating instruction (OK because input is positive).
__ cvttsd2si(output_reg, Operand(input_reg));
-
// Overflow is signalled with minint.
__ cmp(output_reg, 0x80000000u);
DeoptimizeIf(equal, instr->environment());
+ __ jmp(&done, Label::kNear);
+
+ // Non-zero negative reaches here
+ __ bind(&negative_sign);
+ // Truncate, then compare and compensate
+ __ cvttsd2si(output_reg, Operand(input_reg));
+ __ cvtsi2sd(xmm_scratch, output_reg);
+ __ ucomisd(input_reg, xmm_scratch);
+ __ j(equal, &done, Label::kNear);
+ __ sub(output_reg, Immediate(1));
+ DeoptimizeIf(overflow, instr->environment());
+
__ bind(&done);
}
}
@@ -3227,13 +3262,21 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->function()).is(edi));
ASSERT(instr->HasPointerMap());
- ASSERT(instr->HasDeoptimizationEnvironment());
- LPointerMap* pointers = instr->pointer_map();
- RecordPosition(pointers->position());
- SafepointGenerator generator(
- this, pointers, Safepoint::kLazyDeopt);
- ParameterCount count(instr->arity());
- __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
+
+ if (instr->known_function().is_null()) {
+ LPointerMap* pointers = instr->pointer_map();
+ RecordPosition(pointers->position());
+ SafepointGenerator generator(
+ this, pointers, Safepoint::kLazyDeopt);
+ ParameterCount count(instr->arity());
+ __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
+ } else {
+ CallKnownFunction(instr->known_function(),
+ instr->arity(),
+ instr,
+ CALL_AS_METHOD,
+ EDI_CONTAINS_TARGET);
+ }
}
@@ -3288,7 +3331,11 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(eax));
- CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
+ CallKnownFunction(instr->target(),
+ instr->arity(),
+ instr,
+ CALL_AS_FUNCTION,
+ EDI_UNINITIALIZED);
}
@@ -3382,7 +3429,10 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
- instr->key(), elements_kind, 0));
+ instr->key(),
+ elements_kind,
+ 0,
+ instr->additional_index()));
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
__ movss(operand, xmm0);
@@ -3423,31 +3473,21 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
Register elements = ToRegister(instr->object());
Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
- // Do the store.
- if (instr->key()->IsConstantOperand()) {
- ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
- LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
- int offset =
- ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
- __ mov(FieldOperand(elements, offset), value);
- } else {
- __ mov(FieldOperand(elements,
- key,
- times_pointer_size,
- FixedArray::kHeaderSize),
- value);
- }
+ Operand operand = BuildFastArrayOperand(
+ instr->object(),
+ instr->key(),
+ FAST_ELEMENTS,
+ FixedArray::kHeaderSize - kHeapObjectTag,
+ instr->additional_index());
+ __ mov(operand, value);
if (instr->hydrogen()->NeedsWriteBarrier()) {
+ ASSERT(!instr->key()->IsConstantOperand());
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register.
- __ lea(key,
- FieldOperand(elements,
- key,
- times_pointer_size,
- FixedArray::kHeaderSize));
+ __ lea(key, operand);
__ RecordWrite(elements,
key,
value,
@@ -3461,19 +3501,25 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
void LCodeGen::DoStoreKeyedFastDoubleElement(
LStoreKeyedFastDoubleElement* instr) {
XMMRegister value = ToDoubleRegister(instr->value());
- Label have_value;
- __ ucomisd(value, value);
- __ j(parity_odd, &have_value); // NaN.
+ if (instr->NeedsCanonicalization()) {
+ Label have_value;
- ExternalReference canonical_nan_reference =
- ExternalReference::address_of_canonical_non_hole_nan();
- __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
- __ bind(&have_value);
+ __ ucomisd(value, value);
+ __ j(parity_odd, &have_value); // NaN.
+
+ ExternalReference canonical_nan_reference =
+ ExternalReference::address_of_canonical_non_hole_nan();
+ __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
+ __ bind(&have_value);
+ }
Operand double_store_operand = BuildFastArrayOperand(
- instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
- FixedDoubleArray::kHeaderSize - kHeapObjectTag);
+ instr->elements(),
+ instr->key(),
+ FAST_DOUBLE_ELEMENTS,
+ FixedDoubleArray::kHeaderSize - kHeapObjectTag,
+ instr->additional_index());
__ movdbl(double_store_operand, value);
}
@@ -4434,6 +4480,13 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
__ LoadHeapObject(ecx, object);
__ cmp(source, ecx);
__ Assert(equal, "Unexpected object literal boilerplate");
+ __ mov(ecx, FieldOperand(source, HeapObject::kMapOffset));
+ __ cmp(ecx, Handle<Map>(object->map()));
+ __ Assert(equal, "Unexpected boilerplate map");
+ __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
+ __ and_(ecx, Map::kElementsKindMask);
+ __ cmp(ecx, object->GetElementsKind() << Map::kElementsKindShift);
+ __ Assert(equal, "Unexpected boilerplate elements kind");
}
// Only elements backing stores for non-COW arrays need to be copied.
@@ -4503,9 +4556,10 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
__ mov(FieldOperand(result, total_offset + 4), Immediate(value_high));
}
} else if (elements->IsFixedArray()) {
+ Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
for (int i = 0; i < elements_length; i++) {
int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
- Handle<Object> value = JSObject::GetElement(object, i);
+ Handle<Object> value(fast_elements->get(i));
if (value->IsJSObject()) {
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
__ lea(ecx, Operand(result, *offset));
@@ -4529,6 +4583,23 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
int size = instr->hydrogen()->total_size();
+ ElementsKind boilerplate_elements_kind =
+ instr->hydrogen()->boilerplate()->GetElementsKind();
+
+ // Deopt if the literal boilerplate ElementsKind is of a type different than
+ // the expected one. The check isn't necessary if the boilerplate has already
+ // been converted to FAST_ELEMENTS.
+ if (boilerplate_elements_kind != FAST_ELEMENTS) {
+ __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
+ __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
+ // Load the map's "bit field 2". We only need the first byte,
+ // but the following masking takes care of that anyway.
+ __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
+ // Retrieve elements_kind from bit field 2.
+ __ and_(ecx, Map::kElementsKindMask);
+ __ cmp(ecx, boilerplate_elements_kind << Map::kElementsKindShift);
+ DeoptimizeIf(not_equal, instr->environment());
+ }
// Allocate all objects that are part of the literal in one big
// allocation. This avoids multiple limit checks.
@@ -4813,7 +4884,7 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
LOperand* key = instr->key();
__ push(ToOperand(obj));
EmitPushTaggedOperand(key);
- ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ ASSERT(instr->HasPointerMap());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
// Create safepoint generator that will also ensure enough space in the
@@ -4911,7 +4982,7 @@ void LCodeGen::DoIn(LIn* instr) {
LOperand* key = instr->key();
EmitPushTaggedOperand(key);
EmitPushTaggedOperand(obj);
- ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ ASSERT(instr->HasPointerMap());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator safepoint_generator(
diff --git a/src/3rdparty/v8/src/ia32/lithium-codegen-ia32.h b/src/3rdparty/v8/src/ia32/lithium-codegen-ia32.h
index 52befc6..392bca2 100644
--- a/src/3rdparty/v8/src/ia32/lithium-codegen-ia32.h
+++ b/src/3rdparty/v8/src/ia32/lithium-codegen-ia32.h
@@ -206,12 +206,18 @@ class LCodeGen BASE_EMBEDDED {
LInstruction* instr,
LOperand* context);
+ enum EDIState {
+ EDI_UNINITIALIZED,
+ EDI_CONTAINS_TARGET
+ };
+
// Generate a direct call to a known function. Expects the function
// to be in edi.
void CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
- CallKind call_kind);
+ CallKind call_kind,
+ EDIState edi_state);
void RecordSafepointWithLazyDeopt(LInstruction* instr,
SafepointMode safepoint_mode);
@@ -236,7 +242,8 @@ class LCodeGen BASE_EMBEDDED {
Operand BuildFastArrayOperand(LOperand* elements_pointer,
LOperand* key,
ElementsKind elements_kind,
- uint32_t offset);
+ uint32_t offset,
+ uint32_t additional_index = 0);
// Specific math operations - used from DoUnaryMathOperation.
void EmitIntegerMathAbs(LUnaryMathOperation* instr);
diff --git a/src/3rdparty/v8/src/ia32/lithium-ia32.cc b/src/3rdparty/v8/src/ia32/lithium-ia32.cc
index fe48521..d0cb230 100644
--- a/src/3rdparty/v8/src/ia32/lithium-ia32.cc
+++ b/src/3rdparty/v8/src/ia32/lithium-ia32.cc
@@ -729,22 +729,6 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
}
-LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
- LInstruction* instr, int ast_id) {
- ASSERT(instruction_pending_deoptimization_environment_ == NULL);
- ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
- instruction_pending_deoptimization_environment_ = instr;
- pending_deoptimization_ast_id_ = ast_id;
- return instr;
-}
-
-
-void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
- instruction_pending_deoptimization_environment_ = NULL;
- pending_deoptimization_ast_id_ = AstNode::kNoNumber;
-}
-
-
LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
HInstruction* hinstr,
CanDeoptimize can_deoptimize) {
@@ -757,8 +741,10 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
if (hinstr->HasObservableSideEffects()) {
ASSERT(hinstr->next()->IsSimulate());
HSimulate* sim = HSimulate::cast(hinstr->next());
- instr = SetInstructionPendingDeoptimizationEnvironment(
- instr, sim->ast_id());
+ ASSERT(instruction_pending_deoptimization_environment_ == NULL);
+ ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
+ instruction_pending_deoptimization_environment_ = instr;
+ pending_deoptimization_ast_id_ = sim->ast_id();
}
// If instruction does not have side-effects lazy deoptimization
@@ -776,12 +762,6 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
}
-LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
- instr->MarkAsSaveDoubles();
- return instr;
-}
-
-
LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
ASSERT(!instr->HasPointerMap());
instr->set_pointer_map(new(zone()) LPointerMap(position_));
@@ -1163,7 +1143,7 @@ LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
LOperand* context = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new(zone()) LGlobalObject(context, instr->qml_global()));
+ return DefineAsRegister(new(zone()) LGlobalObject(context));
}
@@ -1253,7 +1233,7 @@ LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
LOperand* context = UseFixed(instr->context(), esi);
argument_count_ -= instr->argument_count();
- LCallGlobal* result = new(zone()) LCallGlobal(context, instr->qml_global());
+ LCallGlobal* result = new(zone()) LCallGlobal(context);
return MarkAsCall(DefineFixed(result, eax), instr);
}
@@ -1330,6 +1310,7 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
ASSERT(instr->value()->representation().IsInteger32());
ASSERT(instr->representation().IsInteger32());
+ if (instr->HasNoUses()) return NULL;
LOperand* input = UseRegisterAtStart(instr->value());
LBitNotI* result = new(zone()) LBitNotI(input);
return DefineSameAsFirst(result);
@@ -1354,6 +1335,12 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
}
+LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
if (instr->representation().IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
@@ -1862,7 +1849,7 @@ LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
LOperand* context = UseFixed(instr->context(), esi);
- LOperand* global_object = UseFixed(instr->global_object(), eax);
+ LOperand* global_object = UseFixed(instr->global_object(), edx);
LLoadGlobalGeneric* result =
new(zone()) LLoadGlobalGeneric(context, global_object);
return MarkAsCall(DefineFixed(result, eax), instr);
@@ -1922,7 +1909,7 @@ LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic(
ASSERT(instr->representation().IsTagged());
if (instr->need_generic()) {
LOperand* context = UseFixed(instr->context(), esi);
- LOperand* obj = UseFixed(instr->object(), eax);
+ LOperand* obj = UseFixed(instr->object(), edx);
LLoadNamedFieldPolymorphic* result =
new(zone()) LLoadNamedFieldPolymorphic(context, obj);
return MarkAsCall(DefineFixed(result, eax), instr);
@@ -1938,7 +1925,7 @@ LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic(
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), esi);
- LOperand* object = UseFixed(instr->object(), eax);
+ LOperand* object = UseFixed(instr->object(), edx);
LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(context, object);
return MarkAsCall(DefineFixed(result, eax), instr);
}
@@ -2003,8 +1990,7 @@ LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegisterOrConstant(instr->key());
LLoadKeyedSpecializedArrayElement* result =
- new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer,
- key);
+ new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer, key);
LInstruction* load_instr = DefineAsRegister(result);
// An unsigned int array load might overflow and cause a deopt, make sure it
// has an environment.
@@ -2017,7 +2003,7 @@ LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* object = UseFixed(instr->object(), edx);
- LOperand* key = UseFixed(instr->key(), eax);
+ LOperand* key = UseFixed(instr->key(), ecx);
LLoadKeyedGeneric* result =
new(zone()) LLoadKeyedGeneric(context, object, key);
@@ -2348,9 +2334,12 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
ASSERT(pending_deoptimization_ast_id_ == instr->ast_id());
LLazyBailout* lazy_bailout = new(zone()) LLazyBailout;
LInstruction* result = AssignEnvironment(lazy_bailout);
+ // Store the lazy deopt environment with the instruction if needed. Right
+ // now it is only used for LInstanceOfKnownGlobal.
instruction_pending_deoptimization_environment_->
- set_deoptimization_environment(result->environment());
- ClearInstructionPendingDeoptimizationEnvironment();
+ SetDeferredLazyDeoptimizationEnvironment(result->environment());
+ instruction_pending_deoptimization_environment_ = NULL;
+ pending_deoptimization_ast_id_ = AstNode::kNoNumber;
return result;
}
@@ -2380,8 +2369,8 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
undefined,
instr->call_kind(),
instr->is_construct());
- if (instr->arguments() != NULL) {
- inner->Bind(instr->arguments(), graph()->GetArgumentsObject());
+ if (instr->arguments_var() != NULL) {
+ inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
}
current_block_->UpdateEnvironment(inner);
chunk_->AddInlinedClosure(instr->closure());
@@ -2390,10 +2379,20 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
+ LInstruction* pop = NULL;
+
+ HEnvironment* env = current_block_->last_environment();
+
+ if (instr->arguments_pushed()) {
+ int argument_count = env->arguments_environment()->parameter_count();
+ pop = new(zone()) LDrop(argument_count);
+ argument_count_ -= argument_count;
+ }
+
HEnvironment* outer = current_block_->last_environment()->
DiscardInlined(false);
current_block_->UpdateEnvironment(outer);
- return NULL;
+ return pop;
}
diff --git a/src/3rdparty/v8/src/ia32/lithium-ia32.h b/src/3rdparty/v8/src/ia32/lithium-ia32.h
index 0db0a4b..be64b2f 100644
--- a/src/3rdparty/v8/src/ia32/lithium-ia32.h
+++ b/src/3rdparty/v8/src/ia32/lithium-ia32.h
@@ -174,7 +174,8 @@ class LCodeGen;
V(CheckMapValue) \
V(LoadFieldByIndex) \
V(DateField) \
- V(WrapReceiver)
+ V(WrapReceiver) \
+ V(Drop)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
@@ -198,8 +199,7 @@ class LInstruction: public ZoneObject {
LInstruction()
: environment_(NULL),
hydrogen_value_(NULL),
- is_call_(false),
- is_save_doubles_(false) { }
+ is_call_(false) { }
virtual ~LInstruction() { }
virtual void CompileToNative(LCodeGen* generator) = 0;
@@ -242,22 +242,12 @@ class LInstruction: public ZoneObject {
void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; }
HValue* hydrogen_value() const { return hydrogen_value_; }
- void set_deoptimization_environment(LEnvironment* env) {
- deoptimization_environment_.set(env);
- }
- LEnvironment* deoptimization_environment() const {
- return deoptimization_environment_.get();
- }
- bool HasDeoptimizationEnvironment() const {
- return deoptimization_environment_.is_set();
- }
+ virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { }
void MarkAsCall() { is_call_ = true; }
- void MarkAsSaveDoubles() { is_save_doubles_ = true; }
// Interface to the register allocator and iterators.
bool IsMarkedAsCall() const { return is_call_; }
- bool IsMarkedAsSaveDoubles() const { return is_save_doubles_; }
virtual bool HasResult() const = 0;
virtual LOperand* result() = 0;
@@ -278,9 +268,7 @@ class LInstruction: public ZoneObject {
LEnvironment* environment_;
SetOncePointer<LPointerMap> pointer_map_;
HValue* hydrogen_value_;
- SetOncePointer<LEnvironment> deoptimization_environment_;
bool is_call_;
- bool is_save_doubles_;
};
@@ -525,9 +513,8 @@ class LArgumentsLength: public LTemplateInstruction<1, 1, 0> {
class LArgumentsElements: public LTemplateInstruction<1, 0, 0> {
public:
- LArgumentsElements() { }
-
DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements")
+ DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements)
};
@@ -844,6 +831,15 @@ class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 2, 1> {
DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal)
Handle<JSFunction> function() const { return hydrogen()->function(); }
+ LEnvironment* GetDeferredLazyDeoptimizationEnvironment() {
+ return lazy_deopt_env_;
+ }
+ virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) {
+ lazy_deopt_env_ = env;
+ }
+
+ private:
+ LEnvironment* lazy_deopt_env_;
};
@@ -1242,13 +1238,13 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
public:
- LLoadKeyedFastDoubleElement(LOperand* elements,
- LOperand* key) {
+ LLoadKeyedFastDoubleElement(LOperand* elements, LOperand* key) {
inputs_[0] = elements;
inputs_[1] = key;
}
@@ -1259,13 +1255,13 @@ class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
- LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
- LOperand* key) {
+ LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) {
inputs_[0] = external_pointer;
inputs_[1] = key;
}
@@ -1279,6 +1275,7 @@ class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -1401,6 +1398,19 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> {
};
+class LDrop: public LTemplateInstruction<0, 0, 0> {
+ public:
+ explicit LDrop(int count) : count_(count) { }
+
+ int count() const { return count_; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Drop, "drop")
+
+ private:
+ int count_;
+};
+
+
class LThisFunction: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function")
@@ -1439,17 +1449,13 @@ class LDeclareGlobals: public LTemplateInstruction<0, 1, 0> {
class LGlobalObject: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LGlobalObject(LOperand* context, bool qml_global) {
+ explicit LGlobalObject(LOperand* context) {
inputs_[0] = context;
- qml_global_ = qml_global;
}
DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object")
LOperand* context() { return InputAt(0); }
- bool qml_global() { return qml_global_; }
- private:
- bool qml_global_;
};
@@ -1493,6 +1499,7 @@ class LInvokeFunction: public LTemplateInstruction<1, 2, 0> {
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
+ Handle<JSFunction> known_function() { return hydrogen()->known_function(); }
};
@@ -1550,7 +1557,7 @@ class LCallFunction: public LTemplateInstruction<1, 2, 0> {
class LCallGlobal: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LCallGlobal(LOperand* context, bool qml_global) : qml_global_(qml_global) {
+ explicit LCallGlobal(LOperand* context) {
inputs_[0] = context;
}
@@ -1562,10 +1569,6 @@ class LCallGlobal: public LTemplateInstruction<1, 1, 0> {
LOperand* context() { return inputs_[0]; }
Handle<String> name() const {return hydrogen()->name(); }
int arity() const { return hydrogen()->argument_count() - 1; }
-
- bool qml_global() { return qml_global_; }
- private:
- bool qml_global_;
};
@@ -1773,6 +1776,7 @@ class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
LOperand* object() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -1795,6 +1799,9 @@ class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
+
+ bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
};
@@ -1818,6 +1825,7 @@ class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -2479,11 +2487,6 @@ class LChunkBuilder BASE_EMBEDDED {
LInstruction* instr,
HInstruction* hinstr,
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
- LInstruction* MarkAsSaveDoubles(LInstruction* instr);
-
- LInstruction* SetInstructionPendingDeoptimizationEnvironment(
- LInstruction* instr, int ast_id);
- void ClearInstructionPendingDeoptimizationEnvironment();
LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
int* argument_index_accumulator);
diff --git a/src/3rdparty/v8/src/ia32/macro-assembler-ia32.cc b/src/3rdparty/v8/src/ia32/macro-assembler-ia32.cc
index 60e38a6..c31b0c2 100644
--- a/src/3rdparty/v8/src/ia32/macro-assembler-ia32.cc
+++ b/src/3rdparty/v8/src/ia32/macro-assembler-ia32.cc
@@ -2566,7 +2566,7 @@ bool AreAliased(Register r1, Register r2, Register r3, Register r4) {
CodePatcher::CodePatcher(byte* address, int size)
: address_(address),
size_(size),
- masm_(Isolate::Current(), address, size + Assembler::kGap) {
+ masm_(NULL, address, size + Assembler::kGap) {
// Create a new macro assembler pointing to the address of the code to patch.
// The size is adjusted with kGap on order for the assembler to generate size
// bytes of instructions without failing with buffer size constraints.
diff --git a/src/3rdparty/v8/src/ia32/macro-assembler-ia32.h b/src/3rdparty/v8/src/ia32/macro-assembler-ia32.h
index 1cc9142..66d1ce7 100644
--- a/src/3rdparty/v8/src/ia32/macro-assembler-ia32.h
+++ b/src/3rdparty/v8/src/ia32/macro-assembler-ia32.h
@@ -946,9 +946,6 @@ inline Operand GlobalObjectOperand() {
return ContextOperand(esi, Context::GLOBAL_INDEX);
}
-static inline Operand QmlGlobalObjectOperand() {
- return ContextOperand(esi, Context::QML_GLOBAL_INDEX);
-}
// Generates an Operand for saving parameters after PrepareCallApiFunction.
Operand ApiParameterOperand(int index);
diff --git a/src/3rdparty/v8/src/ia32/stub-cache-ia32.cc b/src/3rdparty/v8/src/ia32/stub-cache-ia32.cc
index fd26779..e148e2f 100644
--- a/src/3rdparty/v8/src/ia32/stub-cache-ia32.cc
+++ b/src/3rdparty/v8/src/ia32/stub-cache-ia32.cc
@@ -406,6 +406,7 @@ static void PushInterceptorArguments(MacroAssembler* masm,
__ push(receiver);
__ push(holder);
__ push(FieldOperand(scratch, InterceptorInfo::kDataOffset));
+ __ push(Immediate(reinterpret_cast<int>(masm->isolate())));
}
@@ -419,12 +420,12 @@ static void CompileCallLoadPropertyWithInterceptor(
__ CallExternalReference(
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
masm->isolate()),
- 5);
+ 6);
}
// Number of pointers to be reserved on stack for fast API call.
-static const int kFastApiCallArguments = 3;
+static const int kFastApiCallArguments = 4;
// Reserves space for the extra arguments to API function in the
@@ -472,10 +473,11 @@ static void GenerateFastApiCall(MacroAssembler* masm,
// -- esp[8] : api function
// (first fast api call extra argument)
// -- esp[12] : api call data
- // -- esp[16] : last argument
+ // -- esp[16] : isolate
+ // -- esp[20] : last argument
// -- ...
- // -- esp[(argc + 3) * 4] : first argument
- // -- esp[(argc + 4) * 4] : receiver
+ // -- esp[(argc + 4) * 4] : first argument
+ // -- esp[(argc + 5) * 4] : receiver
// -----------------------------------
// Get the function and setup the context.
Handle<JSFunction> function = optimization.constant_function();
@@ -493,9 +495,11 @@ static void GenerateFastApiCall(MacroAssembler* masm,
} else {
__ mov(Operand(esp, 3 * kPointerSize), Immediate(call_data));
}
+ __ mov(Operand(esp, 4 * kPointerSize),
+ Immediate(reinterpret_cast<int>(masm->isolate())));
// Prepare arguments.
- __ lea(eax, Operand(esp, 3 * kPointerSize));
+ __ lea(eax, Operand(esp, 4 * kPointerSize));
const int kApiArgc = 1; // API function gets reference to the v8::Arguments.
@@ -679,7 +683,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
__ CallExternalReference(
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
masm->isolate()),
- 5);
+ 6);
// Restore the name_ register.
__ pop(name_);
@@ -746,8 +750,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Register scratch,
Label* miss_label) {
// Check that the map of the object hasn't changed.
+ CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
+ : REQUIRE_EXACT_MAP;
__ CheckMap(receiver_reg, Handle<Map>(object->map()),
- miss_label, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ miss_label, DO_SMI_CHECK, mode);
// Perform global security token check if needed.
if (object->IsJSGlobalProxy()) {
@@ -1032,6 +1038,7 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
} else {
__ push(Immediate(Handle<Object>(callback->data())));
}
+ __ push(Immediate(reinterpret_cast<int>(isolate())));
// Save a pointer to where we pushed the arguments pointer.
// This will be passed as the const AccessorInfo& to the C++ callback.
@@ -1042,9 +1049,9 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
__ push(scratch3); // Restore return address.
- // 3 elements array for v8::Arguments::values_, handler for name and pointer
+ // 4 elements array for v8::Arguments::values_, handler for name and pointer
// to the values (it considered as smi in GC).
- const int kStackSpace = 5;
+ const int kStackSpace = 6;
const int kApiArgc = 2;
__ PrepareCallApiFunction(kApiArgc);
@@ -1122,13 +1129,20 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
name, miss);
ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
+ // Preserve the receiver register explicitly whenever it is different from
+ // the holder and it is needed should the interceptor return without any
+ // result. The CALLBACKS case needs the receiver to be passed into C++ code,
+ // the FIELD case might cause a miss during the prototype check.
+ bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
+ bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
+ (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
+
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
{
FrameScope frame_scope(masm(), StackFrame::INTERNAL);
- if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
- // CALLBACKS case needs a receiver to be passed into C++ callback.
+ if (must_preserve_receiver_reg) {
__ push(receiver);
}
__ push(holder_reg);
@@ -1151,10 +1165,17 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
frame_scope.GenerateLeaveFrame();
__ ret(0);
+ // Clobber registers when generating debug-code to provoke errors.
__ bind(&interceptor_failed);
+ if (FLAG_debug_code) {
+ __ mov(receiver, Immediate(BitCast<int32_t>(kZapValue)));
+ __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue)));
+ __ mov(name_reg, Immediate(BitCast<int32_t>(kZapValue)));
+ }
+
__ pop(name_reg);
__ pop(holder_reg);
- if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
+ if (must_preserve_receiver_reg) {
__ pop(receiver);
}
@@ -1163,7 +1184,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
// Check that the maps from interceptor's holder to lookup's holder
// haven't changed. And load lookup's holder into holder_reg.
- if (*interceptor_holder != lookup->holder()) {
+ if (must_perfrom_prototype_check) {
holder_reg = CheckPrototypes(interceptor_holder,
holder_reg,
Handle<JSObject>(lookup->holder()),
@@ -1197,6 +1218,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
__ push(holder_reg);
__ mov(holder_reg, Immediate(callback));
__ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
+ __ push(Immediate(reinterpret_cast<int>(isolate())));
__ push(holder_reg);
__ push(name_reg);
__ push(scratch2); // restore return address
@@ -1204,7 +1226,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
masm()->isolate());
- __ TailCallExternalReference(ref, 5, 1);
+ __ TailCallExternalReference(ref, 6, 1);
}
} else { // !compile_followup_inline
// Call the runtime system to load the interceptor.
@@ -1220,7 +1242,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
isolate());
- __ TailCallExternalReference(ref, 5, 1);
+ __ TailCallExternalReference(ref, 6, 1);
}
}
@@ -2158,7 +2180,7 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
name, depth, &miss);
// Move the return address on top of the stack.
- __ mov(eax, Operand(esp, 3 * kPointerSize));
+ __ mov(eax, Operand(esp, 4 * kPointerSize));
__ mov(Operand(esp, 0 * kPointerSize), eax);
// esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
@@ -2687,27 +2709,27 @@ Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
Handle<JSObject> object,
Handle<JSObject> last) {
// ----------- S t a t e -------------
- // -- eax : receiver
// -- ecx : name
+ // -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
// Check that the receiver isn't a smi.
- __ JumpIfSmi(eax, &miss);
+ __ JumpIfSmi(edx, &miss);
ASSERT(last->IsGlobalObject() || last->HasFastProperties());
// Check the maps of the full prototype chain. Also check that
// global property cells up to (but not including) the last object
// in the prototype chain are empty.
- CheckPrototypes(object, eax, last, ebx, edx, edi, name, &miss);
+ CheckPrototypes(object, edx, last, ebx, eax, edi, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
if (last->IsGlobalObject()) {
GenerateCheckPropertyCell(
- masm(), Handle<GlobalObject>::cast(last), name, edx, &miss);
+ masm(), Handle<GlobalObject>::cast(last), name, eax, &miss);
}
// Return undefined if maps of the full prototype chain are still the
@@ -2728,13 +2750,13 @@ Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
int index,
Handle<String> name) {
// ----------- S t a t e -------------
- // -- eax : receiver
// -- ecx : name
+ // -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
- GenerateLoadField(object, holder, eax, ebx, edx, edi, index, name, &miss);
+ GenerateLoadField(object, holder, edx, ebx, eax, edi, index, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
@@ -2749,13 +2771,13 @@ Handle<Code> LoadStubCompiler::CompileLoadCallback(
Handle<JSObject> holder,
Handle<AccessorInfo> callback) {
// ----------- S t a t e -------------
- // -- eax : receiver
// -- ecx : name
+ // -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
- GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, edi, callback,
+ GenerateLoadCallback(object, holder, edx, ecx, ebx, eax, edi, callback,
name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
@@ -2770,13 +2792,13 @@ Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
Handle<JSFunction> value,
Handle<String> name) {
// ----------- S t a t e -------------
- // -- eax : receiver
// -- ecx : name
+ // -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
- GenerateLoadConstant(object, holder, eax, ebx, edx, edi, value, name, &miss);
+ GenerateLoadConstant(object, holder, edx, ebx, eax, edi, value, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
@@ -2789,8 +2811,8 @@ Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<String> name) {
// ----------- S t a t e -------------
- // -- eax : receiver
// -- ecx : name
+ // -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
@@ -2800,7 +2822,7 @@ Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> receiver,
// TODO(368): Compile in the whole chain: all the interceptors in
// prototypes and ultimate answer.
- GenerateLoadInterceptor(receiver, holder, &lookup, eax, ecx, edx, ebx, edi,
+ GenerateLoadInterceptor(receiver, holder, &lookup, edx, ecx, eax, ebx, edi,
name, &miss);
__ bind(&miss);
@@ -2818,15 +2840,15 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
Handle<String> name,
bool is_dont_delete) {
// ----------- S t a t e -------------
- // -- eax : receiver
// -- ecx : name
+ // -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
// Check that the maps haven't changed.
- __ JumpIfSmi(eax, &miss);
- CheckPrototypes(object, eax, holder, ebx, edx, edi, name, &miss);
+ __ JumpIfSmi(edx, &miss);
+ CheckPrototypes(object, edx, holder, ebx, eax, edi, name, &miss);
// Get the value from the cell.
if (Serializer::enabled()) {
@@ -2864,7 +2886,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
Handle<JSObject> holder,
int index) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -2874,10 +2896,10 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
__ IncrementCounter(counters->keyed_load_field(), 1);
// Check that the name has not changed.
- __ cmp(eax, Immediate(name));
+ __ cmp(ecx, Immediate(name));
__ j(not_equal, &miss);
- GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss);
+ GenerateLoadField(receiver, holder, edx, ebx, eax, edi, index, name, &miss);
__ bind(&miss);
__ DecrementCounter(counters->keyed_load_field(), 1);
@@ -2894,7 +2916,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
Handle<JSObject> holder,
Handle<AccessorInfo> callback) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -2904,10 +2926,10 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
__ IncrementCounter(counters->keyed_load_callback(), 1);
// Check that the name has not changed.
- __ cmp(eax, Immediate(name));
+ __ cmp(ecx, Immediate(name));
__ j(not_equal, &miss);
- GenerateLoadCallback(receiver, holder, edx, eax, ebx, ecx, edi, callback,
+ GenerateLoadCallback(receiver, holder, edx, ecx, ebx, eax, edi, callback,
name, &miss);
__ bind(&miss);
@@ -2925,7 +2947,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
Handle<JSObject> holder,
Handle<JSFunction> value) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -2935,11 +2957,11 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
__ IncrementCounter(counters->keyed_load_constant_function(), 1);
// Check that the name has not changed.
- __ cmp(eax, Immediate(name));
+ __ cmp(ecx, Immediate(name));
__ j(not_equal, &miss);
GenerateLoadConstant(
- receiver, holder, edx, ebx, ecx, edi, value, name, &miss);
+ receiver, holder, edx, ebx, eax, edi, value, name, &miss);
__ bind(&miss);
__ DecrementCounter(counters->keyed_load_constant_function(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -2954,7 +2976,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
Handle<JSObject> holder,
Handle<String> name) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -2964,12 +2986,12 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
__ IncrementCounter(counters->keyed_load_interceptor(), 1);
// Check that the name has not changed.
- __ cmp(eax, Immediate(name));
+ __ cmp(ecx, Immediate(name));
__ j(not_equal, &miss);
LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
- GenerateLoadInterceptor(receiver, holder, &lookup, edx, eax, ecx, ebx, edi,
+ GenerateLoadInterceptor(receiver, holder, &lookup, edx, ecx, eax, ebx, edi,
name, &miss);
__ bind(&miss);
__ DecrementCounter(counters->keyed_load_interceptor(), 1);
@@ -2983,7 +3005,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
Handle<String> name) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -2993,10 +3015,10 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
__ IncrementCounter(counters->keyed_load_array_length(), 1);
// Check that the name has not changed.
- __ cmp(eax, Immediate(name));
+ __ cmp(ecx, Immediate(name));
__ j(not_equal, &miss);
- GenerateLoadArrayLength(masm(), edx, ecx, &miss);
+ GenerateLoadArrayLength(masm(), edx, eax, &miss);
__ bind(&miss);
__ DecrementCounter(counters->keyed_load_array_length(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -3009,7 +3031,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
Handle<String> name) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -3019,10 +3041,10 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
__ IncrementCounter(counters->keyed_load_string_length(), 1);
// Check that the name has not changed.
- __ cmp(eax, Immediate(name));
+ __ cmp(ecx, Immediate(name));
__ j(not_equal, &miss);
- GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true);
+ GenerateLoadStringLength(masm(), edx, eax, ebx, &miss, true);
__ bind(&miss);
__ DecrementCounter(counters->keyed_load_string_length(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -3035,7 +3057,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
Handle<String> name) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -3045,10 +3067,10 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
__ IncrementCounter(counters->keyed_load_function_prototype(), 1);
// Check that the name has not changed.
- __ cmp(eax, Immediate(name));
+ __ cmp(ecx, Immediate(name));
__ j(not_equal, &miss);
- GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss);
+ GenerateLoadFunctionPrototype(masm(), edx, eax, ebx, &miss);
__ bind(&miss);
__ DecrementCounter(counters->keyed_load_function_prototype(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -3061,7 +3083,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
Handle<Map> receiver_map) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -3082,7 +3104,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
MapHandleList* receiver_maps,
CodeHandleList* handler_ics) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -3246,7 +3268,7 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub(
void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -3254,21 +3276,15 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- __ JumpIfNotSmi(eax, &miss_force_generic);
- __ mov(ebx, eax);
+ __ JumpIfNotSmi(ecx, &miss_force_generic);
+ __ mov(ebx, ecx);
__ SmiUntag(ebx);
- __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
+ __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
// Push receiver on the stack to free up a register for the dictionary
// probing.
__ push(edx);
- __ LoadFromNumberDictionary(&slow,
- ecx,
- eax,
- ebx,
- edx,
- edi,
- eax);
+ __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax);
// Pop receiver before returning.
__ pop(edx);
__ ret(0);
@@ -3277,7 +3293,6 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
__ pop(edx);
// ----------- S t a t e -------------
- // -- eax : value
// -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
@@ -3289,7 +3304,6 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
__ bind(&miss_force_generic);
// ----------- S t a t e -------------
- // -- eax : value
// -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
@@ -3301,11 +3315,44 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
}
+static void GenerateSmiKeyCheck(MacroAssembler* masm,
+ Register key,
+ Register scratch,
+ XMMRegister xmm_scratch0,
+ XMMRegister xmm_scratch1,
+ Label* fail) {
+ // Check that key is a smi and if SSE2 is available a heap number
+ // containing a smi and branch if the check fails.
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatures::Scope use_sse2(SSE2);
+ Label key_ok;
+ __ JumpIfSmi(key, &key_ok);
+ __ cmp(FieldOperand(key, HeapObject::kMapOffset),
+ Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map())));
+ __ j(not_equal, fail);
+ __ movdbl(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset));
+ __ cvttsd2si(scratch, Operand(xmm_scratch0));
+ __ cvtsi2sd(xmm_scratch1, scratch);
+ __ ucomisd(xmm_scratch1, xmm_scratch0);
+ __ j(not_equal, fail);
+ __ j(parity_even, fail); // NaN.
+ // Check if the key fits in the smi range.
+ __ cmp(scratch, 0xc0000000);
+ __ j(sign, fail);
+ __ SmiTag(scratch);
+ __ mov(key, scratch);
+ __ bind(&key_ok);
+ } else {
+ __ JumpIfNotSmi(key, fail);
+ }
+}
+
+
void KeyedLoadStubCompiler::GenerateLoadExternalArray(
MacroAssembler* masm,
ElementsKind elements_kind) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -3314,41 +3361,41 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(eax, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic);
// Check that the index is in range.
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
- __ cmp(eax, FieldOperand(ebx, ExternalArray::kLengthOffset));
+ __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
__ j(above_equal, &miss_force_generic);
__ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
// ebx: base pointer of external storage
switch (elements_kind) {
case EXTERNAL_BYTE_ELEMENTS:
- __ SmiUntag(eax); // Untag the index.
- __ movsx_b(eax, Operand(ebx, eax, times_1, 0));
+ __ SmiUntag(ecx); // Untag the index.
+ __ movsx_b(eax, Operand(ebx, ecx, times_1, 0));
break;
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case EXTERNAL_PIXEL_ELEMENTS:
- __ SmiUntag(eax); // Untag the index.
- __ movzx_b(eax, Operand(ebx, eax, times_1, 0));
+ __ SmiUntag(ecx); // Untag the index.
+ __ movzx_b(eax, Operand(ebx, ecx, times_1, 0));
break;
case EXTERNAL_SHORT_ELEMENTS:
- __ movsx_w(eax, Operand(ebx, eax, times_1, 0));
+ __ movsx_w(eax, Operand(ebx, ecx, times_1, 0));
break;
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ movzx_w(eax, Operand(ebx, eax, times_1, 0));
+ __ movzx_w(eax, Operand(ebx, ecx, times_1, 0));
break;
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
case EXTERNAL_INT_ELEMENTS:
- __ mov(ecx, Operand(ebx, eax, times_2, 0));
+ __ mov(eax, Operand(ebx, ecx, times_2, 0));
break;
case EXTERNAL_FLOAT_ELEMENTS:
- __ fld_s(Operand(ebx, eax, times_2, 0));
+ __ fld_s(Operand(ebx, ecx, times_2, 0));
break;
case EXTERNAL_DOUBLE_ELEMENTS:
- __ fld_d(Operand(ebx, eax, times_4, 0));
+ __ fld_d(Operand(ebx, ecx, times_4, 0));
break;
default:
UNREACHABLE();
@@ -3356,7 +3403,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
}
// For integer array types:
- // ecx: value
+ // eax: value
// For floating-point array type:
// FP(0): value
@@ -3367,18 +3414,17 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// it to a HeapNumber.
Label box_int;
if (elements_kind == EXTERNAL_INT_ELEMENTS) {
- __ cmp(ecx, 0xC0000000);
+ __ cmp(eax, 0xc0000000);
__ j(sign, &box_int);
} else {
ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
// The test is different for unsigned int values. Since we need
// the value to be in the range of a positive smi, we can't
// handle either of the top two bits being set in the value.
- __ test(ecx, Immediate(0xC0000000));
+ __ test(eax, Immediate(0xc0000000));
__ j(not_zero, &box_int);
}
- __ mov(eax, ecx);
__ SmiTag(eax);
__ ret(0);
@@ -3387,33 +3433,31 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// Allocate a HeapNumber for the int and perform int-to-double
// conversion.
if (elements_kind == EXTERNAL_INT_ELEMENTS) {
- __ push(ecx);
+ __ push(eax);
__ fild_s(Operand(esp, 0));
- __ pop(ecx);
+ __ pop(eax);
} else {
ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
// Need to zero-extend the value.
// There's no fild variant for unsigned values, so zero-extend
// to a 64-bit int manually.
__ push(Immediate(0));
- __ push(ecx);
+ __ push(eax);
__ fild_d(Operand(esp, 0));
- __ pop(ecx);
- __ pop(ecx);
+ __ pop(eax);
+ __ pop(eax);
}
// FP(0): value
- __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
+ __ AllocateHeapNumber(eax, ebx, edi, &failed_allocation);
// Set the value.
- __ mov(eax, ecx);
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ ret(0);
} else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
// For the floating-point array type, we need to always allocate a
// HeapNumber.
- __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
+ __ AllocateHeapNumber(eax, ebx, edi, &failed_allocation);
// Set the value.
- __ mov(eax, ecx);
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ ret(0);
} else {
@@ -3433,7 +3477,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ IncrementCounter(counters->keyed_load_external_array_slow(), 1);
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -3442,7 +3486,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ jmp(ic, RelocInfo::CODE_TARGET);
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -3459,7 +3503,8 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
MacroAssembler* masm,
ElementsKind elements_kind) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- eax : value
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -3468,8 +3513,8 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(ecx, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
// Check that the index is in range.
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
@@ -3564,12 +3609,39 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// (code-stubs-ia32.cc) is roughly what is needed here though the
// conversion failure case does not need to be handled.
if (CpuFeatures::IsSupported(SSE2)) {
- if (elements_kind != EXTERNAL_INT_ELEMENTS &&
- elements_kind != EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+ if ((elements_kind == EXTERNAL_INT_ELEMENTS ||
+ elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) &&
+ CpuFeatures::IsSupported(SSE3)) {
+ CpuFeatures::Scope scope(SSE3);
+ // fisttp stores values as signed integers. To represent the
+ // entire range of int and unsigned int arrays, store as a
+ // 64-bit int and discard the high 32 bits.
+ __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
+ __ sub(esp, Immediate(2 * kPointerSize));
+ __ fisttp_d(Operand(esp, 0));
+
+ // If conversion failed (NaN, infinity, or a number outside
+ // signed int64 range), the result is 0x8000000000000000, and
+ // we must handle this case in the runtime.
+ Label ok;
+ __ cmp(Operand(esp, kPointerSize), Immediate(0x80000000u));
+ __ j(not_equal, &ok);
+ __ cmp(Operand(esp, 0), Immediate(0));
+ __ j(not_equal, &ok);
+ __ add(esp, Immediate(2 * kPointerSize)); // Restore the stack.
+ __ jmp(&slow);
+
+ __ bind(&ok);
+ __ pop(ebx);
+ __ add(esp, Immediate(kPointerSize));
+ __ mov(Operand(edi, ecx, times_2, 0), ebx);
+ } else {
ASSERT(CpuFeatures::IsSupported(SSE2));
CpuFeatures::Scope scope(SSE2);
__ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset));
- // ecx: untagged integer value
+ __ cmp(ebx, 0x80000000u);
+ __ j(equal, &slow);
+ // ebx: untagged integer value
switch (elements_kind) {
case EXTERNAL_PIXEL_ELEMENTS:
__ ClampUint8(ebx);
@@ -3583,41 +3655,14 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ mov_w(Operand(edi, ecx, times_1, 0), ebx);
break;
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ __ mov(Operand(edi, ecx, times_2, 0), ebx);
+ break;
default:
UNREACHABLE();
break;
}
- } else {
- if (CpuFeatures::IsSupported(SSE3)) {
- CpuFeatures::Scope scope(SSE3);
- // fisttp stores values as signed integers. To represent the
- // entire range of int and unsigned int arrays, store as a
- // 64-bit int and discard the high 32 bits.
- // If the value is NaN or +/-infinity, the result is 0x80000000,
- // which is automatically zero when taken mod 2^n, n < 32.
- __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
- __ sub(esp, Immediate(2 * kPointerSize));
- __ fisttp_d(Operand(esp, 0));
- __ pop(ebx);
- __ add(esp, Immediate(kPointerSize));
- } else {
- ASSERT(CpuFeatures::IsSupported(SSE2));
- CpuFeatures::Scope scope(SSE2);
- // We can easily implement the correct rounding behavior for the
- // range [0, 2^31-1]. For the time being, to keep this code simple,
- // make the slow runtime call for values outside this range.
- // Note: we could do better for signed int arrays.
- __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
- // We will need the key if we have to make the slow runtime call.
- __ push(ebx);
- __ LoadPowerOf2(xmm1, ebx, 31);
- __ pop(ebx);
- __ ucomisd(xmm1, xmm0);
- __ j(above_equal, &slow);
- __ cvttsd2si(ebx, Operand(xmm0));
- }
- // ebx: untagged integer value
- __ mov(Operand(edi, ecx, times_2, 0), ebx);
}
__ ret(0); // Return original value.
}
@@ -3655,7 +3700,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -3664,19 +3709,19 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(eax, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic);
// Get the elements array.
- __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
- __ AssertFastElements(ecx);
+ __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
+ __ AssertFastElements(eax);
// Check that the key is within bounds.
- __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset));
+ __ cmp(ecx, FieldOperand(eax, FixedArray::kLengthOffset));
__ j(above_equal, &miss_force_generic);
// Load the result and make sure it's not the hole.
- __ mov(ebx, Operand(ecx, eax, times_2,
+ __ mov(ebx, Operand(eax, ecx, times_2,
FixedArray::kHeaderSize - kHeapObjectTag));
__ cmp(ebx, masm->isolate()->factory()->the_hole_value());
__ j(equal, &miss_force_generic);
@@ -3693,7 +3738,7 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- eax : key
+ // -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
@@ -3702,39 +3747,38 @@ void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(eax, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic);
// Get the elements array.
- __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
- __ AssertFastElements(ecx);
+ __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
+ __ AssertFastElements(eax);
// Check that the key is within bounds.
- __ cmp(eax, FieldOperand(ecx, FixedDoubleArray::kLengthOffset));
+ __ cmp(ecx, FieldOperand(eax, FixedDoubleArray::kLengthOffset));
__ j(above_equal, &miss_force_generic);
// Check for the hole
uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
- __ cmp(FieldOperand(ecx, eax, times_4, offset), Immediate(kHoleNanUpper32));
+ __ cmp(FieldOperand(eax, ecx, times_4, offset), Immediate(kHoleNanUpper32));
__ j(equal, &miss_force_generic);
// Always allocate a heap number for the result.
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
- __ movdbl(xmm0, FieldOperand(ecx, eax, times_4,
+ __ movdbl(xmm0, FieldOperand(eax, ecx, times_4,
FixedDoubleArray::kHeaderSize));
} else {
- __ fld_d(FieldOperand(ecx, eax, times_4, FixedDoubleArray::kHeaderSize));
+ __ fld_d(FieldOperand(eax, ecx, times_4, FixedDoubleArray::kHeaderSize));
}
- __ AllocateHeapNumber(ecx, ebx, edi, &slow_allocate_heapnumber);
+ __ AllocateHeapNumber(eax, ebx, edi, &slow_allocate_heapnumber);
// Set the value.
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
- __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0);
+ __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
} else {
- __ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset));
+ __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
}
- __ mov(eax, ecx);
__ ret(0);
__ bind(&slow_allocate_heapnumber);
@@ -3771,8 +3815,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(ecx, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
__ JumpIfNotSmi(eax, &transition_elements_kind);
@@ -3926,8 +3970,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(ecx, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
// Get the elements array.
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
@@ -3988,6 +4032,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
__ AllocateInNewSpace(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
+
// Restore the key, which is known to be the array length.
__ mov(ecx, Immediate(0));
diff --git a/src/3rdparty/v8/src/ic.cc b/src/3rdparty/v8/src/ic.cc
index 3e9c7a8..9772b94 100644
--- a/src/3rdparty/v8/src/ic.cc
+++ b/src/3rdparty/v8/src/ic.cc
@@ -352,9 +352,9 @@ void IC::Clear(Address address) {
return KeyedStoreIC::Clear(address, target);
case Code::CALL_IC: return CallIC::Clear(address, target);
case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target);
+ case Code::COMPARE_IC: return CompareIC::Clear(address, target);
case Code::UNARY_OP_IC:
case Code::BINARY_OP_IC:
- case Code::COMPARE_IC:
case Code::TO_BOOLEAN_IC:
// Clearing these is tricky and does not
// make any performance difference.
@@ -365,9 +365,8 @@ void IC::Clear(Address address) {
void CallICBase::Clear(Address address, Code* target) {
+ if (target->ic_state() == UNINITIALIZED) return;
bool contextual = CallICBase::Contextual::decode(target->extra_ic_state());
- State state = target->ic_state();
- if (state == UNINITIALIZED) return;
Code* code =
Isolate::Current()->stub_cache()->FindCallInitialize(
target->arguments_count(),
@@ -410,6 +409,17 @@ void KeyedStoreIC::Clear(Address address, Code* target) {
}
+void CompareIC::Clear(Address address, Code* target) {
+ // Only clear ICCompareStubs, we currently cannot clear generic CompareStubs.
+ if (target->major_key() != CodeStub::CompareIC) return;
+ // Only clear CompareICs that can retain objects.
+ if (target->compare_state() != KNOWN_OBJECTS) return;
+ Token::Value op = CompareIC::ComputeOperation(target);
+ SetTargetAtAddress(address, GetRawUninitialized(op));
+ PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
+}
+
+
static bool HasInterceptorGetter(JSObject* object) {
return !object->GetNamedInterceptor()->getter()->IsUndefined();
}
@@ -665,7 +675,7 @@ Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup,
// applicable.
if (!holder.is_identical_to(receiver)) return Handle<Code>::null();
return isolate()->stub_cache()->ComputeCallNormal(
- argc, kind_, extra_state, IsQmlGlobal(holder));
+ argc, kind_, extra_state);
}
break;
}
@@ -1053,18 +1063,33 @@ Handle<Code> KeyedLoadIC::ComputePolymorphicStub(
}
+static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
+ // This helper implements a few common fast cases for converting
+ // non-smi keys of keyed loads/stores to a smi or a string.
+ if (key->IsHeapNumber()) {
+ double value = Handle<HeapNumber>::cast(key)->value();
+ if (isnan(value)) {
+ key = isolate->factory()->nan_symbol();
+ } else {
+ int int_value = FastD2I(value);
+ if (value == int_value && Smi::IsValid(int_value)) {
+ key = Handle<Smi>(Smi::FromInt(int_value));
+ }
+ }
+ } else if (key->IsUndefined()) {
+ key = isolate->factory()->undefined_symbol();
+ }
+ return key;
+}
+
+
MaybeObject* KeyedLoadIC::Load(State state,
Handle<Object> object,
Handle<Object> key,
bool force_generic_stub) {
- // Check for values that can be converted into a symbol.
- // TODO(1295): Remove this code.
- if (key->IsHeapNumber() &&
- isnan(Handle<HeapNumber>::cast(key)->value())) {
- key = isolate()->factory()->nan_symbol();
- } else if (key->IsUndefined()) {
- key = isolate()->factory()->undefined_symbol();
- }
+ // Check for values that can be converted into a symbol directly or
+ // is representable as a smi.
+ key = TryConvertKey(key, isolate());
if (key->IsSymbol()) {
Handle<String> name = Handle<String>::cast(key);
@@ -1761,6 +1786,10 @@ MaybeObject* KeyedStoreIC::Store(State state,
Handle<Object> key,
Handle<Object> value,
bool force_generic) {
+ // Check for values that can be converted into a symbol directly or
+ // is representable as a smi.
+ key = TryConvertKey(key, isolate());
+
if (key->IsSymbol()) {
Handle<String> name = Handle<String>::cast(key);
@@ -2377,7 +2406,7 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
// Activate inlined smi code.
if (previous_type == BinaryOpIC::UNINITIALIZED) {
- PatchInlinedSmiCode(ic.address());
+ PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK);
}
}
@@ -2438,6 +2467,14 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
}
+Code* CompareIC::GetRawUninitialized(Token::Value op) {
+ ICCompareStub stub(op, UNINITIALIZED);
+ Code* code = NULL;
+ CHECK(stub.FindCodeInCache(&code));
+ return code;
+}
+
+
Handle<Code> CompareIC::GetUninitialized(Token::Value op) {
ICCompareStub stub(op, UNINITIALIZED);
return stub.GetCode();
@@ -2452,6 +2489,12 @@ CompareIC::State CompareIC::ComputeState(Code* target) {
}
+Token::Value CompareIC::ComputeOperation(Code* target) {
+ ASSERT(target->major_key() == CodeStub::CompareIC);
+ return static_cast<Token::Value>(target->compare_operation());
+}
+
+
const char* CompareIC::GetStateName(State state) {
switch (state) {
case UNINITIALIZED: return "UNINITIALIZED";
diff --git a/src/3rdparty/v8/src/ic.h b/src/3rdparty/v8/src/ic.h
index 9af865d..3b44abf 100644
--- a/src/3rdparty/v8/src/ic.h
+++ b/src/3rdparty/v8/src/ic.h
@@ -110,16 +110,10 @@ class IC {
// object that contains this IC site.
RelocInfo::Mode ComputeMode();
- bool IsQmlGlobal(Handle<Object> receiver) {
- JSObject* qml_global = isolate_->context()->qml_global();
- return !qml_global->IsUndefined() && qml_global == *receiver;
- }
-
// Returns if this IC is for contextual (no explicit receiver)
// access to properties.
bool IsContextual(Handle<Object> receiver) {
- if (receiver->IsGlobalObject() ||
- IsQmlGlobal(receiver)) {
+ if (receiver->IsGlobalObject()) {
return SlowIsContextual();
} else {
ASSERT(!SlowIsContextual());
@@ -800,6 +794,9 @@ class CompareIC: public IC {
// Helper function for determining the state of a compare IC.
static State ComputeState(Code* target);
+ // Helper function for determining the operation a compare IC is for.
+ static Token::Value ComputeOperation(Code* target);
+
static const char* GetStateName(State state);
private:
@@ -810,7 +807,13 @@ class CompareIC: public IC {
Condition GetCondition() const { return ComputeCondition(op_); }
State GetState() { return ComputeState(target()); }
+ static Code* GetRawUninitialized(Token::Value op);
+
+ static void Clear(Address address, Code* target);
+
Token::Value op_;
+
+ friend class IC;
};
@@ -823,7 +826,8 @@ class ToBooleanIC: public IC {
// Helper for BinaryOpIC and CompareIC.
-void PatchInlinedSmiCode(Address address);
+enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK };
+void PatchInlinedSmiCode(Address address, InlinedSmiCheck check);
} } // namespace v8::internal
diff --git a/src/3rdparty/v8/src/incremental-marking-inl.h b/src/3rdparty/v8/src/incremental-marking-inl.h
index 3e3d6c4..2dae6f2 100644
--- a/src/3rdparty/v8/src/incremental-marking-inl.h
+++ b/src/3rdparty/v8/src/incremental-marking-inl.h
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -100,7 +100,7 @@ void IncrementalMarking::BlackToGreyAndUnshift(HeapObject* obj,
int64_t old_bytes_rescanned = bytes_rescanned_;
bytes_rescanned_ = old_bytes_rescanned + obj_size;
if ((bytes_rescanned_ >> 20) != (old_bytes_rescanned >> 20)) {
- if (bytes_rescanned_ > 2 * heap_->PromotedSpaceSize()) {
+ if (bytes_rescanned_ > 2 * heap_->PromotedSpaceSizeOfObjects()) {
// If we have queued twice the heap size for rescanning then we are
// going around in circles, scanning the same objects again and again
// as the program mutates the heap faster than we can incrementally
@@ -118,13 +118,29 @@ void IncrementalMarking::BlackToGreyAndUnshift(HeapObject* obj,
void IncrementalMarking::WhiteToGreyAndPush(HeapObject* obj, MarkBit mark_bit) {
- WhiteToGrey(obj, mark_bit);
+ Marking::WhiteToGrey(mark_bit);
marking_deque_.PushGrey(obj);
}
-void IncrementalMarking::WhiteToGrey(HeapObject* obj, MarkBit mark_bit) {
- Marking::WhiteToGrey(mark_bit);
+bool IncrementalMarking::MarkObjectAndPush(HeapObject* obj) {
+ MarkBit mark_bit = Marking::MarkBitFrom(obj);
+ if (!mark_bit.Get()) {
+ WhiteToGreyAndPush(obj, mark_bit);
+ return true;
+ }
+ return false;
+}
+
+
+bool IncrementalMarking::MarkObjectWithoutPush(HeapObject* obj) {
+ MarkBit mark_bit = Marking::MarkBitFrom(obj);
+ if (!mark_bit.Get()) {
+ mark_bit.Set();
+ MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size());
+ return true;
+ }
+ return false;
}
diff --git a/src/3rdparty/v8/src/incremental-marking.cc b/src/3rdparty/v8/src/incremental-marking.cc
index 7bbd521..94afffa 100644
--- a/src/3rdparty/v8/src/incremental-marking.cc
+++ b/src/3rdparty/v8/src/incremental-marking.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -42,6 +42,7 @@ IncrementalMarking::IncrementalMarking(Heap* heap)
state_(STOPPED),
marking_deque_memory_(NULL),
marking_deque_memory_committed_(false),
+ marker_(this, heap->mark_compact_collector()),
steps_count_(0),
steps_took_(0),
longest_step_(0.0),
@@ -663,6 +664,22 @@ void IncrementalMarking::Hurry() {
} else if (map == global_context_map) {
// Global contexts have weak fields.
VisitGlobalContext(Context::cast(obj), &marking_visitor);
+ } else if (map->instance_type() == MAP_TYPE) {
+ Map* map = Map::cast(obj);
+ heap_->ClearCacheOnMap(map);
+
+ // When map collection is enabled we have to mark through map's
+ // transitions and back pointers in a special way to make these links
+ // weak. Only maps for subclasses of JSReceiver can have transitions.
+ STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
+ if (FLAG_collect_maps &&
+ map->instance_type() >= FIRST_JS_RECEIVER_TYPE) {
+ marker_.MarkMapContents(map);
+ } else {
+ marking_visitor.VisitPointers(
+ HeapObject::RawField(map, Map::kPointerFieldsBeginOffset),
+ HeapObject::RawField(map, Map::kPointerFieldsEndOffset));
+ }
} else {
obj->Iterate(&marking_visitor);
}
@@ -807,12 +824,6 @@ void IncrementalMarking::Step(intptr_t allocated_bytes,
Map* map = obj->map();
if (map == filler_map) continue;
- if (obj->IsMap()) {
- Map* map = Map::cast(obj);
- heap_->ClearCacheOnMap(map);
- }
-
-
int size = obj->SizeFromMap(map);
bytes_to_process -= size;
MarkBit map_mark_bit = Marking::MarkBitFrom(map);
@@ -830,6 +841,35 @@ void IncrementalMarking::Step(intptr_t allocated_bytes,
MarkObjectGreyDoNotEnqueue(ctx->normalized_map_cache());
VisitGlobalContext(ctx, &marking_visitor);
+ } else if (map->instance_type() == MAP_TYPE) {
+ Map* map = Map::cast(obj);
+ heap_->ClearCacheOnMap(map);
+
+ // When map collection is enabled we have to mark through map's
+ // transitions and back pointers in a special way to make these links
+ // weak. Only maps for subclasses of JSReceiver can have transitions.
+ STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
+ if (FLAG_collect_maps &&
+ map->instance_type() >= FIRST_JS_RECEIVER_TYPE) {
+ marker_.MarkMapContents(map);
+ } else {
+ marking_visitor.VisitPointers(
+ HeapObject::RawField(map, Map::kPointerFieldsBeginOffset),
+ HeapObject::RawField(map, Map::kPointerFieldsEndOffset));
+ }
+ } else if (map->instance_type() == JS_FUNCTION_TYPE) {
+ marking_visitor.VisitPointers(
+ HeapObject::RawField(obj, JSFunction::kPropertiesOffset),
+ HeapObject::RawField(obj, JSFunction::kCodeEntryOffset));
+
+ marking_visitor.VisitCodeEntry(
+ obj->address() + JSFunction::kCodeEntryOffset);
+
+ marking_visitor.VisitPointers(
+ HeapObject::RawField(obj,
+ JSFunction::kCodeEntryOffset + kPointerSize),
+ HeapObject::RawField(obj,
+ JSFunction::kNonWeakFieldsEndOffset));
} else {
obj->IterateBody(map->instance_type(), size, &marking_visitor);
}
@@ -938,7 +978,7 @@ void IncrementalMarking::ResetStepCounters() {
int64_t IncrementalMarking::SpaceLeftInOldSpace() {
- return heap_->MaxOldGenerationSize() - heap_->PromotedSpaceSize();
+ return heap_->MaxOldGenerationSize() - heap_->PromotedSpaceSizeOfObjects();
}
} } // namespace v8::internal
diff --git a/src/3rdparty/v8/src/incremental-marking.h b/src/3rdparty/v8/src/incremental-marking.h
index 8cbe6c1..39e8dae 100644
--- a/src/3rdparty/v8/src/incremental-marking.h
+++ b/src/3rdparty/v8/src/incremental-marking.h
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -154,8 +154,6 @@ class IncrementalMarking {
inline void WhiteToGreyAndPush(HeapObject* obj, MarkBit mark_bit);
- inline void WhiteToGrey(HeapObject* obj, MarkBit mark_bit);
-
// Does white->black or keeps gray or black color. Returns true if converting
// white to black.
inline bool MarkBlackOrKeepGrey(MarkBit mark_bit) {
@@ -169,6 +167,16 @@ class IncrementalMarking {
return true;
}
+ // Marks the object grey and pushes it on the marking stack.
+ // Returns true if object needed marking and false otherwise.
+ // This is for incremental marking only.
+ INLINE(bool MarkObjectAndPush(HeapObject* obj));
+
+ // Marks the object black without pushing it on the marking stack.
+ // Returns true if object needed marking and false otherwise.
+ // This is for incremental marking only.
+ INLINE(bool MarkObjectWithoutPush(HeapObject* obj));
+
inline int steps_count() {
return steps_count_;
}
@@ -260,6 +268,7 @@ class IncrementalMarking {
VirtualMemory* marking_deque_memory_;
bool marking_deque_memory_committed_;
MarkingDeque marking_deque_;
+ Marker<IncrementalMarking> marker_;
int steps_count_;
double steps_took_;
diff --git a/src/3rdparty/v8/src/interface.cc b/src/3rdparty/v8/src/interface.cc
index e344b86..7836110 100644
--- a/src/3rdparty/v8/src/interface.cc
+++ b/src/3rdparty/v8/src/interface.cc
@@ -79,7 +79,7 @@ void Interface::DoAdd(
PrintF("%*sthis = ", Nesting::current(), "");
this->Print(Nesting::current());
PrintF("%*s%s : ", Nesting::current(), "",
- (*reinterpret_cast<String**>(name))->ToAsciiArray());
+ (*static_cast<String**>(name))->ToAsciiArray());
interface->Print(Nesting::current());
}
#endif
@@ -97,7 +97,7 @@ void Interface::DoAdd(
#ifdef DEBUG
Nesting nested;
#endif
- reinterpret_cast<Interface*>(p->value)->Unify(interface, ok);
+ static_cast<Interface*>(p->value)->Unify(interface, ok);
}
#ifdef DEBUG
@@ -180,6 +180,15 @@ void Interface::DoUnify(Interface* that, bool* ok) {
return;
}
+ // Merge instance.
+ if (!that->instance_.is_null()) {
+ if (!this->instance_.is_null() && *this->instance_ != *that->instance_) {
+ *ok = false;
+ return;
+ }
+ this->instance_ = that->instance_;
+ }
+
// Merge interfaces.
this->flags_ |= that->flags_;
that->forward_ = this;
diff --git a/src/3rdparty/v8/src/interface.h b/src/3rdparty/v8/src/interface.h
index c2991cb..580f082 100644
--- a/src/3rdparty/v8/src/interface.h
+++ b/src/3rdparty/v8/src/interface.h
@@ -86,6 +86,12 @@ class Interface : public ZoneObject {
if (*ok) Chase()->flags_ |= MODULE;
}
+ // Set associated instance object.
+ void MakeSingleton(Handle<JSModule> instance, bool* ok) {
+ *ok = IsModule() && Chase()->instance_.is_null();
+ if (*ok) Chase()->instance_ = instance;
+ }
+
// Do not allow any further refinements, directly or through unification.
void Freeze(bool* ok) {
*ok = IsValue() || IsModule();
@@ -95,9 +101,6 @@ class Interface : public ZoneObject {
// ---------------------------------------------------------------------------
// Accessors.
- // Look up an exported name. Returns NULL if not (yet) defined.
- Interface* Lookup(Handle<String> name);
-
// Check whether this is still a fully undetermined type.
bool IsUnknown() { return Chase()->flags_ == NONE; }
@@ -110,6 +113,42 @@ class Interface : public ZoneObject {
// Check whether this is closed (i.e. fully determined).
bool IsFrozen() { return Chase()->flags_ & FROZEN; }
+ Handle<JSModule> Instance() { return Chase()->instance_; }
+
+ // Look up an exported name. Returns NULL if not (yet) defined.
+ Interface* Lookup(Handle<String> name);
+
+ // ---------------------------------------------------------------------------
+ // Iterators.
+
+ // Use like:
+ // for (auto it = interface->iterator(); !it.done(); it.Advance()) {
+ // ... it.name() ... it.interface() ...
+ // }
+ class Iterator {
+ public:
+ bool done() const { return entry_ == NULL; }
+ Handle<String> name() const {
+ ASSERT(!done());
+ return Handle<String>(*static_cast<String**>(entry_->key));
+ }
+ Interface* interface() const {
+ ASSERT(!done());
+ return static_cast<Interface*>(entry_->value);
+ }
+ void Advance() { entry_ = exports_->Next(entry_); }
+
+ private:
+ friend class Interface;
+ explicit Iterator(const ZoneHashMap* exports)
+ : exports_(exports), entry_(exports ? exports->Start() : NULL) {}
+
+ const ZoneHashMap* exports_;
+ ZoneHashMap::Entry* entry_;
+ };
+
+ Iterator iterator() const { return Iterator(this->exports_); }
+
// ---------------------------------------------------------------------------
// Debugging.
#ifdef DEBUG
@@ -129,6 +168,7 @@ class Interface : public ZoneObject {
int flags_;
Interface* forward_; // Unification link
ZoneHashMap* exports_; // Module exports and their types (allocated lazily)
+ Handle<JSModule> instance_;
explicit Interface(int flags)
: flags_(flags),
diff --git a/src/3rdparty/v8/src/isolate.cc b/src/3rdparty/v8/src/isolate.cc
index 535ffb1..0c97abd 100644
--- a/src/3rdparty/v8/src/isolate.cc
+++ b/src/3rdparty/v8/src/isolate.cc
@@ -97,7 +97,6 @@ void ThreadLocalTop::InitializeInternal() {
thread_id_ = ThreadId::Invalid();
external_caught_exception_ = false;
failed_access_check_callback_ = NULL;
- user_object_comparison_callback_ = NULL;
save_context_ = NULL;
catcher_ = NULL;
top_lookup_result_ = NULL;
@@ -744,12 +743,6 @@ void Isolate::SetFailedAccessCheckCallback(
thread_local_top()->failed_access_check_callback_ = callback;
}
-
-void Isolate::SetUserObjectComparisonCallback(
- v8::UserObjectComparisonCallback callback) {
- thread_local_top()->user_object_comparison_callback_ = callback;
-}
-
void Isolate::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
if (!thread_local_top()->failed_access_check_callback_) return;
@@ -1437,6 +1430,7 @@ void Isolate::ThreadDataTable::RemoveAllThreads(Isolate* isolate) {
Isolate::Isolate()
: state_(UNINITIALIZED),
+ embedder_data_(NULL),
entry_stack_(NULL),
stack_trace_nesting_level_(0),
incomplete_message_(NULL),
@@ -1479,7 +1473,6 @@ Isolate::Isolate()
string_tracker_(NULL),
regexp_stack_(NULL),
date_cache_(NULL),
- embedder_data_(NULL),
context_exit_happened_(false) {
TRACE_ISOLATE(constructor);
@@ -1849,6 +1842,9 @@ bool Isolate::Init(Deserializer* des) {
// stack guard.
heap_.SetStackLimits();
+ // Quiet the heap NaN if needed on target platform.
+ if (des != NULL) Assembler::QuietNaN(heap_.nan_value());
+
deoptimizer_data_ = new DeoptimizerData;
runtime_profiler_ = new RuntimeProfiler(this);
runtime_profiler_->SetUp();
@@ -1861,6 +1857,13 @@ bool Isolate::Init(Deserializer* des) {
LOG(this, LogCompiledFunctions());
}
+ CHECK_EQ(static_cast<int>(OFFSET_OF(Isolate, state_)),
+ Internals::kIsolateStateOffset);
+ CHECK_EQ(static_cast<int>(OFFSET_OF(Isolate, embedder_data_)),
+ Internals::kIsolateEmbedderDataOffset);
+ CHECK_EQ(static_cast<int>(OFFSET_OF(Isolate, heap_.roots_)),
+ Internals::kIsolateRootsOffset);
+
state_ = INITIALIZED;
time_millis_at_init_ = OS::TimeCurrentMillis();
return true;
diff --git a/src/3rdparty/v8/src/isolate.h b/src/3rdparty/v8/src/isolate.h
index 9f964a0..f1c9b3c 100644
--- a/src/3rdparty/v8/src/isolate.h
+++ b/src/3rdparty/v8/src/isolate.h
@@ -273,9 +273,6 @@ class ThreadLocalTop BASE_EMBEDDED {
// Head of the list of live LookupResults.
LookupResult* top_lookup_result_;
- // Call back function for user object comparisons
- v8::UserObjectComparisonCallback user_object_comparison_callback_;
-
// Whether out of memory exceptions should be ignored.
bool ignore_out_of_memory_;
@@ -425,7 +422,7 @@ class Isolate {
enum AddressId {
#define DECLARE_ENUM(CamelName, hacker_name) k##CamelName##Address,
FOR_EACH_ISOLATE_ADDRESS_NAME(DECLARE_ENUM)
-#undef C
+#undef DECLARE_ENUM
kIsolateAddressCount
};
@@ -705,11 +702,6 @@ class Isolate {
void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback);
void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type);
- void SetUserObjectComparisonCallback(v8::UserObjectComparisonCallback callback);
- inline v8::UserObjectComparisonCallback UserObjectComparisonCallback() {
- return thread_local_top()->user_object_comparison_callback_;
- }
-
// Exception throwing support. The caller should use the result
// of Throw() as its return value.
Failure* Throw(Object* exception, MessageLocation* location = NULL);
@@ -1046,6 +1038,18 @@ class Isolate {
friend struct GlobalState;
friend struct InitializeGlobalState;
+ enum State {
+ UNINITIALIZED, // Some components may not have been allocated.
+ INITIALIZED // All components are fully initialized.
+ };
+
+ // These fields are accessed through the API, offsets must be kept in sync
+ // with v8::internal::Internals (in include/v8.h) constants. This is also
+ // verified in Isolate::Init() using runtime checks.
+ State state_; // Will be padded to kApiPointerSize.
+ void* embedder_data_;
+ Heap heap_;
+
// The per-process lock should be acquired before the ThreadDataTable is
// modified.
class ThreadDataTable {
@@ -1103,14 +1107,6 @@ class Isolate {
static void SetIsolateThreadLocals(Isolate* isolate,
PerIsolateThreadData* data);
- enum State {
- UNINITIALIZED, // Some components may not have been allocated.
- INITIALIZED // All components are fully initialized.
- };
-
- State state_;
- EntryStackItem* entry_stack_;
-
// Allocate and insert PerIsolateThreadData into the ThreadDataTable
// (regardless of whether such data already exists).
PerIsolateThreadData* AllocatePerIsolateThreadData(ThreadId thread_id);
@@ -1154,13 +1150,13 @@ class Isolate {
// the Error object.
bool IsErrorObject(Handle<Object> obj);
+ EntryStackItem* entry_stack_;
int stack_trace_nesting_level_;
StringStream* incomplete_message_;
// The preallocated memory thread singleton.
PreallocatedMemoryThread* preallocated_memory_thread_;
Address isolate_addresses_[kIsolateAddressCount + 1]; // NOLINT
NoAllocationStringAllocator* preallocated_message_space_;
-
Bootstrapper* bootstrapper_;
RuntimeProfiler* runtime_profiler_;
CompilationCache* compilation_cache_;
@@ -1169,7 +1165,6 @@ class Isolate {
Mutex* break_access_;
Atomic32 debugger_initialized_;
Mutex* debugger_access_;
- Heap heap_;
Logger* logger_;
StackGuard stack_guard_;
StatsTable* stats_table_;
@@ -1210,11 +1205,8 @@ class Isolate {
unibrow::Mapping<unibrow::Ecma262Canonicalize>
regexp_macro_assembler_canonicalize_;
RegExpStack* regexp_stack_;
-
DateCache* date_cache_;
-
unibrow::Mapping<unibrow::Ecma262Canonicalize> interp_canonicalize_mapping_;
- void* embedder_data_;
// The garbage collector should be a little more aggressive when it knows
// that a context was recently exited.
diff --git a/src/3rdparty/v8/src/jsregexp.cc b/src/3rdparty/v8/src/jsregexp.cc
index b7d0d30..3455abc 100644
--- a/src/3rdparty/v8/src/jsregexp.cc
+++ b/src/3rdparty/v8/src/jsregexp.cc
@@ -108,6 +108,30 @@ static inline void ThrowRegExpException(Handle<JSRegExp> re,
}
+ContainedInLattice AddRange(ContainedInLattice containment,
+ const int* ranges,
+ int ranges_length,
+ Interval new_range) {
+ ASSERT((ranges_length & 1) == 1);
+ ASSERT(ranges[ranges_length - 1] == String::kMaxUtf16CodeUnit + 1);
+ if (containment == kLatticeUnknown) return containment;
+ bool inside = false;
+ int last = 0;
+ for (int i = 0; i < ranges_length; inside = !inside, last = ranges[i], i++) {
+ // Consider the range from last to ranges[i].
+ // We haven't got to the new range yet.
+ if (ranges[i] <= new_range.from()) continue;
+ // New range is wholly inside last-ranges[i]. Note that new_range.to() is
+ // inclusive, but the values in ranges are not.
+ if (last <= new_range.from() && new_range.to() < ranges[i]) {
+ return Combine(containment, inside ? kLatticeIn : kLatticeOut);
+ }
+ return kLatticeUnknown;
+ }
+ return containment;
+}
+
+
// More makes code generation slower, less makes V8 benchmark score lower.
const int kMaxLookaheadForBoyerMoore = 8;
// In a 3-character pattern you can maximally step forwards 3 characters
@@ -2157,6 +2181,7 @@ void ActionNode::FillInBMInfo(int offset,
} else if (type_ != POSITIVE_SUBMATCH_SUCCESS) {
on_success()->FillInBMInfo(offset, bm, not_at_start);
}
+ SaveBMInfo(bm, not_at_start, offset);
}
@@ -2181,6 +2206,7 @@ void AssertionNode::FillInBMInfo(
// Match the behaviour of EatsAtLeast on this node.
if (type() == AT_START && not_at_start) return;
on_success()->FillInBMInfo(offset, bm, not_at_start);
+ SaveBMInfo(bm, not_at_start, offset);
}
@@ -2522,10 +2548,12 @@ void TextNode::GetQuickCheckDetails(QuickCheckDetails* details,
}
}
ASSERT(characters_filled_in != details->characters());
- on_success()-> GetQuickCheckDetails(details,
- compiler,
- characters_filled_in,
- true);
+ if (!details->cannot_match()) {
+ on_success()-> GetQuickCheckDetails(details,
+ compiler,
+ characters_filled_in,
+ true);
+ }
}
@@ -2603,6 +2631,148 @@ class VisitMarker {
};
+RegExpNode* SeqRegExpNode::FilterASCII(int depth) {
+ if (info()->replacement_calculated) return replacement();
+ if (depth < 0) return this;
+ ASSERT(!info()->visited);
+ VisitMarker marker(info());
+ return FilterSuccessor(depth - 1);
+}
+
+
+RegExpNode* SeqRegExpNode::FilterSuccessor(int depth) {
+ RegExpNode* next = on_success_->FilterASCII(depth - 1);
+ if (next == NULL) return set_replacement(NULL);
+ on_success_ = next;
+ return set_replacement(this);
+}
+
+
+RegExpNode* TextNode::FilterASCII(int depth) {
+ if (info()->replacement_calculated) return replacement();
+ if (depth < 0) return this;
+ ASSERT(!info()->visited);
+ VisitMarker marker(info());
+ int element_count = elms_->length();
+ for (int i = 0; i < element_count; i++) {
+ TextElement elm = elms_->at(i);
+ if (elm.type == TextElement::ATOM) {
+ Vector<const uc16> quarks = elm.data.u_atom->data();
+ for (int j = 0; j < quarks.length(); j++) {
+ // We don't need special handling for case independence
+ // because of the rule that case independence cannot make
+ // a non-ASCII character match an ASCII character.
+ if (quarks[j] > String::kMaxAsciiCharCode) {
+ return set_replacement(NULL);
+ }
+ }
+ } else {
+ ASSERT(elm.type == TextElement::CHAR_CLASS);
+ RegExpCharacterClass* cc = elm.data.u_char_class;
+ ZoneList<CharacterRange>* ranges = cc->ranges();
+ if (!CharacterRange::IsCanonical(ranges)) {
+ CharacterRange::Canonicalize(ranges);
+ }
+ // Now they are in order so we only need to look at the first.
+ int range_count = ranges->length();
+ if (cc->is_negated()) {
+ if (range_count != 0 &&
+ ranges->at(0).from() == 0 &&
+ ranges->at(0).to() >= String::kMaxAsciiCharCode) {
+ return set_replacement(NULL);
+ }
+ } else {
+ if (range_count == 0 ||
+ ranges->at(0).from() > String::kMaxAsciiCharCode) {
+ return set_replacement(NULL);
+ }
+ }
+ }
+ }
+ return FilterSuccessor(depth - 1);
+}
+
+
+RegExpNode* LoopChoiceNode::FilterASCII(int depth) {
+ if (info()->replacement_calculated) return replacement();
+ if (depth < 0) return this;
+ if (info()->visited) return this;
+ {
+ VisitMarker marker(info());
+
+ RegExpNode* continue_replacement = continue_node_->FilterASCII(depth - 1);
+ // If we can't continue after the loop then there is no sense in doing the
+ // loop.
+ if (continue_replacement == NULL) return set_replacement(NULL);
+ }
+
+ return ChoiceNode::FilterASCII(depth - 1);
+}
+
+
+RegExpNode* ChoiceNode::FilterASCII(int depth) {
+ if (info()->replacement_calculated) return replacement();
+ if (depth < 0) return this;
+ if (info()->visited) return this;
+ VisitMarker marker(info());
+ int choice_count = alternatives_->length();
+ int surviving = 0;
+ RegExpNode* survivor = NULL;
+ for (int i = 0; i < choice_count; i++) {
+ GuardedAlternative alternative = alternatives_->at(i);
+ RegExpNode* replacement = alternative.node()->FilterASCII(depth - 1);
+ ASSERT(replacement != this); // No missing EMPTY_MATCH_CHECK.
+ if (replacement != NULL) {
+ alternatives_->at(i).set_node(replacement);
+ surviving++;
+ survivor = replacement;
+ }
+ }
+ if (surviving < 2) return set_replacement(survivor);
+
+ set_replacement(this);
+ if (surviving == choice_count) {
+ return this;
+ }
+ // Only some of the nodes survived the filtering. We need to rebuild the
+ // alternatives list.
+ ZoneList<GuardedAlternative>* new_alternatives =
+ new ZoneList<GuardedAlternative>(surviving);
+ for (int i = 0; i < choice_count; i++) {
+ RegExpNode* replacement =
+ alternatives_->at(i).node()->FilterASCII(depth - 1);
+ if (replacement != NULL) {
+ alternatives_->at(i).set_node(replacement);
+ new_alternatives->Add(alternatives_->at(i));
+ }
+ }
+ alternatives_ = new_alternatives;
+ return this;
+}
+
+
+RegExpNode* NegativeLookaheadChoiceNode::FilterASCII(int depth) {
+ if (info()->replacement_calculated) return replacement();
+ if (depth < 0) return this;
+ if (info()->visited) return this;
+ VisitMarker marker(info());
+ // Alternative 0 is the negative lookahead, alternative 1 is what comes
+ // afterwards.
+ RegExpNode* node = alternatives_->at(1).node();
+ RegExpNode* replacement = node->FilterASCII(depth - 1);
+ if (replacement == NULL) return set_replacement(NULL);
+ alternatives_->at(1).set_node(replacement);
+
+ RegExpNode* neg_node = alternatives_->at(0).node();
+ RegExpNode* neg_replacement = neg_node->FilterASCII(depth - 1);
+ // If the negative lookahead is always going to fail then
+ // we don't need to check it.
+ if (neg_replacement == NULL) return set_replacement(replacement);
+ alternatives_->at(0).set_node(neg_replacement);
+ return set_replacement(this);
+}
+
+
void LoopChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
@@ -2617,12 +2787,14 @@ void LoopChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details,
void LoopChoiceNode::FillInBMInfo(
- int offset, BoyerMooreLookahead* bm, bool nas) {
+ int offset, BoyerMooreLookahead* bm, bool not_at_start) {
if (body_can_be_zero_length_) {
bm->SetRest(offset);
+ SaveBMInfo(bm, not_at_start, offset);
return;
}
- ChoiceNode::FillInBMInfo(offset, bm, nas);
+ ChoiceNode::FillInBMInfo(offset, bm, not_at_start);
+ SaveBMInfo(bm, not_at_start, offset);
}
@@ -2710,110 +2882,83 @@ static void EmitHat(RegExpCompiler* compiler,
}
-// Emit the code to handle \b and \B (word-boundary or non-word-boundary)
-// when we know whether the next character must be a word character or not.
-static void EmitHalfBoundaryCheck(AssertionNode::AssertionNodeType type,
- RegExpCompiler* compiler,
- RegExpNode* on_success,
- Trace* trace) {
+// Emit the code to handle \b and \B (word-boundary or non-word-boundary).
+void AssertionNode::EmitBoundaryCheck(RegExpCompiler* compiler, Trace* trace) {
RegExpMacroAssembler* assembler = compiler->macro_assembler();
- Label done;
-
- Trace new_trace(*trace);
-
- bool expect_word_character = (type == AssertionNode::AFTER_WORD_CHARACTER);
- Label* on_word = expect_word_character ? &done : new_trace.backtrack();
- Label* on_non_word = expect_word_character ? new_trace.backtrack() : &done;
-
- // Check whether previous character was a word character.
- switch (trace->at_start()) {
- case Trace::TRUE:
- if (expect_word_character) {
- assembler->GoTo(on_non_word);
- }
- break;
- case Trace::UNKNOWN:
- ASSERT_EQ(0, trace->cp_offset());
- assembler->CheckAtStart(on_non_word);
- // Fall through.
- case Trace::FALSE:
- int prev_char_offset = trace->cp_offset() - 1;
- assembler->LoadCurrentCharacter(prev_char_offset, NULL, false, 1);
- EmitWordCheck(assembler, on_word, on_non_word, expect_word_character);
- // We may or may not have loaded the previous character.
- new_trace.InvalidateCurrentCharacter();
+ Trace::TriBool next_is_word_character = Trace::UNKNOWN;
+ bool not_at_start = (trace->at_start() == Trace::FALSE);
+ BoyerMooreLookahead* lookahead = bm_info(not_at_start);
+ if (lookahead == NULL) {
+ int eats_at_least =
+ Min(kMaxLookaheadForBoyerMoore,
+ EatsAtLeast(kMaxLookaheadForBoyerMoore, 0, not_at_start));
+ if (eats_at_least >= 1) {
+ BoyerMooreLookahead* bm =
+ new BoyerMooreLookahead(eats_at_least, compiler);
+ FillInBMInfo(0, bm, not_at_start);
+ if (bm->at(0)->is_non_word()) next_is_word_character = Trace::FALSE;
+ if (bm->at(0)->is_word()) next_is_word_character = Trace::TRUE;
+ }
+ } else {
+ if (lookahead->at(0)->is_non_word()) next_is_word_character = Trace::FALSE;
+ if (lookahead->at(0)->is_word()) next_is_word_character = Trace::TRUE;
+ }
+ bool at_boundary = (type_ == AssertionNode::AT_BOUNDARY);
+ if (next_is_word_character == Trace::UNKNOWN) {
+ Label before_non_word;
+ Label before_word;
+ if (trace->characters_preloaded() != 1) {
+ assembler->LoadCurrentCharacter(trace->cp_offset(), &before_non_word);
+ }
+ // Fall through on non-word.
+ EmitWordCheck(assembler, &before_word, &before_non_word, false);
+ // Next character is not a word character.
+ assembler->Bind(&before_non_word);
+ Label ok;
+ BacktrackIfPrevious(compiler, trace, at_boundary ? kIsNonWord : kIsWord);
+ assembler->GoTo(&ok);
+
+ assembler->Bind(&before_word);
+ BacktrackIfPrevious(compiler, trace, at_boundary ? kIsWord : kIsNonWord);
+ assembler->Bind(&ok);
+ } else if (next_is_word_character == Trace::TRUE) {
+ BacktrackIfPrevious(compiler, trace, at_boundary ? kIsWord : kIsNonWord);
+ } else {
+ ASSERT(next_is_word_character == Trace::FALSE);
+ BacktrackIfPrevious(compiler, trace, at_boundary ? kIsNonWord : kIsWord);
}
-
- assembler->Bind(&done);
-
- on_success->Emit(compiler, &new_trace);
}
-// Emit the code to handle \b and \B (word-boundary or non-word-boundary).
-static void EmitBoundaryCheck(AssertionNode::AssertionNodeType type,
- RegExpCompiler* compiler,
- RegExpNode* on_success,
- Trace* trace) {
+void AssertionNode::BacktrackIfPrevious(
+ RegExpCompiler* compiler,
+ Trace* trace,
+ AssertionNode::IfPrevious backtrack_if_previous) {
RegExpMacroAssembler* assembler = compiler->macro_assembler();
- Label before_non_word;
- Label before_word;
- if (trace->characters_preloaded() != 1) {
- assembler->LoadCurrentCharacter(trace->cp_offset(), &before_non_word);
- }
- // Fall through on non-word.
- EmitWordCheck(assembler, &before_word, &before_non_word, false);
-
- // We will be loading the previous character into the current character
- // register.
Trace new_trace(*trace);
new_trace.InvalidateCurrentCharacter();
- Label ok;
- Label* boundary;
- Label* not_boundary;
- if (type == AssertionNode::AT_BOUNDARY) {
- boundary = &ok;
- not_boundary = new_trace.backtrack();
- } else {
- not_boundary = &ok;
- boundary = new_trace.backtrack();
- }
+ Label fall_through, dummy;
- // Next character is not a word character.
- assembler->Bind(&before_non_word);
- if (new_trace.cp_offset() == 0) {
- // The start of input counts as a non-word character, so the question is
- // decided if we are at the start.
- assembler->CheckAtStart(not_boundary);
- }
- // We already checked that we are not at the start of input so it must be
- // OK to load the previous character.
- assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1,
- &ok, // Unused dummy label in this call.
- false);
- // Fall through on non-word.
- EmitWordCheck(assembler, boundary, not_boundary, false);
- assembler->GoTo(not_boundary);
+ Label* non_word = backtrack_if_previous == kIsNonWord ?
+ new_trace.backtrack() :
+ &fall_through;
+ Label* word = backtrack_if_previous == kIsNonWord ?
+ &fall_through :
+ new_trace.backtrack();
- // Next character is a word character.
- assembler->Bind(&before_word);
if (new_trace.cp_offset() == 0) {
// The start of input counts as a non-word character, so the question is
// decided if we are at the start.
- assembler->CheckAtStart(boundary);
+ assembler->CheckAtStart(non_word);
}
// We already checked that we are not at the start of input so it must be
// OK to load the previous character.
- assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1,
- &ok, // Unused dummy label in this call.
- false);
- bool fall_through_on_word = (type == AssertionNode::AT_NON_BOUNDARY);
- EmitWordCheck(assembler, not_boundary, boundary, fall_through_on_word);
-
- assembler->Bind(&ok);
+ assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1, &dummy, false);
+ EmitWordCheck(assembler, word, non_word, backtrack_if_previous == kIsNonWord);
- on_success->Emit(compiler, &new_trace);
+ assembler->Bind(&fall_through);
+ on_success()->Emit(compiler, &new_trace);
}
@@ -2861,13 +3006,9 @@ void AssertionNode::Emit(RegExpCompiler* compiler, Trace* trace) {
return;
case AT_BOUNDARY:
case AT_NON_BOUNDARY: {
- EmitBoundaryCheck(type_, compiler, on_success(), trace);
+ EmitBoundaryCheck(compiler, trace);
return;
}
- case AFTER_WORD_CHARACTER:
- case AFTER_NONWORD_CHARACTER: {
- EmitHalfBoundaryCheck(type_, compiler, on_success(), trace);
- }
}
on_success()->Emit(compiler, trace);
}
@@ -3277,24 +3418,74 @@ class AlternativeGenerationList {
};
+// The '2' variant is has inclusive from and exclusive to.
+static const int kSpaceRanges[] = { '\t', '\r' + 1, ' ', ' ' + 1, 0x00A0,
+ 0x00A1, 0x1680, 0x1681, 0x180E, 0x180F, 0x2000, 0x200B, 0x2028, 0x202A,
+ 0x202F, 0x2030, 0x205F, 0x2060, 0x3000, 0x3001, 0xFEFF, 0xFF00, 0x10000 };
+static const int kSpaceRangeCount = ARRAY_SIZE(kSpaceRanges);
+
+static const int kWordRanges[] = {
+ '0', '9' + 1, 'A', 'Z' + 1, '_', '_' + 1, 'a', 'z' + 1, 0x10000 };
+static const int kWordRangeCount = ARRAY_SIZE(kWordRanges);
+static const int kDigitRanges[] = { '0', '9' + 1, 0x10000 };
+static const int kDigitRangeCount = ARRAY_SIZE(kDigitRanges);
+static const int kSurrogateRanges[] = { 0xd800, 0xe000, 0x10000 };
+static const int kSurrogateRangeCount = ARRAY_SIZE(kSurrogateRanges);
+static const int kLineTerminatorRanges[] = { 0x000A, 0x000B, 0x000D, 0x000E,
+ 0x2028, 0x202A, 0x10000 };
+static const int kLineTerminatorRangeCount = ARRAY_SIZE(kLineTerminatorRanges);
+
+
+void BoyerMoorePositionInfo::Set(int character) {
+ SetInterval(Interval(character, character));
+}
+
+
+void BoyerMoorePositionInfo::SetInterval(const Interval& interval) {
+ s_ = AddRange(s_, kSpaceRanges, kSpaceRangeCount, interval);
+ w_ = AddRange(w_, kWordRanges, kWordRangeCount, interval);
+ d_ = AddRange(d_, kDigitRanges, kDigitRangeCount, interval);
+ surrogate_ =
+ AddRange(surrogate_, kSurrogateRanges, kSurrogateRangeCount, interval);
+ if (interval.to() - interval.from() >= kMapSize - 1) {
+ if (map_count_ != kMapSize) {
+ map_count_ = kMapSize;
+ for (int i = 0; i < kMapSize; i++) map_->at(i) = true;
+ }
+ return;
+ }
+ for (int i = interval.from(); i <= interval.to(); i++) {
+ int mod_character = (i & kMask);
+ if (!map_->at(mod_character)) {
+ map_count_++;
+ map_->at(mod_character) = true;
+ }
+ if (map_count_ == kMapSize) return;
+ }
+}
+
+
+void BoyerMoorePositionInfo::SetAll() {
+ s_ = w_ = d_ = kLatticeUnknown;
+ if (map_count_ != kMapSize) {
+ map_count_ = kMapSize;
+ for (int i = 0; i < kMapSize; i++) map_->at(i) = true;
+ }
+}
+
+
BoyerMooreLookahead::BoyerMooreLookahead(
- int length, int map_length, RegExpCompiler* compiler)
+ int length, RegExpCompiler* compiler)
: length_(length),
- map_length_(map_length),
compiler_(compiler) {
- ASSERT(IsPowerOf2(map_length));
if (compiler->ascii()) {
max_char_ = String::kMaxAsciiCharCode;
} else {
max_char_ = String::kMaxUtf16CodeUnit;
}
- bitmaps_ = new ZoneList<ZoneList<bool>*>(length);
+ bitmaps_ = new ZoneList<BoyerMoorePositionInfo*>(length);
for (int i = 0; i < length; i++) {
- bitmaps_->Add(new ZoneList<bool>(map_length));
- ZoneList<bool>* map = bitmaps_->at(i);
- for (int i = 0; i < map_length; i++) {
- map->Add(false);
- }
+ bitmaps_->Add(new BoyerMoorePositionInfo());
}
}
@@ -3304,8 +3495,11 @@ BoyerMooreLookahead::BoyerMooreLookahead(
// different parameters at once this is a tradeoff.
bool BoyerMooreLookahead::FindWorthwhileInterval(int* from, int* to) {
int biggest_points = 0;
+ // If more than 32 characters out of 128 can occur it is unlikely that we can
+ // be lucky enough to step forwards much of the time.
+ const int kMaxMax = 32;
for (int max_number_of_chars = 4;
- max_number_of_chars < kTooManyCharacters;
+ max_number_of_chars < kMaxMax;
max_number_of_chars *= 2) {
biggest_points =
FindBestInterval(max_number_of_chars, biggest_points, from, to);
@@ -3332,7 +3526,7 @@ int BoyerMooreLookahead::FindBestInterval(
bool union_map[kSize];
for (int j = 0; j < kSize; j++) union_map[j] = false;
while (i < length_ && Count(i) <= max_number_of_chars) {
- ZoneList<bool>* map = bitmaps_->at(i);
+ BoyerMoorePositionInfo* map = bitmaps_->at(i);
for (int j = 0; j < kSize; j++) union_map[j] |= map->at(j);
i++;
}
@@ -3387,8 +3581,8 @@ int BoyerMooreLookahead::GetSkipTable(int min_lookahead,
int skip = max_lookahead + 1 - min_lookahead;
for (int i = max_lookahead; i >= min_lookahead; i--) {
- ZoneList<bool>* map = bitmaps_->at(i);
- for (int j = 0; j < map_length_; j++) {
+ BoyerMoorePositionInfo* map = bitmaps_->at(i);
+ for (int j = 0; j < kSize; j++) {
if (map->at(j)) {
boolean_skip_table->set(j, kDontSkipArrayEntry);
}
@@ -3401,29 +3595,29 @@ int BoyerMooreLookahead::GetSkipTable(int min_lookahead,
// See comment above on the implementation of GetSkipTable.
bool BoyerMooreLookahead::EmitSkipInstructions(RegExpMacroAssembler* masm) {
+ const int kSize = RegExpMacroAssembler::kTableSize;
+
int min_lookahead = 0;
int max_lookahead = 0;
if (!FindWorthwhileInterval(&min_lookahead, &max_lookahead)) return false;
bool found_single_character = false;
- bool abandoned_search_for_single_character = false;
int single_character = 0;
for (int i = max_lookahead; i >= min_lookahead; i--) {
- ZoneList<bool>* map = bitmaps_->at(i);
- for (int j = 0; j < map_length_; j++) {
+ BoyerMoorePositionInfo* map = bitmaps_->at(i);
+ if (map->map_count() > 1 ||
+ (found_single_character && map->map_count() != 0)) {
+ found_single_character = false;
+ break;
+ }
+ for (int j = 0; j < kSize; j++) {
if (map->at(j)) {
- if (found_single_character) {
- found_single_character = false; // Found two.
- abandoned_search_for_single_character = true;
- break;
- } else {
- found_single_character = true;
- single_character = j;
- }
+ found_single_character = true;
+ single_character = j;
+ break;
}
}
- if (abandoned_search_for_single_character) break;
}
int lookahead_width = max_lookahead + 1 - min_lookahead;
@@ -3437,8 +3631,7 @@ bool BoyerMooreLookahead::EmitSkipInstructions(RegExpMacroAssembler* masm) {
Label cont, again;
masm->Bind(&again);
masm->LoadCurrentCharacter(max_lookahead, &cont, true);
- if (max_char_ > map_length_) {
- ASSERT(map_length_ == RegExpMacroAssembler::kTableSize);
+ if (max_char_ > kSize) {
masm->CheckCharacterAfterAnd(single_character,
RegExpMacroAssembler::kTableMask,
&cont);
@@ -3452,7 +3645,7 @@ bool BoyerMooreLookahead::EmitSkipInstructions(RegExpMacroAssembler* masm) {
}
Handle<ByteArray> boolean_skip_table =
- FACTORY->NewByteArray(map_length_, TENURED);
+ FACTORY->NewByteArray(kSize, TENURED);
int skip_distance = GetSkipTable(
min_lookahead, max_lookahead, boolean_skip_table);
ASSERT(skip_distance != 0);
@@ -3631,16 +3824,20 @@ void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
// not be atoms, they can be any reasonably limited character class or
// small alternation.
ASSERT(trace->is_trivial()); // This is the case on LoopChoiceNodes.
- eats_at_least =
- Min(kMaxLookaheadForBoyerMoore,
- EatsAtLeast(kMaxLookaheadForBoyerMoore, 0, not_at_start));
- if (eats_at_least >= 1) {
- BoyerMooreLookahead bm(eats_at_least,
- RegExpMacroAssembler::kTableSize,
- compiler);
- GuardedAlternative alt0 = alternatives_->at(0);
- alt0.node()->FillInBMInfo(0, &bm, not_at_start);
- skip_was_emitted = bm.EmitSkipInstructions(macro_assembler);
+ BoyerMooreLookahead* lookahead = bm_info(not_at_start);
+ if (lookahead == NULL) {
+ eats_at_least =
+ Min(kMaxLookaheadForBoyerMoore,
+ EatsAtLeast(kMaxLookaheadForBoyerMoore, 0, not_at_start));
+ if (eats_at_least >= 1) {
+ BoyerMooreLookahead* bm =
+ new BoyerMooreLookahead(eats_at_least, compiler);
+ GuardedAlternative alt0 = alternatives_->at(0);
+ alt0.node()->FillInBMInfo(0, bm, not_at_start);
+ skip_was_emitted = bm->EmitSkipInstructions(macro_assembler);
+ }
+ } else {
+ skip_was_emitted = lookahead->EmitSkipInstructions(macro_assembler);
}
}
}
@@ -4203,12 +4400,6 @@ void DotPrinter::VisitAssertion(AssertionNode* that) {
case AssertionNode::AFTER_NEWLINE:
stream()->Add("label=\"(?<=\\n)\", shape=septagon");
break;
- case AssertionNode::AFTER_WORD_CHARACTER:
- stream()->Add("label=\"(?<=\\w)\", shape=septagon");
- break;
- case AssertionNode::AFTER_NONWORD_CHARACTER:
- stream()->Add("label=\"(?<=\\W)\", shape=septagon");
- break;
}
stream()->Add("];\n");
PrintAttributes(that);
@@ -4313,21 +4504,6 @@ void RegExpEngine::DotPrint(const char* label,
// -------------------------------------------------------------------
// Tree to graph conversion
-static const uc16 kSpaceRanges[] = { 0x0009, 0x000D, 0x0020, 0x0020, 0x00A0,
- 0x00A0, 0x1680, 0x1680, 0x180E, 0x180E, 0x2000, 0x200A, 0x2028, 0x2029,
- 0x202F, 0x202F, 0x205F, 0x205F, 0x3000, 0x3000, 0xFEFF, 0xFEFF };
-static const int kSpaceRangeCount = ARRAY_SIZE(kSpaceRanges);
-
-static const uc16 kWordRanges[] = { '0', '9', 'A', 'Z', '_', '_', 'a', 'z' };
-static const int kWordRangeCount = ARRAY_SIZE(kWordRanges);
-
-static const uc16 kDigitRanges[] = { '0', '9' };
-static const int kDigitRangeCount = ARRAY_SIZE(kDigitRanges);
-
-static const uc16 kLineTerminatorRanges[] = { 0x000A, 0x000A, 0x000D, 0x000D,
- 0x2028, 0x2029 };
-static const int kLineTerminatorRangeCount = ARRAY_SIZE(kLineTerminatorRanges);
-
RegExpNode* RegExpAtom::ToNode(RegExpCompiler* compiler,
RegExpNode* on_success) {
ZoneList<TextElement>* elms = new ZoneList<TextElement>(1);
@@ -4341,9 +4517,12 @@ RegExpNode* RegExpText::ToNode(RegExpCompiler* compiler,
return new TextNode(elements(), on_success);
}
+
static bool CompareInverseRanges(ZoneList<CharacterRange>* ranges,
- const uc16* special_class,
+ const int* special_class,
int length) {
+ length--; // Remove final 0x10000.
+ ASSERT(special_class[length] == 0x10000);
ASSERT(ranges->length() != 0);
ASSERT(length != 0);
ASSERT(special_class[0] != 0);
@@ -4359,7 +4538,7 @@ static bool CompareInverseRanges(ZoneList<CharacterRange>* ranges,
return false;
}
range = ranges->at((i >> 1) + 1);
- if (special_class[i+1] != range.from() - 1) {
+ if (special_class[i+1] != range.from()) {
return false;
}
}
@@ -4371,14 +4550,17 @@ static bool CompareInverseRanges(ZoneList<CharacterRange>* ranges,
static bool CompareRanges(ZoneList<CharacterRange>* ranges,
- const uc16* special_class,
+ const int* special_class,
int length) {
+ length--; // Remove final 0x10000.
+ ASSERT(special_class[length] == 0x10000);
if (ranges->length() * 2 != length) {
return false;
}
for (int i = 0; i < length; i += 2) {
CharacterRange range = ranges->at(i >> 1);
- if (range.from() != special_class[i] || range.to() != special_class[i+1]) {
+ if (range.from() != special_class[i] ||
+ range.to() != special_class[i + 1] - 1) {
return false;
}
}
@@ -4779,27 +4961,31 @@ RegExpNode* RegExpAlternative::ToNode(RegExpCompiler* compiler,
}
-static void AddClass(const uc16* elmv,
+static void AddClass(const int* elmv,
int elmc,
ZoneList<CharacterRange>* ranges) {
+ elmc--;
+ ASSERT(elmv[elmc] == 0x10000);
for (int i = 0; i < elmc; i += 2) {
- ASSERT(elmv[i] <= elmv[i + 1]);
- ranges->Add(CharacterRange(elmv[i], elmv[i + 1]));
+ ASSERT(elmv[i] < elmv[i + 1]);
+ ranges->Add(CharacterRange(elmv[i], elmv[i + 1] - 1));
}
}
-static void AddClassNegated(const uc16 *elmv,
+static void AddClassNegated(const int *elmv,
int elmc,
ZoneList<CharacterRange>* ranges) {
+ elmc--;
+ ASSERT(elmv[elmc] == 0x10000);
ASSERT(elmv[0] != 0x0000);
ASSERT(elmv[elmc-1] != String::kMaxUtf16CodeUnit);
uc16 last = 0x0000;
for (int i = 0; i < elmc; i += 2) {
ASSERT(last <= elmv[i] - 1);
- ASSERT(elmv[i] <= elmv[i + 1]);
+ ASSERT(elmv[i] < elmv[i + 1]);
ranges->Add(CharacterRange(last, elmv[i] - 1));
- last = elmv[i + 1] + 1;
+ last = elmv[i + 1];
}
ranges->Add(CharacterRange(last, String::kMaxUtf16CodeUnit));
}
@@ -4850,8 +5036,8 @@ void CharacterRange::AddClassEscape(uc16 type,
}
-Vector<const uc16> CharacterRange::GetWordBounds() {
- return Vector<const uc16>(kWordRanges, kWordRangeCount);
+Vector<const int> CharacterRange::GetWordBounds() {
+ return Vector<const int>(kWordRanges, kWordRangeCount - 1);
}
@@ -4883,7 +5069,7 @@ void CharacterRangeSplitter::Call(uc16 from, DispatchTable::Entry entry) {
void CharacterRange::Split(ZoneList<CharacterRange>* base,
- Vector<const uc16> overlay,
+ Vector<const int> overlay,
ZoneList<CharacterRange>** included,
ZoneList<CharacterRange>** excluded) {
ASSERT_EQ(NULL, *included);
@@ -4892,7 +5078,7 @@ void CharacterRange::Split(ZoneList<CharacterRange>* base,
for (int i = 0; i < base->length(); i++)
table.AddRange(base->at(i), CharacterRangeSplitter::kInBase);
for (int i = 0; i < overlay.length(); i += 2) {
- table.AddRange(CharacterRange(overlay[i], overlay[i+1]),
+ table.AddRange(CharacterRange(overlay[i], overlay[i + 1] - 1),
CharacterRangeSplitter::kInOverlay);
}
CharacterRangeSplitter callback(included, excluded);
@@ -4978,87 +5164,6 @@ bool CharacterRange::IsCanonical(ZoneList<CharacterRange>* ranges) {
return true;
}
-SetRelation CharacterRange::WordCharacterRelation(
- ZoneList<CharacterRange>* range) {
- ASSERT(IsCanonical(range));
- int i = 0; // Word character range index.
- int j = 0; // Argument range index.
- ASSERT_NE(0, kWordRangeCount);
- SetRelation result;
- if (range->length() == 0) {
- result.SetElementsInSecondSet();
- return result;
- }
- CharacterRange argument_range = range->at(0);
- CharacterRange word_range = CharacterRange(kWordRanges[0], kWordRanges[1]);
- while (i < kWordRangeCount && j < range->length()) {
- // Check the two ranges for the five cases:
- // - no overlap.
- // - partial overlap (there are elements in both ranges that isn't
- // in the other, and there are also elements that are in both).
- // - argument range entirely inside word range.
- // - word range entirely inside argument range.
- // - ranges are completely equal.
-
- // First check for no overlap. The earlier range is not in the other set.
- if (argument_range.from() > word_range.to()) {
- // Ranges are disjoint. The earlier word range contains elements that
- // cannot be in the argument set.
- result.SetElementsInSecondSet();
- } else if (word_range.from() > argument_range.to()) {
- // Ranges are disjoint. The earlier argument range contains elements that
- // cannot be in the word set.
- result.SetElementsInFirstSet();
- } else if (word_range.from() <= argument_range.from() &&
- word_range.to() >= argument_range.from()) {
- result.SetElementsInBothSets();
- // argument range completely inside word range.
- if (word_range.from() < argument_range.from() ||
- word_range.to() > argument_range.from()) {
- result.SetElementsInSecondSet();
- }
- } else if (word_range.from() >= argument_range.from() &&
- word_range.to() <= argument_range.from()) {
- result.SetElementsInBothSets();
- result.SetElementsInFirstSet();
- } else {
- // There is overlap, and neither is a subrange of the other
- result.SetElementsInFirstSet();
- result.SetElementsInSecondSet();
- result.SetElementsInBothSets();
- }
- if (result.NonTrivialIntersection()) {
- // The result is as (im)precise as we can possibly make it.
- return result;
- }
- // Progress the range(s) with minimal to-character.
- uc16 word_to = word_range.to();
- uc16 argument_to = argument_range.to();
- if (argument_to <= word_to) {
- j++;
- if (j < range->length()) {
- argument_range = range->at(j);
- }
- }
- if (word_to <= argument_to) {
- i += 2;
- if (i < kWordRangeCount) {
- word_range = CharacterRange(kWordRanges[i], kWordRanges[i + 1]);
- }
- }
- }
- // Check if anything wasn't compared in the loop.
- if (i < kWordRangeCount) {
- // word range contains something not in argument range.
- result.SetElementsInSecondSet();
- } else if (j < range->length()) {
- // Argument range contains something not in word range.
- result.SetElementsInFirstSet();
- }
-
- return result;
-}
-
ZoneList<CharacterRange>* CharacterSet::ranges() {
if (ranges_ == NULL) {
@@ -5191,145 +5296,6 @@ void CharacterRange::Canonicalize(ZoneList<CharacterRange>* character_ranges) {
}
-// Utility function for CharacterRange::Merge. Adds a range at the end of
-// a canonicalized range list, if necessary merging the range with the last
-// range of the list.
-static void AddRangeToSet(ZoneList<CharacterRange>* set, CharacterRange range) {
- if (set == NULL) return;
- ASSERT(set->length() == 0 || set->at(set->length() - 1).to() < range.from());
- int n = set->length();
- if (n > 0) {
- CharacterRange lastRange = set->at(n - 1);
- if (lastRange.to() == range.from() - 1) {
- set->at(n - 1) = CharacterRange(lastRange.from(), range.to());
- return;
- }
- }
- set->Add(range);
-}
-
-
-static void AddRangeToSelectedSet(int selector,
- ZoneList<CharacterRange>* first_set,
- ZoneList<CharacterRange>* second_set,
- ZoneList<CharacterRange>* intersection_set,
- CharacterRange range) {
- switch (selector) {
- case kInsideFirst:
- AddRangeToSet(first_set, range);
- break;
- case kInsideSecond:
- AddRangeToSet(second_set, range);
- break;
- case kInsideBoth:
- AddRangeToSet(intersection_set, range);
- break;
- }
-}
-
-
-
-void CharacterRange::Merge(ZoneList<CharacterRange>* first_set,
- ZoneList<CharacterRange>* second_set,
- ZoneList<CharacterRange>* first_set_only_out,
- ZoneList<CharacterRange>* second_set_only_out,
- ZoneList<CharacterRange>* both_sets_out) {
- // Inputs are canonicalized.
- ASSERT(CharacterRange::IsCanonical(first_set));
- ASSERT(CharacterRange::IsCanonical(second_set));
- // Outputs are empty, if applicable.
- ASSERT(first_set_only_out == NULL || first_set_only_out->length() == 0);
- ASSERT(second_set_only_out == NULL || second_set_only_out->length() == 0);
- ASSERT(both_sets_out == NULL || both_sets_out->length() == 0);
-
- // Merge sets by iterating through the lists in order of lowest "from" value,
- // and putting intervals into one of three sets.
-
- if (first_set->length() == 0) {
- second_set_only_out->AddAll(*second_set);
- return;
- }
- if (second_set->length() == 0) {
- first_set_only_out->AddAll(*first_set);
- return;
- }
- // Indices into input lists.
- int i1 = 0;
- int i2 = 0;
- // Cache length of input lists.
- int n1 = first_set->length();
- int n2 = second_set->length();
- // Current range. May be invalid if state is kInsideNone.
- int from = 0;
- int to = -1;
- // Where current range comes from.
- int state = kInsideNone;
-
- while (i1 < n1 || i2 < n2) {
- CharacterRange next_range;
- int range_source;
- if (i2 == n2 ||
- (i1 < n1 && first_set->at(i1).from() < second_set->at(i2).from())) {
- // Next smallest element is in first set.
- next_range = first_set->at(i1++);
- range_source = kInsideFirst;
- } else {
- // Next smallest element is in second set.
- next_range = second_set->at(i2++);
- range_source = kInsideSecond;
- }
- if (to < next_range.from()) {
- // Ranges disjoint: |current| |next|
- AddRangeToSelectedSet(state,
- first_set_only_out,
- second_set_only_out,
- both_sets_out,
- CharacterRange(from, to));
- from = next_range.from();
- to = next_range.to();
- state = range_source;
- } else {
- if (from < next_range.from()) {
- AddRangeToSelectedSet(state,
- first_set_only_out,
- second_set_only_out,
- both_sets_out,
- CharacterRange(from, next_range.from()-1));
- }
- if (to < next_range.to()) {
- // Ranges overlap: |current|
- // |next|
- AddRangeToSelectedSet(state | range_source,
- first_set_only_out,
- second_set_only_out,
- both_sets_out,
- CharacterRange(next_range.from(), to));
- from = to + 1;
- to = next_range.to();
- state = range_source;
- } else {
- // Range included: |current| , possibly ending at same character.
- // |next|
- AddRangeToSelectedSet(
- state | range_source,
- first_set_only_out,
- second_set_only_out,
- both_sets_out,
- CharacterRange(next_range.from(), next_range.to()));
- from = next_range.to() + 1;
- // If ranges end at same character, both ranges are consumed completely.
- if (next_range.to() == to) state = kInsideNone;
- }
- }
- }
- AddRangeToSelectedSet(state,
- first_set_only_out,
- second_set_only_out,
- both_sets_out,
- CharacterRange(from, to));
-}
-
-
void CharacterRange::Negate(ZoneList<CharacterRange>* ranges,
ZoneList<CharacterRange>* negated_ranges) {
ASSERT(CharacterRange::IsCanonical(ranges));
@@ -5353,45 +5319,6 @@ void CharacterRange::Negate(ZoneList<CharacterRange>* ranges,
}
-
-// -------------------------------------------------------------------
-// Interest propagation
-
-
-RegExpNode* RegExpNode::TryGetSibling(NodeInfo* info) {
- for (int i = 0; i < siblings_.length(); i++) {
- RegExpNode* sibling = siblings_.Get(i);
- if (sibling->info()->Matches(info))
- return sibling;
- }
- return NULL;
-}
-
-
-RegExpNode* RegExpNode::EnsureSibling(NodeInfo* info, bool* cloned) {
- ASSERT_EQ(false, *cloned);
- siblings_.Ensure(this);
- RegExpNode* result = TryGetSibling(info);
- if (result != NULL) return result;
- result = this->Clone();
- NodeInfo* new_info = result->info();
- new_info->ResetCompilationState();
- new_info->AddFromPreceding(info);
- AddSibling(result);
- *cloned = true;
- return result;
-}
-
-
-template <class C>
-static RegExpNode* PropagateToEndpoint(C* node, NodeInfo* info) {
- NodeInfo full_info(*node->info());
- full_info.AddFromPreceding(info);
- bool cloned = false;
- return RegExpNode::EnsureSibling(node, &full_info, &cloned);
-}
-
-
// -------------------------------------------------------------------
// Splay tree
@@ -5642,169 +5569,20 @@ void Analysis::VisitBackReference(BackReferenceNode* that) {
void Analysis::VisitAssertion(AssertionNode* that) {
EnsureAnalyzed(that->on_success());
- AssertionNode::AssertionNodeType type = that->type();
- if (type == AssertionNode::AT_BOUNDARY ||
- type == AssertionNode::AT_NON_BOUNDARY) {
- // Check if the following character is known to be a word character
- // or known to not be a word character.
- ZoneList<CharacterRange>* following_chars = that->FirstCharacterSet();
-
- CharacterRange::Canonicalize(following_chars);
-
- SetRelation word_relation =
- CharacterRange::WordCharacterRelation(following_chars);
- if (word_relation.Disjoint()) {
- // Includes the case where following_chars is empty (e.g., end-of-input).
- // Following character is definitely *not* a word character.
- type = (type == AssertionNode::AT_BOUNDARY) ?
- AssertionNode::AFTER_WORD_CHARACTER :
- AssertionNode::AFTER_NONWORD_CHARACTER;
- that->set_type(type);
- } else if (word_relation.ContainedIn()) {
- // Following character is definitely a word character.
- type = (type == AssertionNode::AT_BOUNDARY) ?
- AssertionNode::AFTER_NONWORD_CHARACTER :
- AssertionNode::AFTER_WORD_CHARACTER;
- that->set_type(type);
- }
- }
}
-ZoneList<CharacterRange>* RegExpNode::FirstCharacterSet() {
- if (first_character_set_ == NULL) {
- if (ComputeFirstCharacterSet(kFirstCharBudget) < 0) {
- // If we can't find an exact solution within the budget, we
- // set the value to the set of every character, i.e., all characters
- // are possible.
- ZoneList<CharacterRange>* all_set = new ZoneList<CharacterRange>(1);
- all_set->Add(CharacterRange::Everything());
- first_character_set_ = all_set;
- }
- }
- return first_character_set_;
-}
-
-
-int RegExpNode::ComputeFirstCharacterSet(int budget) {
- // Default behavior is to not be able to determine the first character.
- return kComputeFirstCharacterSetFail;
-}
-
-
-int LoopChoiceNode::ComputeFirstCharacterSet(int budget) {
- budget--;
- if (budget >= 0) {
- // Find loop min-iteration. It's the value of the guarded choice node
- // with a GEQ guard, if any.
- int min_repetition = 0;
-
- for (int i = 0; i <= 1; i++) {
- GuardedAlternative alternative = alternatives()->at(i);
- ZoneList<Guard*>* guards = alternative.guards();
- if (guards != NULL && guards->length() > 0) {
- Guard* guard = guards->at(0);
- if (guard->op() == Guard::GEQ) {
- min_repetition = guard->value();
- break;
- }
- }
- }
-
- budget = loop_node()->ComputeFirstCharacterSet(budget);
- if (budget >= 0) {
- ZoneList<CharacterRange>* character_set =
- loop_node()->first_character_set();
- if (body_can_be_zero_length() || min_repetition == 0) {
- budget = continue_node()->ComputeFirstCharacterSet(budget);
- if (budget < 0) return budget;
- ZoneList<CharacterRange>* body_set =
- continue_node()->first_character_set();
- ZoneList<CharacterRange>* union_set =
- new ZoneList<CharacterRange>(Max(character_set->length(),
- body_set->length()));
- CharacterRange::Merge(character_set,
- body_set,
- union_set,
- union_set,
- union_set);
- character_set = union_set;
- }
- set_first_character_set(character_set);
- }
- }
- return budget;
-}
-
-
-int NegativeLookaheadChoiceNode::ComputeFirstCharacterSet(int budget) {
- budget--;
- if (budget >= 0) {
- GuardedAlternative successor = this->alternatives()->at(1);
- RegExpNode* successor_node = successor.node();
- budget = successor_node->ComputeFirstCharacterSet(budget);
- if (budget >= 0) {
- set_first_character_set(successor_node->first_character_set());
- }
- }
- return budget;
-}
-
-
-// The first character set of an EndNode is unknowable. Just use the
-// default implementation that fails and returns all characters as possible.
-
-
-int AssertionNode::ComputeFirstCharacterSet(int budget) {
- budget -= 1;
- if (budget >= 0) {
- switch (type_) {
- case AT_END: {
- set_first_character_set(new ZoneList<CharacterRange>(0));
- break;
- }
- case AT_START:
- case AT_BOUNDARY:
- case AT_NON_BOUNDARY:
- case AFTER_NEWLINE:
- case AFTER_NONWORD_CHARACTER:
- case AFTER_WORD_CHARACTER: {
- ASSERT_NOT_NULL(on_success());
- budget = on_success()->ComputeFirstCharacterSet(budget);
- if (budget >= 0) {
- set_first_character_set(on_success()->first_character_set());
- }
- break;
- }
- }
- }
- return budget;
-}
-
-
-int ActionNode::ComputeFirstCharacterSet(int budget) {
- if (type_ == POSITIVE_SUBMATCH_SUCCESS) return kComputeFirstCharacterSetFail;
- budget--;
- if (budget >= 0) {
- ASSERT_NOT_NULL(on_success());
- budget = on_success()->ComputeFirstCharacterSet(budget);
- if (budget >= 0) {
- set_first_character_set(on_success()->first_character_set());
- }
- }
- return budget;
+void BackReferenceNode::FillInBMInfo(
+ int offset, BoyerMooreLookahead* bm, bool not_at_start) {
+ // Working out the set of characters that a backreference can match is too
+ // hard, so we just say that any character can match.
+ bm->SetRest(offset);
+ SaveBMInfo(bm, not_at_start, offset);
}
-int BackReferenceNode::ComputeFirstCharacterSet(int budget) {
- // We don't know anything about the first character of a backreference
- // at this point.
- // The potential first characters are the first characters of the capture,
- // and the first characters of the on_success node, depending on whether the
- // capture can be empty and whether it is known to be participating or known
- // not to be.
- return kComputeFirstCharacterSetFail;
-}
+STATIC_ASSERT(BoyerMoorePositionInfo::kMapSize ==
+ RegExpMacroAssembler::kTableSize);
void ChoiceNode::FillInBMInfo(
@@ -5814,24 +5592,33 @@ void ChoiceNode::FillInBMInfo(
GuardedAlternative& alt = alts->at(i);
if (alt.guards() != NULL && alt.guards()->length() != 0) {
bm->SetRest(offset); // Give up trying to fill in info.
+ SaveBMInfo(bm, not_at_start, offset);
return;
}
alt.node()->FillInBMInfo(offset, bm, not_at_start);
}
+ SaveBMInfo(bm, not_at_start, offset);
}
void TextNode::FillInBMInfo(
- int offset, BoyerMooreLookahead* bm, bool not_at_start) {
- if (offset >= bm->length()) return;
+ int initial_offset, BoyerMooreLookahead* bm, bool not_at_start) {
+ if (initial_offset >= bm->length()) return;
+ int offset = initial_offset;
int max_char = bm->max_char();
for (int i = 0; i < elements()->length(); i++) {
- if (offset >= bm->length()) return;
+ if (offset >= bm->length()) {
+ if (initial_offset == 0) set_bm_info(not_at_start, bm);
+ return;
+ }
TextElement text = elements()->at(i);
if (text.type == TextElement::ATOM) {
RegExpAtom* atom = text.data.u_atom;
for (int j = 0; j < atom->length(); j++, offset++) {
- if (offset >= bm->length()) return;
+ if (offset >= bm->length()) {
+ if (initial_offset == 0) set_bm_info(not_at_start, bm);
+ return;
+ }
uc16 character = atom->data()[j];
if (bm->compiler()->ignore_case()) {
unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
@@ -5858,67 +5645,23 @@ void TextNode::FillInBMInfo(
CharacterRange& range = ranges->at(k);
if (range.from() > max_char) continue;
int to = Min(max_char, static_cast<int>(range.to()));
- if (to - range.from() >= BoyerMooreLookahead::kTooManyCharacters) {
- bm->SetAll(offset);
- break;
- }
- for (int m = range.from(); m <= to; m++) {
- bm->Set(offset, m);
- }
+ bm->SetInterval(offset, Interval(range.from(), to));
}
}
offset++;
}
}
- if (offset >= bm->length()) return;
+ if (offset >= bm->length()) {
+ if (initial_offset == 0) set_bm_info(not_at_start, bm);
+ return;
+ }
on_success()->FillInBMInfo(offset,
bm,
true); // Not at start after a text node.
+ if (initial_offset == 0) set_bm_info(not_at_start, bm);
}
-int TextNode::ComputeFirstCharacterSet(int budget) {
- budget--;
- if (budget >= 0) {
- ASSERT_NE(0, elements()->length());
- TextElement text = elements()->at(0);
- if (text.type == TextElement::ATOM) {
- RegExpAtom* atom = text.data.u_atom;
- ASSERT_NE(0, atom->length());
- uc16 first_char = atom->data()[0];
- ZoneList<CharacterRange>* range = new ZoneList<CharacterRange>(1);
- range->Add(CharacterRange(first_char, first_char));
- set_first_character_set(range);
- } else {
- ASSERT(text.type == TextElement::CHAR_CLASS);
- RegExpCharacterClass* char_class = text.data.u_char_class;
- ZoneList<CharacterRange>* ranges = char_class->ranges();
- // TODO(lrn): Canonicalize ranges when they are created
- // instead of waiting until now.
- CharacterRange::Canonicalize(ranges);
- if (char_class->is_negated()) {
- int length = ranges->length();
- int new_length = length + 1;
- if (length > 0) {
- if (ranges->at(0).from() == 0) new_length--;
- if (ranges->at(length - 1).to() == String::kMaxUtf16CodeUnit) {
- new_length--;
- }
- }
- ZoneList<CharacterRange>* negated_ranges =
- new ZoneList<CharacterRange>(new_length);
- CharacterRange::Negate(ranges, negated_ranges);
- set_first_character_set(negated_ranges);
- } else {
- set_first_character_set(ranges);
- }
- }
- }
- return budget;
-}
-
-
-
// -------------------------------------------------------------------
// Dispatch table construction
@@ -6091,6 +5834,14 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(
node = loop_node;
}
}
+ if (is_ascii) {
+ node = node->FilterASCII(RegExpCompiler::kMaxRecursion);
+ // Do it again to propagate the new nodes to places where they were not
+ // put because they had not been calculated yet.
+ if (node != NULL) node = node->FilterASCII(RegExpCompiler::kMaxRecursion);
+ }
+
+ if (node == NULL) node = new EndNode(EndNode::BACKTRACK);
data->node = node;
Analysis analysis(ignore_case, is_ascii);
analysis.EnsureAnalyzed(node);
diff --git a/src/3rdparty/v8/src/jsregexp.h b/src/3rdparty/v8/src/jsregexp.h
index 288e995..20313ca 100644
--- a/src/3rdparty/v8/src/jsregexp.h
+++ b/src/3rdparty/v8/src/jsregexp.h
@@ -40,6 +40,7 @@ class RegExpCompiler;
class RegExpMacroAssembler;
class RegExpNode;
class RegExpTree;
+class BoyerMooreLookahead;
class RegExpImpl {
public:
@@ -224,48 +225,8 @@ enum ElementInSetsRelation {
};
-// Represents the relation of two sets.
-// Sets can be either disjoint, partially or fully overlapping, or equal.
-class SetRelation BASE_EMBEDDED {
- public:
- // Relation is represented by a bit saying whether there are elements in
- // one set that is not in the other, and a bit saying that there are elements
- // that are in both sets.
-
- // Location of an element. Corresponds to the internal areas of
- // a Venn diagram.
- enum {
- kInFirst = 1 << kInsideFirst,
- kInSecond = 1 << kInsideSecond,
- kInBoth = 1 << kInsideBoth
- };
- SetRelation() : bits_(0) {}
- ~SetRelation() {}
- // Add the existence of objects in a particular
- void SetElementsInFirstSet() { bits_ |= kInFirst; }
- void SetElementsInSecondSet() { bits_ |= kInSecond; }
- void SetElementsInBothSets() { bits_ |= kInBoth; }
- // Check the currently known relation of the sets (common functions only,
- // for other combinations, use value() to get the bits and check them
- // manually).
- // Sets are completely disjoint.
- bool Disjoint() { return (bits_ & kInBoth) == 0; }
- // Sets are equal.
- bool Equals() { return (bits_ & (kInFirst | kInSecond)) == 0; }
- // First set contains second.
- bool Contains() { return (bits_ & kInSecond) == 0; }
- // Second set contains first.
- bool ContainedIn() { return (bits_ & kInFirst) == 0; }
- bool NonTrivialIntersection() {
- return (bits_ == (kInFirst | kInSecond | kInBoth));
- }
- int value() { return bits_; }
-
- private:
- int bits_;
-};
-
-
+// Represents code units in the range from from_ to to_, both ends are
+// inclusive.
class CharacterRange {
public:
CharacterRange() : from_(0), to_(0) { }
@@ -273,7 +234,7 @@ class CharacterRange {
CharacterRange(void* null) { ASSERT_EQ(NULL, null); } //NOLINT
CharacterRange(uc16 from, uc16 to) : from_(from), to_(to) { }
static void AddClassEscape(uc16 type, ZoneList<CharacterRange>* ranges);
- static Vector<const uc16> GetWordBounds();
+ static Vector<const int> GetWordBounds();
static inline CharacterRange Singleton(uc16 value) {
return CharacterRange(value, value);
}
@@ -294,7 +255,7 @@ class CharacterRange {
bool IsSingleton() { return (from_ == to_); }
void AddCaseEquivalents(ZoneList<CharacterRange>* ranges, bool is_ascii);
static void Split(ZoneList<CharacterRange>* base,
- Vector<const uc16> overlay,
+ Vector<const int> overlay,
ZoneList<CharacterRange>** included,
ZoneList<CharacterRange>** excluded);
// Whether a range list is in canonical form: Ranges ordered by from value,
@@ -305,28 +266,6 @@ class CharacterRange {
// adjacent ranges are merged. The resulting list may be shorter than the
// original, but cannot be longer.
static void Canonicalize(ZoneList<CharacterRange>* ranges);
- // Check how the set of characters defined by a CharacterRange list relates
- // to the set of word characters. List must be in canonical form.
- static SetRelation WordCharacterRelation(ZoneList<CharacterRange>* ranges);
- // Takes two character range lists (representing character sets) in canonical
- // form and merges them.
- // The characters that are only covered by the first set are added to
- // first_set_only_out. the characters that are only in the second set are
- // added to second_set_only_out, and the characters that are in both are
- // added to both_sets_out.
- // The pointers to first_set_only_out, second_set_only_out and both_sets_out
- // should be to empty lists, but they need not be distinct, and may be NULL.
- // If NULL, the characters are dropped, and if two arguments are the same
- // pointer, the result is the union of the two sets that would be created
- // if the pointers had been distinct.
- // This way, the Merge function can compute all the usual set operations:
- // union (all three out-sets are equal), intersection (only both_sets_out is
- // non-NULL), and set difference (only first_set is non-NULL).
- static void Merge(ZoneList<CharacterRange>* first_set,
- ZoneList<CharacterRange>* second_set,
- ZoneList<CharacterRange>* first_set_only_out,
- ZoneList<CharacterRange>* second_set_only_out,
- ZoneList<CharacterRange>* both_sets_out);
// Negate the contents of a character range in canonical form.
static void Negate(ZoneList<CharacterRange>* src,
ZoneList<CharacterRange>* dst);
@@ -421,90 +360,6 @@ class DispatchTable : public ZoneObject {
};
-// Improve the speed that we scan for an initial point where a non-anchored
-// regexp can match by using a Boyer-Moore-like table. This is done by
-// identifying non-greedy non-capturing loops in the nodes that eat any
-// character one at a time. For example in the middle of the regexp
-// /foo[\s\S]*?bar/ we find such a loop. There is also such a loop implicitly
-// inserted at the start of any non-anchored regexp.
-//
-// When we have found such a loop we look ahead in the nodes to find the set of
-// characters that can come at given distances. For example for the regexp
-// /.?foo/ we know that there are at least 3 characters ahead of us, and the
-// sets of characters that can occur are [any, [f, o], [o]]. We find a range in
-// the lookahead info where the set of characters is reasonably constrained. In
-// our example this is from index 1 to 2 (0 is not constrained). We can now
-// look 3 characters ahead and if we don't find one of [f, o] (the union of
-// [f, o] and [o]) then we can skip forwards by the range size (in this case 2).
-//
-// For Unicode input strings we do the same, but modulo 128.
-//
-// We also look at the first string fed to the regexp and use that to get a hint
-// of the character frequencies in the inputs. This affects the assessment of
-// whether the set of characters is 'reasonably constrained'.
-//
-// We also have another lookahead mechanism (called quick check in the code),
-// which uses a wide load of multiple characters followed by a mask and compare
-// to determine whether a match is possible at this point.
-class BoyerMooreLookahead {
- public:
- BoyerMooreLookahead(int length, int map_length, RegExpCompiler* compiler);
-
- int length() { return length_; }
- int max_char() { return max_char_; }
- RegExpCompiler* compiler() { return compiler_; }
-
- static const int kTooManyCharacters = 32;
-
- int Count(int map_number) {
- ZoneList<bool>* map = bitmaps_->at(map_number);
- if (map == NULL) return map_length_;
- int count = 0;
- for (int i = 0; i < map_length_; i++) {
- if (map->at(i)) count++;
- }
- return count;
- }
-
- void Set(int map_number, int character) {
- if (character > max_char_) return;
- ZoneList<bool>* map = bitmaps_->at(map_number);
- if (map == NULL) return;
- map->at(character & (map_length_ - 1)) = true;
- }
-
- void SetAll(int map_number) {
- bitmaps_->at(map_number) = NULL;
- }
-
- void SetRest(int from_map) {
- for (int i = from_map; i < length_; i++) SetAll(i);
- }
- bool EmitSkipInstructions(RegExpMacroAssembler* masm);
-
- private:
- // This is the value obtained by EatsAtLeast. If we do not have at least this
- // many characters left in the sample string then the match is bound to fail.
- // Therefore it is OK to read a character this far ahead of the current match
- // point.
- int length_;
- // We conservatively consider all character values modulo this length. For
- // ASCII there is no loss of precision, since this has a value of 128.
- int map_length_;
- RegExpCompiler* compiler_;
- // 0x7f for ASCII, 0xffff for UTF-16.
- int max_char_;
- ZoneList<ZoneList<bool>*>* bitmaps_;
-
- int GetSkipTable(int min_lookahead,
- int max_lookahead,
- Handle<ByteArray> boolean_skip_table);
- bool FindWorthwhileInterval(int* from, int* to);
- int FindBestInterval(
- int max_number_of_chars, int old_biggest_points, int* from, int* to);
-};
-
-
#define FOR_EACH_NODE_TYPE(VISIT) \
VISIT(End) \
VISIT(Action) \
@@ -561,7 +416,8 @@ struct NodeInfo {
follows_newline_interest(false),
follows_start_interest(false),
at_end(false),
- visited(false) { }
+ visited(false),
+ replacement_calculated(false) { }
// Returns true if the interests and assumptions of this node
// matches the given one.
@@ -611,25 +467,7 @@ struct NodeInfo {
bool at_end: 1;
bool visited: 1;
-};
-
-
-class SiblingList {
- public:
- SiblingList() : list_(NULL) { }
- int length() {
- return list_ == NULL ? 0 : list_->length();
- }
- void Ensure(RegExpNode* parent) {
- if (list_ == NULL) {
- list_ = new ZoneList<RegExpNode*>(2);
- list_->Add(parent);
- }
- }
- void Add(RegExpNode* node) { list_->Add(node); }
- RegExpNode* Get(int index) { return list_->at(index); }
- private:
- ZoneList<RegExpNode*>* list_;
+ bool replacement_calculated: 1;
};
@@ -685,9 +523,14 @@ class QuickCheckDetails {
};
+extern int kUninitializedRegExpNodePlaceHolder;
+
+
class RegExpNode: public ZoneObject {
public:
- RegExpNode() : first_character_set_(NULL), trace_count_(0) { }
+ RegExpNode() : replacement_(NULL), trace_count_(0) {
+ bm_info_[0] = bm_info_[1] = NULL;
+ }
virtual ~RegExpNode();
virtual void Accept(NodeVisitor* visitor) = 0;
// Generates a goto to this node or actually generates the code at this point.
@@ -731,12 +574,35 @@ class RegExpNode: public ZoneObject {
// Collects information on the possible code units (mod 128) that can match if
// we look forward. This is used for a Boyer-Moore-like string searching
// implementation. TODO(erikcorry): This should share more code with
- // EatsAtLeast, GetQuickCheckDetails and ComputeFirstCharacterSet.
+ // EatsAtLeast, GetQuickCheckDetails.
virtual void FillInBMInfo(
int offset, BoyerMooreLookahead* bm, bool not_at_start) {
UNREACHABLE();
}
+ // If we know that the input is ASCII then there are some nodes that can
+ // never match. This method returns a node that can be substituted for
+ // itself, or NULL if the node can never match.
+ virtual RegExpNode* FilterASCII(int depth) { return this; }
+ // Helper for FilterASCII.
+ RegExpNode* replacement() {
+ ASSERT(info()->replacement_calculated);
+ return replacement_;
+ }
+ RegExpNode* set_replacement(RegExpNode* replacement) {
+ info()->replacement_calculated = true;
+ replacement_ = replacement;
+ return replacement; // For convenience.
+ }
+
+ // We want to avoid recalculating the lookahead info, so we store it on the
+ // node. Only info that is for this node is stored. We can tell that the
+ // info is for this node when offset == 0, so the information is calculated
+ // relative to this node.
+ void SaveBMInfo(BoyerMooreLookahead* bm, bool not_at_start, int offset) {
+ if (offset == 0) set_bm_info(not_at_start, bm);
+ }
+
Label* label() { return &label_; }
// If non-generic code is generated for a node (i.e. the node is not at the
// start of the trace) then it cannot be reused. This variable sets a limit
@@ -747,72 +613,31 @@ class RegExpNode: public ZoneObject {
NodeInfo* info() { return &info_; }
- void AddSibling(RegExpNode* node) { siblings_.Add(node); }
-
- // Static version of EnsureSibling that expresses the fact that the
- // result has the same type as the input.
- template <class C>
- static C* EnsureSibling(C* node, NodeInfo* info, bool* cloned) {
- return static_cast<C*>(node->EnsureSibling(info, cloned));
- }
-
- SiblingList* siblings() { return &siblings_; }
- void set_siblings(SiblingList* other) { siblings_ = *other; }
-
- // Return the set of possible next characters recognized by the regexp
- // (or a safe subset, potentially the set of all characters).
- ZoneList<CharacterRange>* FirstCharacterSet();
-
- // Compute (if possible within the budget of traversed nodes) the
- // possible first characters of the input matched by this node and
- // its continuation. Returns the remaining budget after the computation.
- // If the budget is spent, the result is negative, and the cached
- // first_character_set_ value isn't set.
- virtual int ComputeFirstCharacterSet(int budget);
-
- // Get and set the cached first character set value.
- ZoneList<CharacterRange>* first_character_set() {
- return first_character_set_;
- }
- void set_first_character_set(ZoneList<CharacterRange>* character_set) {
- first_character_set_ = character_set;
+ BoyerMooreLookahead* bm_info(bool not_at_start) {
+ return bm_info_[not_at_start ? 1 : 0];
}
protected:
enum LimitResult { DONE, CONTINUE };
- static const int kComputeFirstCharacterSetFail = -1;
+ RegExpNode* replacement_;
LimitResult LimitVersions(RegExpCompiler* compiler, Trace* trace);
- // Returns a sibling of this node whose interests and assumptions
- // match the ones in the given node info. If no sibling exists NULL
- // is returned.
- RegExpNode* TryGetSibling(NodeInfo* info);
-
- // Returns a sibling of this node whose interests match the ones in
- // the given node info. The info must not contain any assertions.
- // If no node exists a new one will be created by cloning the current
- // node. The result will always be an instance of the same concrete
- // class as this node.
- RegExpNode* EnsureSibling(NodeInfo* info, bool* cloned);
-
- // Returns a clone of this node initialized using the copy constructor
- // of its concrete class. Note that the node may have to be pre-
- // processed before it is on a usable state.
- virtual RegExpNode* Clone() = 0;
+ void set_bm_info(bool not_at_start, BoyerMooreLookahead* bm) {
+ bm_info_[not_at_start ? 1 : 0] = bm;
+ }
private:
static const int kFirstCharBudget = 10;
Label label_;
NodeInfo info_;
- SiblingList siblings_;
- ZoneList<CharacterRange>* first_character_set_;
// This variable keeps track of how many times code has been generated for
// this node (in different traces). We don't keep track of where the
// generated code is located unless the code is generated at the start of
// a trace, in which case it is generic and can be reused by flushing the
// deferred operations in the current trace and generating a goto.
int trace_count_;
+ BoyerMooreLookahead* bm_info_[2];
};
@@ -833,8 +658,8 @@ class Interval {
return (from_ <= value) && (value <= to_);
}
bool is_empty() { return from_ == kNone; }
- int from() { return from_; }
- int to() { return to_; }
+ int from() const { return from_; }
+ int to() const { return to_; }
static Interval Empty() { return Interval(); }
static const int kNone = -1;
private:
@@ -849,10 +674,16 @@ class SeqRegExpNode: public RegExpNode {
: on_success_(on_success) { }
RegExpNode* on_success() { return on_success_; }
void set_on_success(RegExpNode* node) { on_success_ = node; }
+ virtual RegExpNode* FilterASCII(int depth);
virtual void FillInBMInfo(
int offset, BoyerMooreLookahead* bm, bool not_at_start) {
on_success_->FillInBMInfo(offset, bm, not_at_start);
+ if (offset == 0) set_bm_info(not_at_start, bm);
}
+
+ protected:
+ RegExpNode* FilterSuccessor(int depth);
+
private:
RegExpNode* on_success_;
};
@@ -904,8 +735,6 @@ class ActionNode: public SeqRegExpNode {
Type type() { return type_; }
// TODO(erikcorry): We should allow some action nodes in greedy loops.
virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; }
- virtual ActionNode* Clone() { return new ActionNode(*this); }
- virtual int ComputeFirstCharacterSet(int budget);
private:
union {
@@ -972,13 +801,8 @@ class TextNode: public SeqRegExpNode {
RegExpCompiler* compiler);
virtual void FillInBMInfo(
int offset, BoyerMooreLookahead* bm, bool not_at_start);
- virtual TextNode* Clone() {
- TextNode* result = new TextNode(*this);
- result->CalculateOffsets();
- return result;
- }
void CalculateOffsets();
- virtual int ComputeFirstCharacterSet(int budget);
+ virtual RegExpNode* FilterASCII(int depth);
private:
enum TextEmitPassType {
@@ -1009,12 +833,7 @@ class AssertionNode: public SeqRegExpNode {
AT_START,
AT_BOUNDARY,
AT_NON_BOUNDARY,
- AFTER_NEWLINE,
- // Types not directly expressible in regexp syntax.
- // Used for modifying a boundary node if its following character is
- // known to be word and/or non-word.
- AFTER_NONWORD_CHARACTER,
- AFTER_WORD_CHARACTER
+ AFTER_NEWLINE
};
static AssertionNode* AtEnd(RegExpNode* on_success) {
return new AssertionNode(AT_END, on_success);
@@ -1042,12 +861,15 @@ class AssertionNode: public SeqRegExpNode {
bool not_at_start);
virtual void FillInBMInfo(
int offset, BoyerMooreLookahead* bm, bool not_at_start);
- virtual int ComputeFirstCharacterSet(int budget);
- virtual AssertionNode* Clone() { return new AssertionNode(*this); }
AssertionNodeType type() { return type_; }
void set_type(AssertionNodeType type) { type_ = type; }
private:
+ void EmitBoundaryCheck(RegExpCompiler* compiler, Trace* trace);
+ enum IfPrevious { kIsNonWord, kIsWord };
+ void BacktrackIfPrevious(RegExpCompiler* compiler,
+ Trace* trace,
+ IfPrevious backtrack_if_previous);
AssertionNode(AssertionNodeType t, RegExpNode* on_success)
: SeqRegExpNode(on_success), type_(t) { }
AssertionNodeType type_;
@@ -1076,13 +898,7 @@ class BackReferenceNode: public SeqRegExpNode {
return;
}
virtual void FillInBMInfo(
- int offset, BoyerMooreLookahead* bm, bool not_at_start) {
- // Working out the set of characters that a backreference can match is too
- // hard, so we just say that any character can match.
- bm->SetRest(offset);
- }
- virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); }
- virtual int ComputeFirstCharacterSet(int budget);
+ int offset, BoyerMooreLookahead* bm, bool not_at_start);
private:
int start_reg_;
@@ -1111,7 +927,7 @@ class EndNode: public RegExpNode {
// Returning 0 from EatsAtLeast should ensure we never get here.
UNREACHABLE();
}
- virtual EndNode* Clone() { return new EndNode(*this); }
+
private:
Action action_;
};
@@ -1198,13 +1014,13 @@ class ChoiceNode: public RegExpNode {
bool not_at_start);
virtual void FillInBMInfo(
int offset, BoyerMooreLookahead* bm, bool not_at_start);
- virtual ChoiceNode* Clone() { return new ChoiceNode(*this); }
bool being_calculated() { return being_calculated_; }
bool not_at_start() { return not_at_start_; }
void set_not_at_start() { not_at_start_ = true; }
void set_being_calculated(bool b) { being_calculated_ = b; }
virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; }
+ virtual RegExpNode* FilterASCII(int depth);
protected:
int GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative);
@@ -1249,6 +1065,7 @@ class NegativeLookaheadChoiceNode: public ChoiceNode {
virtual void FillInBMInfo(
int offset, BoyerMooreLookahead* bm, bool not_at_start) {
alternatives_->at(1).node()->FillInBMInfo(offset, bm, not_at_start);
+ if (offset == 0) set_bm_info(not_at_start, bm);
}
// For a negative lookahead we don't emit the quick check for the
// alternative that is expected to fail. This is because quick check code
@@ -1256,7 +1073,7 @@ class NegativeLookaheadChoiceNode: public ChoiceNode {
// characters, but on a negative lookahead the negative branch did not take
// part in that calculation (EatsAtLeast) so the assumptions don't hold.
virtual bool try_to_emit_quick_check_for_alternative(int i) { return i != 0; }
- virtual int ComputeFirstCharacterSet(int budget);
+ virtual RegExpNode* FilterASCII(int depth);
};
@@ -1279,12 +1096,11 @@ class LoopChoiceNode: public ChoiceNode {
bool not_at_start);
virtual void FillInBMInfo(
int offset, BoyerMooreLookahead* bm, bool not_at_start);
- virtual int ComputeFirstCharacterSet(int budget);
- virtual LoopChoiceNode* Clone() { return new LoopChoiceNode(*this); }
RegExpNode* loop_node() { return loop_node_; }
RegExpNode* continue_node() { return continue_node_; }
bool body_can_be_zero_length() { return body_can_be_zero_length_; }
virtual void Accept(NodeVisitor* visitor);
+ virtual RegExpNode* FilterASCII(int depth);
private:
// AddAlternative is made private for loop nodes because alternatives
@@ -1300,6 +1116,146 @@ class LoopChoiceNode: public ChoiceNode {
};
+// Improve the speed that we scan for an initial point where a non-anchored
+// regexp can match by using a Boyer-Moore-like table. This is done by
+// identifying non-greedy non-capturing loops in the nodes that eat any
+// character one at a time. For example in the middle of the regexp
+// /foo[\s\S]*?bar/ we find such a loop. There is also such a loop implicitly
+// inserted at the start of any non-anchored regexp.
+//
+// When we have found such a loop we look ahead in the nodes to find the set of
+// characters that can come at given distances. For example for the regexp
+// /.?foo/ we know that there are at least 3 characters ahead of us, and the
+// sets of characters that can occur are [any, [f, o], [o]]. We find a range in
+// the lookahead info where the set of characters is reasonably constrained. In
+// our example this is from index 1 to 2 (0 is not constrained). We can now
+// look 3 characters ahead and if we don't find one of [f, o] (the union of
+// [f, o] and [o]) then we can skip forwards by the range size (in this case 2).
+//
+// For Unicode input strings we do the same, but modulo 128.
+//
+// We also look at the first string fed to the regexp and use that to get a hint
+// of the character frequencies in the inputs. This affects the assessment of
+// whether the set of characters is 'reasonably constrained'.
+//
+// We also have another lookahead mechanism (called quick check in the code),
+// which uses a wide load of multiple characters followed by a mask and compare
+// to determine whether a match is possible at this point.
+enum ContainedInLattice {
+ kNotYet = 0,
+ kLatticeIn = 1,
+ kLatticeOut = 2,
+ kLatticeUnknown = 3 // Can also mean both in and out.
+};
+
+
+inline ContainedInLattice Combine(ContainedInLattice a, ContainedInLattice b) {
+ return static_cast<ContainedInLattice>(a | b);
+}
+
+
+ContainedInLattice AddRange(ContainedInLattice a,
+ const int* ranges,
+ int ranges_size,
+ Interval new_range);
+
+
+class BoyerMoorePositionInfo : public ZoneObject {
+ public:
+ BoyerMoorePositionInfo()
+ : map_(new ZoneList<bool>(kMapSize)),
+ map_count_(0),
+ w_(kNotYet),
+ s_(kNotYet),
+ d_(kNotYet),
+ surrogate_(kNotYet) {
+ for (int i = 0; i < kMapSize; i++) {
+ map_->Add(false);
+ }
+ }
+
+ bool& at(int i) { return map_->at(i); }
+
+ static const int kMapSize = 128;
+ static const int kMask = kMapSize - 1;
+
+ int map_count() const { return map_count_; }
+
+ void Set(int character);
+ void SetInterval(const Interval& interval);
+ void SetAll();
+ bool is_non_word() { return w_ == kLatticeOut; }
+ bool is_word() { return w_ == kLatticeIn; }
+
+ private:
+ ZoneList<bool>* map_;
+ int map_count_; // Number of set bits in the map.
+ ContainedInLattice w_; // The \w character class.
+ ContainedInLattice s_; // The \s character class.
+ ContainedInLattice d_; // The \d character class.
+ ContainedInLattice surrogate_; // Surrogate UTF-16 code units.
+};
+
+
+class BoyerMooreLookahead : public ZoneObject {
+ public:
+ BoyerMooreLookahead(int length, RegExpCompiler* compiler);
+
+ int length() { return length_; }
+ int max_char() { return max_char_; }
+ RegExpCompiler* compiler() { return compiler_; }
+
+ int Count(int map_number) {
+ return bitmaps_->at(map_number)->map_count();
+ }
+
+ BoyerMoorePositionInfo* at(int i) { return bitmaps_->at(i); }
+
+ void Set(int map_number, int character) {
+ if (character > max_char_) return;
+ BoyerMoorePositionInfo* info = bitmaps_->at(map_number);
+ info->Set(character);
+ }
+
+ void SetInterval(int map_number, const Interval& interval) {
+ if (interval.from() > max_char_) return;
+ BoyerMoorePositionInfo* info = bitmaps_->at(map_number);
+ if (interval.to() > max_char_) {
+ info->SetInterval(Interval(interval.from(), max_char_));
+ } else {
+ info->SetInterval(interval);
+ }
+ }
+
+ void SetAll(int map_number) {
+ bitmaps_->at(map_number)->SetAll();
+ }
+
+ void SetRest(int from_map) {
+ for (int i = from_map; i < length_; i++) SetAll(i);
+ }
+ bool EmitSkipInstructions(RegExpMacroAssembler* masm);
+
+ private:
+ // This is the value obtained by EatsAtLeast. If we do not have at least this
+ // many characters left in the sample string then the match is bound to fail.
+ // Therefore it is OK to read a character this far ahead of the current match
+ // point.
+ int length_;
+ RegExpCompiler* compiler_;
+ // 0x7f for ASCII, 0xffff for UTF-16.
+ int max_char_;
+ ZoneList<BoyerMoorePositionInfo*>* bitmaps_;
+
+ int GetSkipTable(int min_lookahead,
+ int max_lookahead,
+ Handle<ByteArray> boolean_skip_table);
+ bool FindWorthwhileInterval(int* from, int* to);
+ int FindBestInterval(
+ int max_number_of_chars, int old_biggest_points, int* from, int* to);
+};
+
+
// There are many ways to generate code for a node. This class encapsulates
// the current way we should be generating. In other words it encapsulates
// the current state of the code generator. The effect of this is that we
diff --git a/src/3rdparty/v8/src/lazy-instance.h b/src/3rdparty/v8/src/lazy-instance.h
index 4c09b0d..9d68b8c 100644
--- a/src/3rdparty/v8/src/lazy-instance.h
+++ b/src/3rdparty/v8/src/lazy-instance.h
@@ -250,7 +250,7 @@ struct LazyInstance {
template <typename T,
- typename CreateTrait = DefaultConstructTrait<T>,
+ typename CreateTrait = DefaultCreateTrait<T>,
typename InitOnceTrait = SingleThreadInitOnceTrait,
typename DestroyTrait = LeakyInstanceTrait<T> >
struct LazyDynamicInstance {
diff --git a/src/3rdparty/v8/src/list-inl.h b/src/3rdparty/v8/src/list-inl.h
index 7c2c83f..6cf3bad 100644
--- a/src/3rdparty/v8/src/list-inl.h
+++ b/src/3rdparty/v8/src/list-inl.h
@@ -137,6 +137,14 @@ bool List<T, P>::RemoveElement(const T& elm) {
template<typename T, class P>
+void List<T, P>::Allocate(int length) {
+ DeleteData(data_);
+ Initialize(length);
+ length_ = length;
+}
+
+
+template<typename T, class P>
void List<T, P>::Clear() {
DeleteData(data_);
Initialize(0);
@@ -207,20 +215,19 @@ void List<T, P>::Initialize(int capacity) {
}
-template <typename T>
-int SortedListBSearch(
- const List<T>& list, T elem, int (*cmp)(const T* x, const T* y)) {
+template <typename T, typename P>
+int SortedListBSearch(const List<T>& list, P cmp) {
int low = 0;
int high = list.length() - 1;
while (low <= high) {
int mid = (low + high) / 2;
T mid_elem = list[mid];
- if (cmp(&mid_elem, &elem) > 0) {
+ if (cmp(&mid_elem) > 0) {
high = mid - 1;
continue;
}
- if (cmp(&mid_elem, &elem) < 0) {
+ if (cmp(&mid_elem) < 0) {
low = mid + 1;
continue;
}
@@ -231,9 +238,21 @@ int SortedListBSearch(
}
+template<typename T>
+class ElementCmp {
+ public:
+ explicit ElementCmp(T e) : elem_(e) {}
+ int operator()(const T* other) {
+ return PointerValueCompare(other, &elem_);
+ }
+ private:
+ T elem_;
+};
+
+
template <typename T>
int SortedListBSearch(const List<T>& list, T elem) {
- return SortedListBSearch<T>(list, elem, PointerValueCompare<T>);
+ return SortedListBSearch<T, ElementCmp<T> > (list, ElementCmp<T>(elem));
}
diff --git a/src/3rdparty/v8/src/list.h b/src/3rdparty/v8/src/list.h
index adddea4..7350c0d 100644
--- a/src/3rdparty/v8/src/list.h
+++ b/src/3rdparty/v8/src/list.h
@@ -117,6 +117,9 @@ class List {
// pointer type. Returns the removed element.
INLINE(T RemoveLast()) { return Remove(length_ - 1); }
+ // Deletes current list contents and allocates space for 'length' elements.
+ INLINE(void Allocate(int length));
+
// Clears the list by setting the length to zero. Even if T is a
// pointer type, clearing the list doesn't delete the entries.
INLINE(void Clear());
@@ -173,9 +176,11 @@ typedef List<Handle<Code> > CodeHandleList;
// Perform binary search for an element in an already sorted
// list. Returns the index of the element of -1 if it was not found.
-template <typename T>
-int SortedListBSearch(
- const List<T>& list, T elem, int (*cmp)(const T* x, const T* y));
+// |cmp| is a predicate that takes a pointer to an element of the List
+// and returns +1 if it is greater, -1 if it is less than the element
+// being searched.
+template <typename T, class P>
+int SortedListBSearch(const List<T>& list, P cmp);
template <typename T>
int SortedListBSearch(const List<T>& list, T elem);
diff --git a/src/3rdparty/v8/src/lithium-allocator.cc b/src/3rdparty/v8/src/lithium-allocator.cc
index 4396c73..9534f9e 100644
--- a/src/3rdparty/v8/src/lithium-allocator.cc
+++ b/src/3rdparty/v8/src/lithium-allocator.cc
@@ -958,7 +958,7 @@ void LAllocator::ProcessInstructions(HBasicBlock* block, BitVector* live) {
}
}
- if (instr->IsMarkedAsCall() || instr->IsMarkedAsSaveDoubles()) {
+ if (instr->IsMarkedAsCall()) {
for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) {
if (output == NULL || !output->IsDoubleRegister() ||
output->index() != i) {
diff --git a/src/3rdparty/v8/src/liveedit-debugger.js b/src/3rdparty/v8/src/liveedit-debugger.js
index abfb0f6..4463c93 100644
--- a/src/3rdparty/v8/src/liveedit-debugger.js
+++ b/src/3rdparty/v8/src/liveedit-debugger.js
@@ -159,6 +159,11 @@ Debug.LiveEdit = new function() {
preview_description.stack_modified = dropped_functions_number != 0;
+ // Our current implementation requires client to manually issue "step in"
+ // command for correct stack state.
+ preview_description.stack_update_needs_step_in =
+ preview_description.stack_modified;
+
// Start with breakpoints. Convert their line/column positions and
// temporary remove.
var break_points_restorer = TemporaryRemoveBreakPoints(script, change_log);
diff --git a/src/3rdparty/v8/src/liveedit.cc b/src/3rdparty/v8/src/liveedit.cc
index 9c5294a..22b8250 100644
--- a/src/3rdparty/v8/src/liveedit.cc
+++ b/src/3rdparty/v8/src/liveedit.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -30,6 +30,7 @@
#include "liveedit.h"
+#include "code-stubs.h"
#include "compilation-cache.h"
#include "compiler.h"
#include "debug.h"
@@ -1475,26 +1476,36 @@ static const char* DropFrames(Vector<StackFrame*> frames,
// Check the nature of the top frame.
Isolate* isolate = Isolate::Current();
Code* pre_top_frame_code = pre_top_frame->LookupCode();
+ bool frame_has_padding;
if (pre_top_frame_code->is_inline_cache_stub() &&
pre_top_frame_code->ic_state() == DEBUG_BREAK) {
// OK, we can drop inline cache calls.
*mode = Debug::FRAME_DROPPED_IN_IC_CALL;
+ frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
} else if (pre_top_frame_code ==
isolate->debug()->debug_break_slot()) {
// OK, we can drop debug break slot.
*mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL;
+ frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
} else if (pre_top_frame_code ==
isolate->builtins()->builtin(
Builtins::kFrameDropper_LiveEdit)) {
// OK, we can drop our own code.
*mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
+ frame_has_padding = false;
} else if (pre_top_frame_code ==
isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) {
*mode = Debug::FRAME_DROPPED_IN_RETURN_CALL;
+ frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
} else if (pre_top_frame_code->kind() == Code::STUB &&
- pre_top_frame_code->major_key()) {
- // Entry from our unit tests, it's fine, we support this case.
+ pre_top_frame_code->major_key() == CodeStub::CEntry) {
+ // Entry from our unit tests on 'debugger' statement.
+ // It's fine, we support this case.
*mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
+ // We don't have a padding from 'debugger' statement call.
+ // Here the stub is CEntry, it's not debug-only and can't be padded.
+ // If anyone would complain, a proxy padded stub could be added.
+ frame_has_padding = false;
} else {
return "Unknown structure of stack above changing function";
}
@@ -1504,8 +1515,49 @@ static const char* DropFrames(Vector<StackFrame*> frames,
- Debug::kFrameDropperFrameSize * kPointerSize // Size of the new frame.
+ kPointerSize; // Bigger address end is exclusive.
+ Address* top_frame_pc_address = top_frame->pc_address();
+
+ // top_frame may be damaged below this point. Do not used it.
+ ASSERT(!(top_frame = NULL));
+
if (unused_stack_top > unused_stack_bottom) {
- return "Not enough space for frame dropper frame";
+ if (frame_has_padding) {
+ int shortage_bytes =
+ static_cast<int>(unused_stack_top - unused_stack_bottom);
+
+ Address padding_start = pre_top_frame->fp() -
+ Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize;
+
+ Address padding_pointer = padding_start;
+ Smi* padding_object =
+ Smi::FromInt(Debug::FramePaddingLayout::kPaddingValue);
+ while (Memory::Object_at(padding_pointer) == padding_object) {
+ padding_pointer -= kPointerSize;
+ }
+ int padding_counter =
+ Smi::cast(Memory::Object_at(padding_pointer))->value();
+ if (padding_counter * kPointerSize < shortage_bytes) {
+ return "Not enough space for frame dropper frame "
+ "(even with padding frame)";
+ }
+ Memory::Object_at(padding_pointer) =
+ Smi::FromInt(padding_counter - shortage_bytes / kPointerSize);
+
+ StackFrame* pre_pre_frame = frames[top_frame_index - 2];
+
+ memmove(padding_start + kPointerSize - shortage_bytes,
+ padding_start + kPointerSize,
+ Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize);
+
+ pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes);
+ pre_pre_frame->SetCallerFp(pre_top_frame->fp());
+ unused_stack_top -= shortage_bytes;
+
+ STATIC_ASSERT(sizeof(Address) == kPointerSize);
+ top_frame_pc_address -= shortage_bytes / kPointerSize;
+ } else {
+ return "Not enough space for frame dropper frame";
+ }
}
// Committing now. After this point we should return only NULL value.
@@ -1515,7 +1567,7 @@ static const char* DropFrames(Vector<StackFrame*> frames,
ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame));
Handle<Code> code = Isolate::Current()->builtins()->FrameDropper_LiveEdit();
- top_frame->set_pc(code->entry());
+ *top_frame_pc_address = code->entry();
pre_top_frame->SetCallerFp(bottom_js_frame->fp());
*restarter_frame_function_pointer =
diff --git a/src/3rdparty/v8/src/macros.py b/src/3rdparty/v8/src/macros.py
index 93287ae..08fa82e 100644
--- a/src/3rdparty/v8/src/macros.py
+++ b/src/3rdparty/v8/src/macros.py
@@ -196,6 +196,7 @@ macro SET_UTC_DATE_VALUE(arg, value) = (%DateSetValue(arg, value, 1));
macro SET_LOCAL_DATE_VALUE(arg, value) = (%DateSetValue(arg, value, 0));
# Last input and last subject of regexp matches.
+const LAST_SUBJECT_INDEX = 1;
macro LAST_SUBJECT(array) = ((array)[1]);
macro LAST_INPUT(array) = ((array)[2]);
@@ -204,6 +205,15 @@ macro CAPTURE(index) = (3 + (index));
const CAPTURE0 = 3;
const CAPTURE1 = 4;
+# For the regexp capture override array. This has the same
+# format as the arguments to a function called from
+# String.prototype.replace.
+macro OVERRIDE_MATCH(override) = ((override)[0]);
+macro OVERRIDE_POS(override) = ((override)[(override).length - 2]);
+macro OVERRIDE_SUBJECT(override) = ((override)[(override).length - 1]);
+# 1-based so index of 1 returns the first capture
+macro OVERRIDE_CAPTURE(override, index) = ((override)[(index)]);
+
# PropertyDescriptor return value indices - must match
# PropertyDescriptorIndices in runtime.cc.
const IS_ACCESSOR_INDEX = 0;
diff --git a/src/3rdparty/v8/src/mark-compact-inl.h b/src/3rdparty/v8/src/mark-compact-inl.h
index 43f6b89..2f7e31f 100644
--- a/src/3rdparty/v8/src/mark-compact-inl.h
+++ b/src/3rdparty/v8/src/mark-compact-inl.h
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -52,6 +52,15 @@ void MarkCompactCollector::SetFlags(int flags) {
}
+bool MarkCompactCollector::MarkObjectAndPush(HeapObject* obj) {
+ if (MarkObjectWithoutPush(obj)) {
+ marking_deque_.PushBlack(obj);
+ return true;
+ }
+ return false;
+}
+
+
void MarkCompactCollector::MarkObject(HeapObject* obj, MarkBit mark_bit) {
ASSERT(Marking::MarkBitFrom(obj) == mark_bit);
if (!mark_bit.Get()) {
@@ -62,16 +71,13 @@ void MarkCompactCollector::MarkObject(HeapObject* obj, MarkBit mark_bit) {
}
-bool MarkCompactCollector::MarkObjectWithoutPush(HeapObject* object) {
- MarkBit mark = Marking::MarkBitFrom(object);
- bool old_mark = mark.Get();
- if (!old_mark) SetMark(object, mark);
- return old_mark;
-}
-
-
-void MarkCompactCollector::MarkObjectAndPush(HeapObject* object) {
- if (!MarkObjectWithoutPush(object)) marking_deque_.PushBlack(object);
+bool MarkCompactCollector::MarkObjectWithoutPush(HeapObject* obj) {
+ MarkBit mark_bit = Marking::MarkBitFrom(obj);
+ if (!mark_bit.Get()) {
+ SetMark(obj, mark_bit);
+ return true;
+ }
+ return false;
}
diff --git a/src/3rdparty/v8/src/mark-compact.cc b/src/3rdparty/v8/src/mark-compact.cc
index 866d359..c455564 100644
--- a/src/3rdparty/v8/src/mark-compact.cc
+++ b/src/3rdparty/v8/src/mark-compact.cc
@@ -64,13 +64,13 @@ MarkCompactCollector::MarkCompactCollector() : // NOLINT
abort_incremental_marking_(false),
compacting_(false),
was_marked_incrementally_(false),
- collect_maps_(FLAG_collect_maps),
flush_monomorphic_ics_(false),
tracer_(NULL),
migration_slots_buffer_(NULL),
heap_(NULL),
code_flusher_(NULL),
- encountered_weak_maps_(NULL) { }
+ encountered_weak_maps_(NULL),
+ marker_(this, this) { }
#ifdef DEBUG
@@ -282,7 +282,7 @@ void MarkCompactCollector::CollectGarbage() {
MarkLiveObjects();
ASSERT(heap_->incremental_marking()->IsStopped());
- if (collect_maps_) ClearNonLiveTransitions();
+ if (FLAG_collect_maps) ClearNonLiveTransitions();
ClearWeakMaps();
@@ -294,9 +294,7 @@ void MarkCompactCollector::CollectGarbage() {
SweepSpaces();
- if (!collect_maps_) ReattachInitialMaps();
-
- heap_->isolate()->inner_pointer_to_code_cache()->Flush();
+ if (!FLAG_collect_maps) ReattachInitialMaps();
Finish();
@@ -337,6 +335,7 @@ void MarkCompactCollector::VerifyMarkbitsAreClean() {
for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
MarkBit mark_bit = Marking::MarkBitFrom(obj);
ASSERT(Marking::IsWhite(mark_bit));
+ ASSERT_EQ(0, Page::FromAddress(obj->address())->LiveBytes());
}
}
#endif
@@ -373,6 +372,7 @@ void MarkCompactCollector::ClearMarkbits() {
MarkBit mark_bit = Marking::MarkBitFrom(obj);
mark_bit.Clear();
mark_bit.Next().Clear();
+ Page::FromAddress(obj->address())->ResetLiveBytes();
}
}
@@ -658,11 +658,6 @@ void MarkCompactCollector::AbortCompaction() {
void MarkCompactCollector::Prepare(GCTracer* tracer) {
was_marked_incrementally_ = heap()->incremental_marking()->IsMarking();
- // Disable collection of maps if incremental marking is enabled.
- // Map collection algorithm relies on a special map transition tree traversal
- // order which is not implemented for incremental marking.
- collect_maps_ = FLAG_collect_maps && !was_marked_incrementally_;
-
// Monomorphic ICs are preserved when possible, but need to be flushed
// when they might be keeping a Context alive, or when the heap is about
// to be serialized.
@@ -680,7 +675,6 @@ void MarkCompactCollector::Prepare(GCTracer* tracer) {
ASSERT(!FLAG_never_compact || !FLAG_always_compact);
- if (collect_maps_) CreateBackPointers();
#ifdef ENABLE_GDB_JIT_INTERFACE
if (FLAG_gdbjit) {
// If GDBJIT interface is active disable compaction.
@@ -1150,9 +1144,10 @@ class StaticMarkingVisitor : public StaticVisitorBase {
JSWeakMap* weak_map = reinterpret_cast<JSWeakMap*>(object);
// Enqueue weak map in linked list of encountered weak maps.
- ASSERT(weak_map->next() == Smi::FromInt(0));
- weak_map->set_next(collector->encountered_weak_maps());
- collector->set_encountered_weak_maps(weak_map);
+ if (weak_map->next() == Smi::FromInt(0)) {
+ weak_map->set_next(collector->encountered_weak_maps());
+ collector->set_encountered_weak_maps(weak_map);
+ }
// Skip visiting the backing hash table containing the mappings.
int object_size = JSWeakMap::BodyDescriptor::SizeOf(map, object);
@@ -1168,9 +1163,15 @@ class StaticMarkingVisitor : public StaticVisitorBase {
object_size);
// Mark the backing hash table without pushing it on the marking stack.
- ObjectHashTable* table = ObjectHashTable::cast(weak_map->table());
- ASSERT(!MarkCompactCollector::IsMarked(table));
- collector->SetMark(table, Marking::MarkBitFrom(table));
+ Object* table_object = weak_map->table();
+ if (!table_object->IsHashTable()) return;
+ ObjectHashTable* table = ObjectHashTable::cast(table_object);
+ Object** table_slot =
+ HeapObject::RawField(weak_map, JSWeakMap::kTableOffset);
+ MarkBit table_mark = Marking::MarkBitFrom(table);
+ collector->RecordSlot(table_slot, table_slot, table);
+ if (!table_mark.Get()) collector->SetMark(table, table_mark);
+ // Recording the map slot can be skipped, because maps are not compacted.
collector->MarkObject(table->map(), Marking::MarkBitFrom(table->map()));
ASSERT(MarkCompactCollector::IsMarked(table->map()));
}
@@ -1179,16 +1180,7 @@ class StaticMarkingVisitor : public StaticVisitorBase {
Heap* heap = map->GetHeap();
Code* code = reinterpret_cast<Code*>(object);
if (FLAG_cleanup_code_caches_at_gc) {
- Object* raw_info = code->type_feedback_info();
- if (raw_info->IsTypeFeedbackInfo()) {
- TypeFeedbackCells* type_feedback_cells =
- TypeFeedbackInfo::cast(raw_info)->type_feedback_cells();
- for (int i = 0; i < type_feedback_cells->CellCount(); i++) {
- ASSERT(type_feedback_cells->AstId(i)->IsSmi());
- JSGlobalPropertyCell* cell = type_feedback_cells->Cell(i);
- cell->set_value(TypeFeedbackCells::RawUninitializedSentinel(heap));
- }
- }
+ code->ClearTypeFeedbackCells(heap);
}
code->CodeIterateBody<StaticMarkingVisitor>(heap);
}
@@ -1390,6 +1382,12 @@ class StaticMarkingVisitor : public StaticVisitorBase {
static void VisitSharedFunctionInfoAndFlushCode(Map* map,
HeapObject* object) {
+ Heap* heap = map->GetHeap();
+ SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(object);
+ if (shared->ic_age() != heap->global_ic_age()) {
+ shared->ResetForNewContext(heap->global_ic_age());
+ }
+
MarkCompactCollector* collector = map->GetHeap()->mark_compact_collector();
if (!collector->is_code_flushing_enabled()) {
VisitSharedFunctionInfoGeneric(map, object);
@@ -1406,10 +1404,6 @@ class StaticMarkingVisitor : public StaticVisitorBase {
if (shared->IsInobjectSlackTrackingInProgress()) shared->DetachInitialMap();
- if (shared->ic_age() != heap->global_ic_age()) {
- shared->ResetForNewContext(heap->global_ic_age());
- }
-
if (!known_flush_code_candidate) {
known_flush_code_candidate = IsFlushable(heap, shared);
if (known_flush_code_candidate) {
@@ -1523,12 +1517,6 @@ class StaticMarkingVisitor : public StaticVisitorBase {
JSFunction::kCodeEntryOffset + kPointerSize),
HeapObject::RawField(object,
JSFunction::kNonWeakFieldsEndOffset));
-
- // Don't visit the next function list field as it is a weak reference.
- Object** next_function =
- HeapObject::RawField(object, JSFunction::kNextFunctionLinkOffset);
- heap->mark_compact_collector()->RecordSlot(
- next_function, next_function, *next_function);
}
static inline void VisitJSRegExpFields(Map* map,
@@ -1763,9 +1751,8 @@ class SymbolTableCleaner : public ObjectVisitor {
// Since no objects have yet been moved we can safely access the map of
// the object.
- if (o->IsExternalString() ||
- (o->IsHeapObject() && HeapObject::cast(o)->map()->has_external_resource())) {
- heap_->FinalizeExternalString(HeapObject::cast(*p));
+ if (o->IsExternalString()) {
+ heap_->FinalizeExternalString(String::cast(*p));
}
// Set the entry to the_hole_value (as deleted).
*p = heap_->the_hole_value();
@@ -1806,11 +1793,11 @@ void MarkCompactCollector::ProcessNewlyMarkedObject(HeapObject* object) {
heap_->ClearCacheOnMap(map);
// When map collection is enabled we have to mark through map's transitions
- // in a special way to make transition links weak.
- // Only maps for subclasses of JSReceiver can have transitions.
+ // in a special way to make transition links weak. Only maps for subclasses
+ // of JSReceiver can have transitions.
STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
- if (collect_maps_ && map->instance_type() >= FIRST_JS_RECEIVER_TYPE) {
- MarkMapContents(map);
+ if (FLAG_collect_maps && map->instance_type() >= FIRST_JS_RECEIVER_TYPE) {
+ marker_.MarkMapContents(map);
} else {
marking_deque_.PushBlack(map);
}
@@ -1820,79 +1807,86 @@ void MarkCompactCollector::ProcessNewlyMarkedObject(HeapObject* object) {
}
-void MarkCompactCollector::MarkMapContents(Map* map) {
+// Force instantiation of template instances.
+template void Marker<IncrementalMarking>::MarkMapContents(Map* map);
+template void Marker<MarkCompactCollector>::MarkMapContents(Map* map);
+
+
+template <class T>
+void Marker<T>::MarkMapContents(Map* map) {
// Mark prototype transitions array but don't push it into marking stack.
// This will make references from it weak. We will clean dead prototype
// transitions in ClearNonLiveTransitions.
- FixedArray* prototype_transitions = map->prototype_transitions();
- MarkBit mark = Marking::MarkBitFrom(prototype_transitions);
- if (!mark.Get()) {
- mark.Set();
- MemoryChunk::IncrementLiveBytesFromGC(prototype_transitions->address(),
- prototype_transitions->Size());
+ Object** proto_trans_slot =
+ HeapObject::RawField(map, Map::kPrototypeTransitionsOrBackPointerOffset);
+ HeapObject* prototype_transitions = HeapObject::cast(*proto_trans_slot);
+ if (prototype_transitions->IsFixedArray()) {
+ mark_compact_collector()->RecordSlot(proto_trans_slot,
+ proto_trans_slot,
+ prototype_transitions);
+ MarkBit mark = Marking::MarkBitFrom(prototype_transitions);
+ if (!mark.Get()) {
+ mark.Set();
+ MemoryChunk::IncrementLiveBytesFromGC(prototype_transitions->address(),
+ prototype_transitions->Size());
+ }
}
- Object** raw_descriptor_array_slot =
+ // Make sure that the back pointer stored either in the map itself or inside
+ // its prototype transitions array is marked. Treat pointers in the descriptor
+ // array as weak and also mark that array to prevent visiting it later.
+ base_marker()->MarkObjectAndPush(HeapObject::cast(map->GetBackPointer()));
+
+ Object** descriptor_array_slot =
HeapObject::RawField(map, Map::kInstanceDescriptorsOrBitField3Offset);
- Object* raw_descriptor_array = *raw_descriptor_array_slot;
- if (!raw_descriptor_array->IsSmi()) {
- MarkDescriptorArray(
- reinterpret_cast<DescriptorArray*>(raw_descriptor_array));
+ Object* descriptor_array = *descriptor_array_slot;
+ if (!descriptor_array->IsSmi()) {
+ MarkDescriptorArray(reinterpret_cast<DescriptorArray*>(descriptor_array));
+ }
+
+ // Mark the Object* fields of the Map. Since the descriptor array has been
+ // marked already, it is fine that one of these fields contains a pointer
+ // to it. But make sure to skip back pointer and prototype transitions.
+ STATIC_ASSERT(Map::kPointerFieldsEndOffset ==
+ Map::kPrototypeTransitionsOrBackPointerOffset + kPointerSize);
+ Object** start_slot = HeapObject::RawField(
+ map, Map::kPointerFieldsBeginOffset);
+ Object** end_slot = HeapObject::RawField(
+ map, Map::kPrototypeTransitionsOrBackPointerOffset);
+ for (Object** slot = start_slot; slot < end_slot; slot++) {
+ Object* obj = *slot;
+ if (!obj->NonFailureIsHeapObject()) continue;
+ mark_compact_collector()->RecordSlot(start_slot, slot, obj);
+ base_marker()->MarkObjectAndPush(reinterpret_cast<HeapObject*>(obj));
}
-
- // Mark the Object* fields of the Map.
- // Since the descriptor array has been marked already, it is fine
- // that one of these fields contains a pointer to it.
- Object** start_slot = HeapObject::RawField(map,
- Map::kPointerFieldsBeginOffset);
-
- Object** end_slot = HeapObject::RawField(map, Map::kPointerFieldsEndOffset);
-
- StaticMarkingVisitor::VisitPointers(map->GetHeap(), start_slot, end_slot);
-}
-
-
-void MarkCompactCollector::MarkAccessorPairSlot(HeapObject* accessors,
- int offset) {
- Object** slot = HeapObject::RawField(accessors, offset);
- HeapObject* accessor = HeapObject::cast(*slot);
- if (accessor->IsMap()) return;
- RecordSlot(slot, slot, accessor);
- MarkObjectAndPush(accessor);
}
-void MarkCompactCollector::MarkDescriptorArray(
- DescriptorArray* descriptors) {
- MarkBit descriptors_mark = Marking::MarkBitFrom(descriptors);
- if (descriptors_mark.Get()) return;
+template <class T>
+void Marker<T>::MarkDescriptorArray(DescriptorArray* descriptors) {
// Empty descriptor array is marked as a root before any maps are marked.
- ASSERT(descriptors != heap()->empty_descriptor_array());
- SetMark(descriptors, descriptors_mark);
+ ASSERT(descriptors != descriptors->GetHeap()->empty_descriptor_array());
- FixedArray* contents = reinterpret_cast<FixedArray*>(
+ // The DescriptorArray contains a pointer to its contents array, but the
+ // contents array will be marked black and hence not be visited again.
+ if (!base_marker()->MarkObjectAndPush(descriptors)) return;
+ FixedArray* contents = FixedArray::cast(
descriptors->get(DescriptorArray::kContentArrayIndex));
- ASSERT(contents->IsHeapObject());
- ASSERT(!IsMarked(contents));
- ASSERT(contents->IsFixedArray());
ASSERT(contents->length() >= 2);
- MarkBit contents_mark = Marking::MarkBitFrom(contents);
- SetMark(contents, contents_mark);
- // Contents contains (value, details) pairs. If the details say that the type
- // of descriptor is MAP_TRANSITION, CONSTANT_TRANSITION,
- // EXTERNAL_ARRAY_TRANSITION or NULL_DESCRIPTOR, we don't mark the value as
- // live. Only for MAP_TRANSITION, EXTERNAL_ARRAY_TRANSITION and
- // CONSTANT_TRANSITION is the value an Object* (a Map*).
+ ASSERT(Marking::IsWhite(Marking::MarkBitFrom(contents)));
+ base_marker()->MarkObjectWithoutPush(contents);
+
+ // Contents contains (value, details) pairs. If the descriptor contains a
+ // transition (value is a Map), we don't mark the value as live. It might
+ // be set to the NULL_DESCRIPTOR in ClearNonLiveTransitions later.
for (int i = 0; i < contents->length(); i += 2) {
- // If the pair (value, details) at index i, i+1 is not
- // a transition or null descriptor, mark the value.
PropertyDetails details(Smi::cast(contents->get(i + 1)));
Object** slot = contents->data_start() + i;
if (!(*slot)->IsHeapObject()) continue;
HeapObject* value = HeapObject::cast(*slot);
- RecordSlot(slot, slot, *slot);
+ mark_compact_collector()->RecordSlot(slot, slot, *slot);
switch (details.type()) {
case NORMAL:
@@ -1900,21 +1894,22 @@ void MarkCompactCollector::MarkDescriptorArray(
case CONSTANT_FUNCTION:
case HANDLER:
case INTERCEPTOR:
- MarkObjectAndPush(value);
+ base_marker()->MarkObjectAndPush(value);
break;
case CALLBACKS:
if (!value->IsAccessorPair()) {
- MarkObjectAndPush(value);
- } else if (!MarkObjectWithoutPush(value)) {
- MarkAccessorPairSlot(value, AccessorPair::kGetterOffset);
- MarkAccessorPairSlot(value, AccessorPair::kSetterOffset);
+ base_marker()->MarkObjectAndPush(value);
+ } else if (base_marker()->MarkObjectWithoutPush(value)) {
+ AccessorPair* accessors = AccessorPair::cast(value);
+ MarkAccessorPairSlot(accessors, AccessorPair::kGetterOffset);
+ MarkAccessorPairSlot(accessors, AccessorPair::kSetterOffset);
}
break;
case ELEMENTS_TRANSITION:
// For maps with multiple elements transitions, the transition maps are
// stored in a FixedArray. Keep the fixed array alive but not the maps
// that it refers to.
- if (value->IsFixedArray()) MarkObjectWithoutPush(value);
+ if (value->IsFixedArray()) base_marker()->MarkObjectWithoutPush(value);
break;
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
@@ -1922,26 +1917,16 @@ void MarkCompactCollector::MarkDescriptorArray(
break;
}
}
- // The DescriptorArray descriptors contains a pointer to its contents array,
- // but the contents array is already marked.
- marking_deque_.PushBlack(descriptors);
}
-void MarkCompactCollector::CreateBackPointers() {
- HeapObjectIterator iterator(heap()->map_space());
- for (HeapObject* next_object = iterator.Next();
- next_object != NULL; next_object = iterator.Next()) {
- if (next_object->IsMap()) { // Could also be FreeSpace object on free list.
- Map* map = Map::cast(next_object);
- STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
- if (map->instance_type() >= FIRST_JS_RECEIVER_TYPE) {
- map->CreateBackPointers();
- } else {
- ASSERT(map->instance_descriptors() == heap()->empty_descriptor_array());
- }
- }
- }
+template <class T>
+void Marker<T>::MarkAccessorPairSlot(AccessorPair* accessors, int offset) {
+ Object** slot = HeapObject::RawField(accessors, offset);
+ HeapObject* accessor = HeapObject::cast(*slot);
+ if (accessor->IsMap()) return;
+ mark_compact_collector()->RecordSlot(slot, slot, accessor);
+ base_marker()->MarkObjectAndPush(accessor);
}
@@ -1975,6 +1960,7 @@ static inline int MarkWordToObjectStarts(uint32_t mark_bits, int* starts);
static void DiscoverGreyObjectsOnPage(MarkingDeque* marking_deque, Page* p) {
+ ASSERT(!marking_deque->IsFull());
ASSERT(strcmp(Marking::kWhiteBitPattern, "00") == 0);
ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0);
ASSERT(strcmp(Marking::kGreyBitPattern, "11") == 0);
@@ -2467,15 +2453,8 @@ void MarkCompactCollector::ReattachInitialMaps() {
void MarkCompactCollector::ClearNonLiveTransitions() {
HeapObjectIterator map_iterator(heap()->map_space());
// Iterate over the map space, setting map transitions that go from
- // a marked map to an unmarked map to null transitions. At the same time,
- // set all the prototype fields of maps back to their original value,
- // dropping the back pointers temporarily stored in the prototype field.
- // Setting the prototype field requires following the linked list of
- // back pointers, reversing them all at once. This allows us to find
- // those maps with map transitions that need to be nulled, and only
- // scan the descriptor arrays of those maps, not all maps.
- // All of these actions are carried out only on maps of JSObjects
- // and related subtypes.
+ // a marked map to an unmarked map to null transitions. This action
+ // is carried out only on maps of JSObjects and related subtypes.
for (HeapObject* obj = map_iterator.Next();
obj != NULL; obj = map_iterator.Next()) {
Map* map = reinterpret_cast<Map*>(obj);
@@ -2551,36 +2530,16 @@ void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) {
void MarkCompactCollector::ClearNonLiveMapTransitions(Map* map,
MarkBit map_mark) {
- // Follow the chain of back pointers to find the prototype.
- Object* real_prototype = map;
- while (real_prototype->IsMap()) {
- real_prototype = Map::cast(real_prototype)->prototype();
- ASSERT(real_prototype->IsHeapObject());
- }
+ Object* potential_parent = map->GetBackPointer();
+ if (!potential_parent->IsMap()) return;
+ Map* parent = Map::cast(potential_parent);
- // Follow back pointers, setting them to prototype, clearing map transitions
- // when necessary.
- Map* current = map;
+ // Follow back pointer, check whether we are dealing with a map transition
+ // from a live map to a dead path and in case clear transitions of parent.
bool current_is_alive = map_mark.Get();
- bool on_dead_path = !current_is_alive;
- while (current->IsMap()) {
- Object* next = current->prototype();
- // There should never be a dead map above a live map.
- ASSERT(on_dead_path || current_is_alive);
-
- // A live map above a dead map indicates a dead transition. This test will
- // always be false on the first iteration.
- if (on_dead_path && current_is_alive) {
- on_dead_path = false;
- current->ClearNonLiveTransitions(heap(), real_prototype);
- }
-
- Object** slot = HeapObject::RawField(current, Map::kPrototypeOffset);
- *slot = real_prototype;
- if (current_is_alive) RecordSlot(slot, slot, real_prototype);
-
- current = reinterpret_cast<Map*>(next);
- current_is_alive = Marking::MarkBitFrom(current).Get();
+ bool parent_is_alive = Marking::MarkBitFrom(parent).Get();
+ if (!current_is_alive && parent_is_alive) {
+ parent->ClearNonLiveTransitions(heap());
}
}
@@ -2591,14 +2550,17 @@ void MarkCompactCollector::ProcessWeakMaps() {
ASSERT(MarkCompactCollector::IsMarked(HeapObject::cast(weak_map_obj)));
JSWeakMap* weak_map = reinterpret_cast<JSWeakMap*>(weak_map_obj);
ObjectHashTable* table = ObjectHashTable::cast(weak_map->table());
+ Object** anchor = reinterpret_cast<Object**>(table->address());
for (int i = 0; i < table->Capacity(); i++) {
if (MarkCompactCollector::IsMarked(HeapObject::cast(table->KeyAt(i)))) {
- Object* value = table->get(table->EntryToValueIndex(i));
- StaticMarkingVisitor::VisitPointer(heap(), &value);
- table->set_unchecked(heap(),
- table->EntryToValueIndex(i),
- value,
- UPDATE_WRITE_BARRIER);
+ Object** key_slot =
+ HeapObject::RawField(table, FixedArray::OffsetOfElementAt(
+ ObjectHashTable::EntryToIndex(i)));
+ RecordSlot(anchor, key_slot, *key_slot);
+ Object** value_slot =
+ HeapObject::RawField(table, FixedArray::OffsetOfElementAt(
+ ObjectHashTable::EntryToValueIndex(i)));
+ StaticMarkingVisitor::MarkObjectByPointer(this, anchor, value_slot);
}
}
weak_map_obj = weak_map->next();
@@ -2781,15 +2743,15 @@ static void UpdatePointer(HeapObject** p, HeapObject* object) {
}
-static HeapObject* UpdateReferenceInExternalStringTableEntry(Heap* heap,
- Object** p) {
+static String* UpdateReferenceInExternalStringTableEntry(Heap* heap,
+ Object** p) {
MapWord map_word = HeapObject::cast(*p)->map_word();
if (map_word.IsForwardingAddress()) {
- return HeapObject::cast(map_word.ToForwardingAddress());
+ return String::cast(map_word.ToForwardingAddress());
}
- return HeapObject::cast(*p);
+ return String::cast(*p);
}
@@ -3418,6 +3380,8 @@ void MarkCompactCollector::EvacuateNewSpaceAndCandidates() {
// under it.
ProcessInvalidatedCode(&updating_visitor);
+ heap_->isolate()->inner_pointer_to_code_cache()->Flush();
+
#ifdef DEBUG
if (FLAG_verify_heap) {
VerifyEvacuation(heap_);
@@ -3830,7 +3794,7 @@ void MarkCompactCollector::SweepSpace(PagedSpace* space, SweeperType sweeper) {
bool lazy_sweeping_active = false;
bool unused_page_present = false;
- intptr_t old_space_size = heap()->PromotedSpaceSize();
+ intptr_t old_space_size = heap()->PromotedSpaceSizeOfObjects();
intptr_t space_left =
Min(heap()->OldGenPromotionLimit(old_space_size),
heap()->OldGenAllocationLimit(old_space_size)) - old_space_size;
diff --git a/src/3rdparty/v8/src/mark-compact.h b/src/3rdparty/v8/src/mark-compact.h
index 66ffd19..dbc2869 100644
--- a/src/3rdparty/v8/src/mark-compact.h
+++ b/src/3rdparty/v8/src/mark-compact.h
@@ -42,6 +42,7 @@ typedef bool (*IsAliveFunction)(HeapObject* obj, int* size, int* offset);
// Forward declarations.
class CodeFlusher;
class GCTracer;
+class MarkCompactCollector;
class MarkingVisitor;
class RootMarkingVisitor;
@@ -166,7 +167,6 @@ class Marking {
// ----------------------------------------------------------------------------
// Marking deque for tracing live objects.
-
class MarkingDeque {
public:
MarkingDeque()
@@ -383,6 +383,34 @@ class SlotsBuffer {
};
+// -------------------------------------------------------------------------
+// Marker shared between incremental and non-incremental marking
+template<class BaseMarker> class Marker {
+ public:
+ Marker(BaseMarker* base_marker, MarkCompactCollector* mark_compact_collector)
+ : base_marker_(base_marker),
+ mark_compact_collector_(mark_compact_collector) {}
+
+ // Mark pointers in a Map and its DescriptorArray together, possibly
+ // treating transitions or back pointers weak.
+ void MarkMapContents(Map* map);
+ void MarkDescriptorArray(DescriptorArray* descriptors);
+ void MarkAccessorPairSlot(AccessorPair* accessors, int offset);
+
+ private:
+ BaseMarker* base_marker() {
+ return base_marker_;
+ }
+
+ MarkCompactCollector* mark_compact_collector() {
+ return mark_compact_collector_;
+ }
+
+ BaseMarker* base_marker_;
+ MarkCompactCollector* mark_compact_collector_;
+};
+
+
// Defined in isolate.h.
class ThreadLocalTop;
@@ -544,6 +572,8 @@ class MarkCompactCollector {
void ClearMarkbits();
+ bool is_compacting() const { return compacting_; }
+
private:
MarkCompactCollector();
~MarkCompactCollector();
@@ -582,8 +612,6 @@ class MarkCompactCollector {
bool was_marked_incrementally_;
- bool collect_maps_;
-
bool flush_monomorphic_ics_;
// A pointer to the current stack-allocated GC tracer object during a full
@@ -606,12 +634,13 @@ class MarkCompactCollector {
//
// After: Live objects are marked and non-live objects are unmarked.
-
friend class RootMarkingVisitor;
friend class MarkingVisitor;
friend class StaticMarkingVisitor;
friend class CodeMarkingVisitor;
friend class SharedFunctionInfoMarkingVisitor;
+ friend class Marker<IncrementalMarking>;
+ friend class Marker<MarkCompactCollector>;
// Mark non-optimize code for functions inlined into the given optimized
// code. This will prevent it from being flushed.
@@ -629,29 +658,25 @@ class MarkCompactCollector {
void AfterMarking();
// Marks the object black and pushes it on the marking stack.
- // This is for non-incremental marking.
+ // Returns true if object needed marking and false otherwise.
+ // This is for non-incremental marking only.
+ INLINE(bool MarkObjectAndPush(HeapObject* obj));
+
+ // Marks the object black and pushes it on the marking stack.
+ // This is for non-incremental marking only.
INLINE(void MarkObject(HeapObject* obj, MarkBit mark_bit));
- INLINE(bool MarkObjectWithoutPush(HeapObject* object));
- INLINE(void MarkObjectAndPush(HeapObject* value));
+ // Marks the object black without pushing it on the marking stack.
+ // Returns true if object needed marking and false otherwise.
+ // This is for non-incremental marking only.
+ INLINE(bool MarkObjectWithoutPush(HeapObject* obj));
- // Marks the object black. This is for non-incremental marking.
+ // Marks the object black assuming that it is not yet marked.
+ // This is for non-incremental marking only.
INLINE(void SetMark(HeapObject* obj, MarkBit mark_bit));
void ProcessNewlyMarkedObject(HeapObject* obj);
- // Creates back pointers for all map transitions, stores them in
- // the prototype field. The original prototype pointers are restored
- // in ClearNonLiveTransitions(). All JSObject maps
- // connected by map transitions have the same prototype object, which
- // is why we can use this field temporarily for back pointers.
- void CreateBackPointers();
-
- // Mark a Map and its DescriptorArray together, skipping transitions.
- void MarkMapContents(Map* map);
- void MarkAccessorPairSlot(HeapObject* accessors, int offset);
- void MarkDescriptorArray(DescriptorArray* descriptors);
-
// Mark the heap roots and all objects reachable from them.
void MarkRoots(RootMarkingVisitor* visitor);
@@ -754,6 +779,7 @@ class MarkCompactCollector {
MarkingDeque marking_deque_;
CodeFlusher* code_flusher_;
Object* encountered_weak_maps_;
+ Marker<MarkCompactCollector> marker_;
List<Page*> evacuation_candidates_;
List<Code*> invalidated_code_;
diff --git a/src/3rdparty/v8/src/math.js b/src/3rdparty/v8/src/math.js
index 8e735c4..aee56af 100644
--- a/src/3rdparty/v8/src/math.js
+++ b/src/3rdparty/v8/src/math.js
@@ -30,7 +30,6 @@
// has the added benefit that the code in this file is isolated from
// changes to these properties.
var $floor = MathFloor;
-var $random = MathRandom;
var $abs = MathAbs;
// Instance class name can only be set on functions. That is the only
diff --git a/src/3rdparty/v8/src/messages.js b/src/3rdparty/v8/src/messages.js
index a3adcf8..ab71936 100644
--- a/src/3rdparty/v8/src/messages.js
+++ b/src/3rdparty/v8/src/messages.js
@@ -61,18 +61,21 @@ function FormatString(format, message) {
// To check if something is a native error we need to check the
-// concrete native error types. It is not enough to check "obj
-// instanceof $Error" because user code can replace
-// NativeError.prototype.__proto__. User code cannot replace
-// NativeError.prototype though and therefore this is a safe test.
+// concrete native error types. It is not sufficient to use instanceof
+// since it possible to create an object that has Error.prototype on
+// its prototype chain. This is the case for DOMException for example.
function IsNativeErrorObject(obj) {
- return (obj instanceof $Error) ||
- (obj instanceof $EvalError) ||
- (obj instanceof $RangeError) ||
- (obj instanceof $ReferenceError) ||
- (obj instanceof $SyntaxError) ||
- (obj instanceof $TypeError) ||
- (obj instanceof $URIError);
+ switch (%_ClassOf(obj)) {
+ case 'Error':
+ case 'EvalError':
+ case 'RangeError':
+ case 'ReferenceError':
+ case 'SyntaxError':
+ case 'TypeError':
+ case 'URIError':
+ return true;
+ }
+ return false;
}
@@ -745,7 +748,7 @@ function GetPositionInLine(message) {
function GetStackTraceLine(recv, fun, pos, isGlobal) {
- return FormatSourcePosition(new CallSite(recv, fun, pos));
+ return new CallSite(recv, fun, pos).toString();
}
// ----------------------------------------------------------------------------
@@ -919,6 +922,65 @@ function CallSiteIsConstructor() {
return this.fun === constructor;
}
+function CallSiteToString() {
+ var fileName;
+ var fileLocation = "";
+ if (this.isNative()) {
+ fileLocation = "native";
+ } else if (this.isEval()) {
+ fileName = this.getScriptNameOrSourceURL();
+ if (!fileName) {
+ fileLocation = this.getEvalOrigin();
+ }
+ } else {
+ fileName = this.getFileName();
+ }
+
+ if (fileName) {
+ fileLocation += fileName;
+ var lineNumber = this.getLineNumber();
+ if (lineNumber != null) {
+ fileLocation += ":" + lineNumber;
+ var columnNumber = this.getColumnNumber();
+ if (columnNumber) {
+ fileLocation += ":" + columnNumber;
+ }
+ }
+ }
+
+ if (!fileLocation) {
+ fileLocation = "unknown source";
+ }
+ var line = "";
+ var functionName = this.getFunction().name;
+ var addPrefix = true;
+ var isConstructor = this.isConstructor();
+ var isMethodCall = !(this.isToplevel() || isConstructor);
+ if (isMethodCall) {
+ var methodName = this.getMethodName();
+ line += this.getTypeName() + ".";
+ if (functionName) {
+ line += functionName;
+ if (methodName && (methodName != functionName)) {
+ line += " [as " + methodName + "]";
+ }
+ } else {
+ line += methodName || "<anonymous>";
+ }
+ } else if (isConstructor) {
+ line += "new " + (functionName || "<anonymous>");
+ } else if (functionName) {
+ line += functionName;
+ } else {
+ line += fileLocation;
+ addPrefix = false;
+ }
+ if (addPrefix) {
+ line += " (" + fileLocation + ")";
+ }
+ return line;
+}
+
SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array(
"getThis", CallSiteGetThis,
"getTypeName", CallSiteGetTypeName,
@@ -934,7 +996,8 @@ SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array(
"getColumnNumber", CallSiteGetColumnNumber,
"isNative", CallSiteIsNative,
"getPosition", CallSiteGetPosition,
- "isConstructor", CallSiteIsConstructor
+ "isConstructor", CallSiteIsConstructor,
+ "toString", CallSiteToString
));
@@ -976,65 +1039,6 @@ function FormatEvalOrigin(script) {
return eval_origin;
}
-function FormatSourcePosition(frame) {
- var fileName;
- var fileLocation = "";
- if (frame.isNative()) {
- fileLocation = "native";
- } else if (frame.isEval()) {
- fileName = frame.getScriptNameOrSourceURL();
- if (!fileName) {
- fileLocation = frame.getEvalOrigin();
- }
- } else {
- fileName = frame.getFileName();
- }
-
- if (fileName) {
- fileLocation += fileName;
- var lineNumber = frame.getLineNumber();
- if (lineNumber != null) {
- fileLocation += ":" + lineNumber;
- var columnNumber = frame.getColumnNumber();
- if (columnNumber) {
- fileLocation += ":" + columnNumber;
- }
- }
- }
-
- if (!fileLocation) {
- fileLocation = "unknown source";
- }
- var line = "";
- var functionName = frame.getFunction().name;
- var addPrefix = true;
- var isConstructor = frame.isConstructor();
- var isMethodCall = !(frame.isToplevel() || isConstructor);
- if (isMethodCall) {
- var methodName = frame.getMethodName();
- line += frame.getTypeName() + ".";
- if (functionName) {
- line += functionName;
- if (methodName && (methodName != functionName)) {
- line += " [as " + methodName + "]";
- }
- } else {
- line += methodName || "<anonymous>";
- }
- } else if (isConstructor) {
- line += "new " + (functionName || "<anonymous>");
- } else if (functionName) {
- line += functionName;
- } else {
- line += fileLocation;
- addPrefix = false;
- }
- if (addPrefix) {
- line += " (" + fileLocation + ")";
- }
- return line;
-}
-
function FormatStackTrace(error, frames) {
var lines = [];
try {
@@ -1050,7 +1054,7 @@ function FormatStackTrace(error, frames) {
var frame = frames[i];
var line;
try {
- line = FormatSourcePosition(frame);
+ line = frame.toString();
} catch (e) {
try {
line = "<error: " + e + ">";
@@ -1125,13 +1129,7 @@ function SetUpError() {
}
%FunctionSetInstanceClassName(f, 'Error');
%SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
- // The name property on the prototype of error objects is not
- // specified as being read-one and dont-delete. However, allowing
- // overwriting allows leaks of error objects between script blocks
- // in the same context in a browser setting. Therefore we fix the
- // name.
- %SetProperty(f.prototype, "name", name,
- DONT_ENUM | DONT_DELETE | READ_ONLY) ;
+ %SetProperty(f.prototype, "name", name, DONT_ENUM);
%SetCode(f, function(m) {
if (%_IsConstructCall()) {
// Define all the expected properties directly on the error
@@ -1147,10 +1145,8 @@ function SetUpError() {
return FormatMessage(%NewMessageObject(obj.type, obj.arguments));
});
} else if (!IS_UNDEFINED(m)) {
- %IgnoreAttributesAndSetProperty(this,
- 'message',
- ToString(m),
- DONT_ENUM);
+ %IgnoreAttributesAndSetProperty(
+ this, 'message', ToString(m), DONT_ENUM);
}
captureStackTrace(this, f);
} else {
@@ -1180,16 +1176,41 @@ $Error.captureStackTrace = captureStackTrace;
var visited_errors = new InternalArray();
var cyclic_error_marker = new $Object();
+function GetPropertyWithoutInvokingMonkeyGetters(error, name) {
+ // Climb the prototype chain until we find the holder.
+ while (error && !%HasLocalProperty(error, name)) {
+ error = error.__proto__;
+ }
+ if (error === null) return void 0;
+ if (!IS_OBJECT(error)) return error[name];
+ // If the property is an accessor on one of the predefined errors that can be
+ // generated statically by the compiler, don't touch it. This is to address
+ // http://code.google.com/p/chromium/issues/detail?id=69187
+ var desc = %GetOwnProperty(error, name);
+ if (desc && desc[IS_ACCESSOR_INDEX]) {
+ var isName = name === "name";
+ if (error === $ReferenceError.prototype)
+ return isName ? "ReferenceError" : void 0;
+ if (error === $SyntaxError.prototype)
+ return isName ? "SyntaxError" : void 0;
+ if (error === $TypeError.prototype)
+ return isName ? "TypeError" : void 0;
+ }
+ // Otherwise, read normally.
+ return error[name];
+}
+
function ErrorToStringDetectCycle(error) {
if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
try {
- var type = error.type;
- var name = error.name;
+ var type = GetPropertyWithoutInvokingMonkeyGetters(error, "type");
+ var name = GetPropertyWithoutInvokingMonkeyGetters(error, "name");
name = IS_UNDEFINED(name) ? "Error" : TO_STRING_INLINE(name);
- var message = error.message;
+ var message = GetPropertyWithoutInvokingMonkeyGetters(error, "message");
var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty);
if (type && !hasMessage) {
- message = FormatMessage(%NewMessageObject(type, error.arguments));
+ var args = GetPropertyWithoutInvokingMonkeyGetters(error, "arguments");
+ message = FormatMessage(%NewMessageObject(type, args));
}
message = IS_UNDEFINED(message) ? "" : TO_STRING_INLINE(message);
if (name === "") return message;
diff --git a/src/3rdparty/v8/src/mips/assembler-mips.cc b/src/3rdparty/v8/src/mips/assembler-mips.cc
index fa64e1e..f347fdc 100644
--- a/src/3rdparty/v8/src/mips/assembler-mips.cc
+++ b/src/3rdparty/v8/src/mips/assembler-mips.cc
@@ -2137,6 +2137,15 @@ Address Assembler::target_address_at(Address pc) {
}
+// MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32
+// qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap
+// snapshot generated on ia32, the resulting MIPS sNaN must be quieted.
+// OS::nan_value() returns a qNaN.
+void Assembler::QuietNaN(HeapObject* object) {
+ HeapNumber::cast(object)->set_value(OS::nan_value());
+}
+
+
// On Mips, a target address is stored in a lui/ori instruction pair, each
// of which load 16 bits of the 32-bit address to a register.
// Patching the address must replace both instr, and flush the i-cache.
diff --git a/src/3rdparty/v8/src/mips/assembler-mips.h b/src/3rdparty/v8/src/mips/assembler-mips.h
index 5e67d0c..84714e5 100644
--- a/src/3rdparty/v8/src/mips/assembler-mips.h
+++ b/src/3rdparty/v8/src/mips/assembler-mips.h
@@ -570,6 +570,8 @@ class Assembler : public AssemblerBase {
static void JumpLabelToJumpRegister(Address pc);
+ static void QuietNaN(HeapObject* nan);
+
// This sets the branch destination (which gets loaded at the call address).
// This is for calls and branches within generated code. The serializer
// has already deserialized the lui/ori instructions etc.
diff --git a/src/3rdparty/v8/src/mips/code-stubs-mips.cc b/src/3rdparty/v8/src/mips/code-stubs-mips.cc
index e0ecded..f3dd95b 100644
--- a/src/3rdparty/v8/src/mips/code-stubs-mips.cc
+++ b/src/3rdparty/v8/src/mips/code-stubs-mips.cc
@@ -171,11 +171,6 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
__ sw(a1, MemOperand(v0, Context::SlotOffset(Context::EXTENSION_INDEX)));
__ sw(a2, MemOperand(v0, Context::SlotOffset(Context::GLOBAL_INDEX)));
- // Copy the qml global object from the surrounding context.
- __ lw(a1, MemOperand(cp, Context::SlotOffset(Context::QML_GLOBAL_INDEX)));
- __ sw(a1, MemOperand(v0, Context::SlotOffset(Context::QML_GLOBAL_INDEX)));
-
-
// Initialize the rest of the slots to undefined.
__ LoadRoot(a1, Heap::kUndefinedValueRootIndex);
for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
@@ -238,10 +233,6 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
__ sw(a1, ContextOperand(v0, Context::EXTENSION_INDEX));
__ sw(a2, ContextOperand(v0, Context::GLOBAL_INDEX));
- // Copy the qml global object from the surrounding context.
- __ lw(a1, ContextOperand(cp, Context::QML_GLOBAL_INDEX));
- __ sw(a1, ContextOperand(v0, Context::QML_GLOBAL_INDEX));
-
// Initialize the rest of the slots to the hole value.
__ LoadRoot(a1, Heap::kTheHoleValueRootIndex);
for (int i = 0; i < slots_; i++) {
@@ -1716,46 +1707,6 @@ void CompareStub::Generate(MacroAssembler* masm) {
// NOTICE! This code is only reached after a smi-fast-case check, so
// it is certain that at least one operand isn't a smi.
- {
- // This is optimized for reading the code and not benchmarked for
- // speed or amount of instructions. The code is not ordered for speed
- // or anything like this
- Label miss, user_compare;
-
- // No global compare if both operands are SMIs
- __ And(a2, a1, Operand(a0));
- __ JumpIfSmi(a2, &miss);
-
-
- // We need to check if lhs and rhs are both objects, if not we are
- // jumping out of the function. We will keep the 'map' in t0 (lhs) and
- // t1 (rhs) for later usage.
- __ GetObjectType(a0, t0, a3);
- __ Branch(&miss, ne, a3, Operand(JS_OBJECT_TYPE));
-
- __ GetObjectType(a1, t1, a3);
- __ Branch(&miss, ne, a3, Operand(JS_OBJECT_TYPE));
-
- // Check if the UseUserComparison flag is set by using the map of t0 for lhs
- __ lbu(t0, FieldMemOperand(t0, Map::kBitField2Offset));
- __ And(t0, t0, Operand(1 << Map::kUseUserObjectComparison));
- __ Branch(&user_compare, eq, t0, Operand(1 << Map::kUseUserObjectComparison));
-
-
- // Check if the UseUserComparison flag is _not_ set by using the map of t1 for
- // rhs and then jump to the miss label.
- __ lbu(t1, FieldMemOperand(t1, Map::kBitField2Offset));
- __ And(t1, t1, Operand(1 << Map::kUseUserObjectComparison));
- __ Branch(&miss, ne, t1, Operand(1 << Map::kUseUserObjectComparison));
-
- // Invoke the runtime function here
- __ bind(&user_compare);
- __ Push(a0, a1);
- __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
-
- // We exit here without doing anything
- __ bind(&miss);
- }
// Handle the case where the objects are identical. Either returns the answer
// or goes to slow. Only falls through if the objects were not identical.
@@ -5449,9 +5400,9 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
__ Branch(&call, ne, t0, Operand(at));
// Patch the receiver on the stack with the global receiver object.
- __ lw(a2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
- __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset));
- __ sw(a2, MemOperand(sp, argc_ * kPointerSize));
+ __ lw(a3, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ __ lw(a3, FieldMemOperand(a3, GlobalObject::kGlobalReceiverOffset));
+ __ sw(a3, MemOperand(sp, argc_ * kPointerSize));
__ bind(&call);
}
@@ -5459,8 +5410,12 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
// a1: pushed function (to be verified)
__ JumpIfSmi(a1, &non_function);
// Get the map of the function object.
- __ GetObjectType(a1, a2, a2);
- __ Branch(&slow, ne, a2, Operand(JS_FUNCTION_TYPE));
+ __ GetObjectType(a1, a3, a3);
+ __ Branch(&slow, ne, a3, Operand(JS_FUNCTION_TYPE));
+
+ if (RecordCallTarget()) {
+ GenerateRecordCallTarget(masm);
+ }
// Fast-case: Invoke the function now.
// a1: pushed function
@@ -5485,8 +5440,17 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
// Slow-case: Non-function called.
__ bind(&slow);
+ if (RecordCallTarget()) {
+ // If there is a call target cache, mark it megamorphic in the
+ // non-function case. MegamorphicSentinel is an immortal immovable
+ // object (undefined) so no write barrier is needed.
+ ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
+ masm->isolate()->heap()->undefined_value());
+ __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
+ __ sw(at, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
+ }
// Check for function proxy.
- __ Branch(&non_function, ne, a2, Operand(JS_FUNCTION_PROXY_TYPE));
+ __ Branch(&non_function, ne, a3, Operand(JS_FUNCTION_PROXY_TYPE));
__ push(a1); // Put proxy as additional argument.
__ li(a0, Operand(argc_ + 1, RelocInfo::NONE));
__ li(a2, Operand(0, RelocInfo::NONE));
@@ -6142,37 +6106,11 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// a2: result string length
__ lw(t0, FieldMemOperand(v0, String::kLengthOffset));
__ sra(t0, t0, 1);
+ // Return original string.
__ Branch(&return_v0, eq, a2, Operand(t0));
-
-
- Label result_longer_than_two;
- // Check for special case of two character ASCII string, in which case
- // we do a lookup in the symbol table first.
- __ li(t0, 2);
- __ Branch(&result_longer_than_two, gt, a2, Operand(t0));
- __ Branch(&runtime, lt, a2, Operand(t0));
-
- __ JumpIfInstanceTypeIsNotSequentialAscii(a1, a1, &runtime);
-
- // Get the two characters forming the sub string.
- __ Addu(v0, v0, Operand(a3));
- __ lbu(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize));
- __ lbu(t0, FieldMemOperand(v0, SeqAsciiString::kHeaderSize + 1));
-
- // Try to lookup two character string in symbol table.
- Label make_two_character_string;
- StringHelper::GenerateTwoCharacterSymbolTableProbe(
- masm, a3, t0, a1, t1, t2, t3, t4, &make_two_character_string);
- __ jmp(&return_v0);
-
- // a2: result string length.
- // a3: two characters combined into halfword in little endian byte order.
- __ bind(&make_two_character_string);
- __ AllocateAsciiString(v0, a2, t0, t1, t4, &runtime);
- __ sh(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize));
- __ jmp(&return_v0);
-
- __ bind(&result_longer_than_two);
+ // Longer than original string's length or negative: unsafe arguments.
+ __ Branch(&runtime, hi, a2, Operand(t0));
+ // Shorter than original string's length: an actual substring.
// Deal with different string types: update the index if necessary
// and put the underlying string into t1.
@@ -7030,20 +6968,10 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ And(a2, a1, Operand(a0));
__ JumpIfSmi(a2, &miss);
- // Compare lhs, a2 holds the map, a3 holds the type_reg
- __ GetObjectType(a0, a2, a3);
- __ Branch(&miss, ne, a3, Operand(JS_OBJECT_TYPE));
- __ lbu(a2, FieldMemOperand(a2, Map::kBitField2Offset));
- __ And(a2, a2, Operand(1 << Map::kUseUserObjectComparison));
- __ Branch(&miss, eq, a2, Operand(1 << Map::kUseUserObjectComparison));
-
-
- // Compare rhs, a2 holds the map, a3 holds the type_reg
- __ GetObjectType(a1, a2, a3);
- __ Branch(&miss, ne, a3, Operand(JS_OBJECT_TYPE));
- __ lbu(a2, FieldMemOperand(a2, Map::kBitField2Offset));
- __ And(a2, a2, Operand(1 << Map::kUseUserObjectComparison));
- __ Branch(&miss, eq, a2, Operand(1 << Map::kUseUserObjectComparison));
+ __ GetObjectType(a0, a2, a2);
+ __ Branch(&miss, ne, a2, Operand(JS_OBJECT_TYPE));
+ __ GetObjectType(a1, a2, a2);
+ __ Branch(&miss, ne, a2, Operand(JS_OBJECT_TYPE));
ASSERT(GetCondition() == eq);
__ Ret(USE_DELAY_SLOT);
@@ -7060,18 +6988,8 @@ void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
__ JumpIfSmi(a2, &miss);
__ lw(a2, FieldMemOperand(a0, HeapObject::kMapOffset));
__ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
-
- // Check object in a0
__ Branch(&miss, ne, a2, Operand(known_map_));
- __ lbu(a2, FieldMemOperand(a2, Map::kBitField2Offset));
- __ And(a2, a2, Operand(1 << Map::kUseUserObjectComparison));
- __ Branch(&miss, eq, a2, Operand(1 << Map::kUseUserObjectComparison));
-
- // Check object in a1
__ Branch(&miss, ne, a3, Operand(known_map_));
- __ lbu(a3, FieldMemOperand(a3, Map::kBitField2Offset));
- __ And(a3, a3, Operand(1 << Map::kUseUserObjectComparison));
- __ Branch(&miss, eq, a3, Operand(1 << Map::kUseUserObjectComparison));
__ Ret(USE_DELAY_SLOT);
__ subu(v0, a0, a1);
diff --git a/src/3rdparty/v8/src/mips/constants-mips.h b/src/3rdparty/v8/src/mips/constants-mips.h
index fd04722..3d58571 100644
--- a/src/3rdparty/v8/src/mips/constants-mips.h
+++ b/src/3rdparty/v8/src/mips/constants-mips.h
@@ -788,11 +788,6 @@ const int kBArgsSlotsSize = 0 * Instruction::kInstrSize;
const int kBranchReturnOffset = 2 * Instruction::kInstrSize;
-const int kDoubleAlignmentBits = 3;
-const int kDoubleAlignment = (1 << kDoubleAlignmentBits);
-const int kDoubleAlignmentMask = kDoubleAlignment - 1;
-
-
} } // namespace v8::internal
#endif // #ifndef V8_MIPS_CONSTANTS_H_
diff --git a/src/3rdparty/v8/src/mips/debug-mips.cc b/src/3rdparty/v8/src/mips/debug-mips.cc
index 83f5f50..3be1e4d 100644
--- a/src/3rdparty/v8/src/mips/debug-mips.cc
+++ b/src/3rdparty/v8/src/mips/debug-mips.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -116,6 +116,8 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() {
Assembler::kDebugBreakSlotInstructions);
}
+const bool Debug::FramePaddingLayout::kIsSupported = false;
+
#define __ ACCESS_MASM(masm)
diff --git a/src/3rdparty/v8/src/mips/deoptimizer-mips.cc b/src/3rdparty/v8/src/mips/deoptimizer-mips.cc
index 51c2e46..62f3155 100644
--- a/src/3rdparty/v8/src/mips/deoptimizer-mips.cc
+++ b/src/3rdparty/v8/src/mips/deoptimizer-mips.cc
@@ -447,6 +447,8 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
int frame_index) {
+ Builtins* builtins = isolate_->builtins();
+ Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
unsigned height = iterator->Next();
unsigned height_in_bytes = height * kPointerSize;
@@ -454,7 +456,7 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
PrintF(" translating construct stub => height=%d\n", height_in_bytes);
}
- unsigned fixed_frame_size = 7 * kPointerSize;
+ unsigned fixed_frame_size = 8 * kPointerSize;
unsigned output_frame_size = height_in_bytes + fixed_frame_size;
// Allocate and store the output frame description.
@@ -519,6 +521,15 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
top_address + output_offset, output_offset, value);
}
+ // The output frame reflects a JSConstructStubGeneric frame.
+ output_offset -= kPointerSize;
+ value = reinterpret_cast<intptr_t>(construct_stub);
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; code object\n",
+ top_address + output_offset, output_offset, value);
+ }
+
// Number of incoming arguments.
output_offset -= kPointerSize;
value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1));
@@ -549,8 +560,6 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
ASSERT(0 == output_offset);
- Builtins* builtins = isolate_->builtins();
- Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
uint32_t pc = reinterpret_cast<uint32_t>(
construct_stub->instruction_start() +
isolate_->heap()->construct_stub_deopt_pc_offset()->value());
diff --git a/src/3rdparty/v8/src/mips/full-codegen-mips.cc b/src/3rdparty/v8/src/mips/full-codegen-mips.cc
index 2dbb112..7be5056 100644
--- a/src/3rdparty/v8/src/mips/full-codegen-mips.cc
+++ b/src/3rdparty/v8/src/mips/full-codegen-mips.cc
@@ -189,13 +189,12 @@ void FullCodeGenerator::Generate() {
// Possibly allocate a local context.
int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
- if (heap_slots > 0 ||
- (scope()->is_qml_mode() && scope()->is_global_scope())) {
+ if (heap_slots > 0) {
Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is in a1.
__ push(a1);
if (heap_slots <= FastNewContextStub::kMaximumSlots) {
- FastNewContextStub stub((heap_slots < 0)?0:heap_slots);
+ FastNewContextStub stub(heap_slots);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kNewFunctionContext, 1);
@@ -276,11 +275,11 @@ void FullCodeGenerator::Generate() {
// For named function expressions, declare the function name as a
// constant.
if (scope()->is_function_scope() && scope()->function() != NULL) {
- VariableProxy* proxy = scope()->function();
- ASSERT(proxy->var()->mode() == CONST ||
- proxy->var()->mode() == CONST_HARMONY);
- ASSERT(proxy->var()->location() != Variable::UNALLOCATED);
- EmitDeclaration(proxy, proxy->var()->mode(), NULL);
+ VariableDeclaration* function = scope()->function();
+ ASSERT(function->proxy()->var()->mode() == CONST ||
+ function->proxy()->var()->mode() == CONST_HARMONY);
+ ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED);
+ VisitVariableDeclaration(function);
}
VisitDeclarations(scope()->declarations());
}
@@ -790,64 +789,53 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
}
-void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
- VariableMode mode,
- FunctionLiteral* function) {
+void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
+ // The variable in the declaration always resides in the current function
+ // context.
+ ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
+ if (FLAG_debug_code) {
+ // Check that we're not inside a with or catch context.
+ __ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset));
+ __ LoadRoot(t0, Heap::kWithContextMapRootIndex);
+ __ Check(ne, "Declaration in with context.",
+ a1, Operand(t0));
+ __ LoadRoot(t0, Heap::kCatchContextMapRootIndex);
+ __ Check(ne, "Declaration in catch context.",
+ a1, Operand(t0));
+ }
+}
+
+
+void FullCodeGenerator::VisitVariableDeclaration(
+ VariableDeclaration* declaration) {
// If it was not possible to allocate the variable at compile time, we
// need to "declare" it at runtime to make sure it actually exists in the
// local context.
+ VariableProxy* proxy = declaration->proxy();
+ VariableMode mode = declaration->mode();
Variable* variable = proxy->var();
- bool binding_needs_init = (function == NULL) &&
- (mode == CONST || mode == CONST_HARMONY || mode == LET);
+ bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
switch (variable->location()) {
case Variable::UNALLOCATED:
- ++global_count_;
+ globals_->Add(variable->name());
+ globals_->Add(variable->binding_needs_init()
+ ? isolate()->factory()->the_hole_value()
+ : isolate()->factory()->undefined_value());
break;
case Variable::PARAMETER:
case Variable::LOCAL:
- if (function != NULL) {
- Comment cmnt(masm_, "[ Declaration");
- VisitForAccumulatorValue(function);
- __ sw(result_register(), StackOperand(variable));
- } else if (binding_needs_init) {
- Comment cmnt(masm_, "[ Declaration");
- __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
- __ sw(t0, StackOperand(variable));
+ if (hole_init) {
+ Comment cmnt(masm_, "[ VariableDeclaration");
+ __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
+ __ sw(t0, StackOperand(variable));
}
break;
case Variable::CONTEXT:
- // The variable in the decl always resides in the current function
- // context.
- ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
- if (FLAG_debug_code) {
- // Check that we're not inside a with or catch context.
- __ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset));
- __ LoadRoot(t0, Heap::kWithContextMapRootIndex);
- __ Check(ne, "Declaration in with context.",
- a1, Operand(t0));
- __ LoadRoot(t0, Heap::kCatchContextMapRootIndex);
- __ Check(ne, "Declaration in catch context.",
- a1, Operand(t0));
- }
- if (function != NULL) {
- Comment cmnt(masm_, "[ Declaration");
- VisitForAccumulatorValue(function);
- __ sw(result_register(), ContextOperand(cp, variable->index()));
- int offset = Context::SlotOffset(variable->index());
- // We know that we have written a function, which is not a smi.
- __ RecordWriteContextSlot(cp,
- offset,
- result_register(),
- a2,
- kRAHasBeenSaved,
- kDontSaveFPRegs,
- EMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
- } else if (binding_needs_init) {
- Comment cmnt(masm_, "[ Declaration");
+ if (hole_init) {
+ Comment cmnt(masm_, "[ VariableDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
__ sw(at, ContextOperand(cp, variable->index()));
// No write barrier since the_hole_value is in old space.
@@ -856,13 +844,11 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
break;
case Variable::LOOKUP: {
- Comment cmnt(masm_, "[ Declaration");
+ Comment cmnt(masm_, "[ VariableDeclaration");
__ li(a2, Operand(variable->name()));
// Declaration nodes are always introduced in one of four modes.
- ASSERT(mode == VAR ||
- mode == CONST ||
- mode == CONST_HARMONY ||
- mode == LET);
+ ASSERT(mode == VAR || mode == LET ||
+ mode == CONST || mode == CONST_HARMONY);
PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY)
? READ_ONLY : NONE;
__ li(a1, Operand(Smi::FromInt(attr)));
@@ -870,13 +856,9 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
// Note: For variables we must not push an initial value (such as
// 'undefined') because we may have a (legal) redeclaration and we
// must not destroy the current value.
- if (function != NULL) {
- __ Push(cp, a2, a1);
- // Push initial value for function declaration.
- VisitForStackValue(function);
- } else if (binding_needs_init) {
- __ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
- __ Push(cp, a2, a1, a0);
+ if (hole_init) {
+ __ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
+ __ Push(cp, a2, a1, a0);
} else {
ASSERT(Smi::FromInt(0) == 0);
__ mov(a0, zero_reg); // Smi::FromInt(0) indicates no initial value.
@@ -889,6 +871,122 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
}
+void FullCodeGenerator::VisitFunctionDeclaration(
+ FunctionDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED: {
+ globals_->Add(variable->name());
+ Handle<SharedFunctionInfo> function =
+ Compiler::BuildFunctionInfo(declaration->fun(), script());
+ // Check for stack-overflow exception.
+ if (function.is_null()) return SetStackOverflow();
+ globals_->Add(function);
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ VisitForAccumulatorValue(declaration->fun());
+ __ sw(result_register(), StackOperand(variable));
+ break;
+ }
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ VisitForAccumulatorValue(declaration->fun());
+ __ sw(result_register(), ContextOperand(cp, variable->index()));
+ int offset = Context::SlotOffset(variable->index());
+ // We know that we have written a function, which is not a smi.
+ __ RecordWriteContextSlot(cp,
+ offset,
+ result_register(),
+ a2,
+ kRAHasBeenSaved,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
+ break;
+ }
+
+ case Variable::LOOKUP: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ __ li(a2, Operand(variable->name()));
+ __ li(a1, Operand(Smi::FromInt(NONE)));
+ __ Push(cp, a2, a1);
+ // Push initial value for function declaration.
+ VisitForStackValue(declaration->fun());
+ __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ break;
+ }
+ }
+}
+
+
+void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ Handle<JSModule> instance = declaration->module()->interface()->Instance();
+ ASSERT(!instance.is_null());
+
+ switch (variable->location()) {
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "[ ModuleDeclaration");
+ globals_->Add(variable->name());
+ globals_->Add(instance);
+ Visit(declaration->module());
+ break;
+ }
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ ModuleDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ __ li(a1, Operand(instance));
+ __ sw(a1, ContextOperand(cp, variable->index()));
+ Visit(declaration->module());
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::LOOKUP:
+ UNREACHABLE();
+ }
+}
+
+
+void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ // TODO(rossberg)
+ break;
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ ImportDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ // TODO(rossberg)
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::LOOKUP:
+ UNREACHABLE();
+ }
+}
+
+
+void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
+ // TODO(rossberg)
+}
+
+
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
// The context is the first argument.
@@ -1238,7 +1336,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
__ bind(&fast);
}
- __ lw(a0, var->is_qml_global() ? QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ lw(a0, GlobalObjectOperand());
__ li(a2, Operand(var->name()));
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
@@ -1325,7 +1423,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
Comment cmnt(masm_, "Global variable");
// Use inline caching. Variable name is passed in a2 and the global
// object (receiver) in a0.
- __ lw(a0, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ lw(a0, GlobalObjectOperand());
__ li(a2, Operand(var->name()));
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
@@ -2003,7 +2101,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
// Global var, const, or let.
__ mov(a0, result_register());
__ li(a2, Operand(var->name()));
- __ lw(a1, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ lw(a1, GlobalObjectOperand());
Handle<Code> ic = is_classic_mode()
? isolate()->builtins()->StoreIC_Initialize()
: isolate()->builtins()->StoreIC_Initialize_Strict();
@@ -2290,6 +2388,18 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
}
// Record source position for debugger.
SetSourcePosition(expr->position());
+
+ // Record call targets in unoptimized code, but not in the snapshot.
+ if (!Serializer::enabled()) {
+ flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
+ Handle<Object> uninitialized =
+ TypeFeedbackCells::UninitializedSentinel(isolate());
+ Handle<JSGlobalPropertyCell> cell =
+ isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
+ RecordTypeFeedbackCell(expr->id(), cell);
+ __ li(a2, Operand(cell));
+ }
+
CallFunctionStub stub(arg_count, flags);
__ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
@@ -2321,12 +2431,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
__ li(a1, Operand(Smi::FromInt(scope()->start_position())));
__ push(a1);
- // Push the qml mode flag.
- __ li(a1, Operand(Smi::FromInt(is_qml_mode())));
- __ push(a1);
-
// Do the runtime call.
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
}
@@ -2382,7 +2488,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
context()->DropAndPlug(1, v0);
} else if (proxy != NULL && proxy->var()->IsUnallocated()) {
// Push global object as receiver for the call IC.
- __ lw(a0, proxy->var()->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ lw(a0, GlobalObjectOperand());
__ push(a0);
EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
} else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
@@ -3394,104 +3500,6 @@ void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
}
-void FullCodeGenerator::EmitSwapElements(CallRuntime* expr) {
- ZoneList<Expression*>* args = expr->arguments();
- ASSERT(args->length() == 3);
- VisitForStackValue(args->at(0));
- VisitForStackValue(args->at(1));
- VisitForStackValue(args->at(2));
- Label done;
- Label slow_case;
- Register object = a0;
- Register index1 = a1;
- Register index2 = a2;
- Register elements = a3;
- Register scratch1 = t0;
- Register scratch2 = t1;
-
- __ lw(object, MemOperand(sp, 2 * kPointerSize));
- // Fetch the map and check if array is in fast case.
- // Check that object doesn't require security checks and
- // has no indexed interceptor.
- __ GetObjectType(object, scratch1, scratch2);
- __ Branch(&slow_case, ne, scratch2, Operand(JS_ARRAY_TYPE));
- // Map is now in scratch1.
-
- __ lbu(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
- __ And(scratch2, scratch2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
- __ Branch(&slow_case, ne, scratch2, Operand(zero_reg));
-
- // Check the object's elements are in fast case and writable.
- __ lw(elements, FieldMemOperand(object, JSObject::kElementsOffset));
- __ lw(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ LoadRoot(scratch2, Heap::kFixedArrayMapRootIndex);
- __ Branch(&slow_case, ne, scratch1, Operand(scratch2));
-
- // Check that both indices are smis.
- __ lw(index1, MemOperand(sp, 1 * kPointerSize));
- __ lw(index2, MemOperand(sp, 0));
- __ JumpIfNotBothSmi(index1, index2, &slow_case);
-
- // Check that both indices are valid.
- Label not_hi;
- __ lw(scratch1, FieldMemOperand(object, JSArray::kLengthOffset));
- __ Branch(&slow_case, ls, scratch1, Operand(index1));
- __ Branch(&not_hi, NegateCondition(hi), scratch1, Operand(index1));
- __ Branch(&slow_case, ls, scratch1, Operand(index2));
- __ bind(&not_hi);
-
- // Bring the address of the elements into index1 and index2.
- __ Addu(scratch1, elements,
- Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ sll(index1, index1, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(index1, scratch1, index1);
- __ sll(index2, index2, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(index2, scratch1, index2);
-
- // Swap elements.
- __ lw(scratch1, MemOperand(index1, 0));
- __ lw(scratch2, MemOperand(index2, 0));
- __ sw(scratch1, MemOperand(index2, 0));
- __ sw(scratch2, MemOperand(index1, 0));
-
- Label no_remembered_set;
- __ CheckPageFlag(elements,
- scratch1,
- 1 << MemoryChunk::SCAN_ON_SCAVENGE,
- ne,
- &no_remembered_set);
- // Possible optimization: do a check that both values are Smis
- // (or them and test against Smi mask).
-
- // We are swapping two objects in an array and the incremental marker never
- // pauses in the middle of scanning a single object. Therefore the
- // incremental marker is not disturbed, so we don't need to call the
- // RecordWrite stub that notifies the incremental marker.
- __ RememberedSetHelper(elements,
- index1,
- scratch2,
- kDontSaveFPRegs,
- MacroAssembler::kFallThroughAtEnd);
- __ RememberedSetHelper(elements,
- index2,
- scratch2,
- kDontSaveFPRegs,
- MacroAssembler::kFallThroughAtEnd);
-
- __ bind(&no_remembered_set);
- // We are done. Drop elements from the stack, and return undefined.
- __ Drop(3);
- __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
- __ jmp(&done);
-
- __ bind(&slow_case);
- __ CallRuntime(Runtime::kSwapElements, 3);
-
- __ bind(&done);
- context()->Plug(v0);
-}
-
-
void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(2, args->length());
@@ -3921,7 +3929,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
// but "delete this" is allowed.
ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
if (var->IsUnallocated()) {
- __ lw(a2, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ __ lw(a2, GlobalObjectOperand());
__ li(a1, Operand(var->name()));
__ li(a0, Operand(Smi::FromInt(kNonStrictMode)));
__ Push(a2, a1, a0);
@@ -4227,7 +4235,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
VariableProxy* proxy = expr->AsVariableProxy();
if (proxy != NULL && proxy->var()->IsUnallocated()) {
Comment cmnt(masm_, "Global variable");
- __ lw(a0, proxy->var()->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ __ lw(a0, GlobalObjectOperand());
__ li(a2, Operand(proxy->name()));
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
// Use a regular load, not a contextual load, to avoid a reference
@@ -4489,7 +4497,8 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
Scope* declaration_scope = scope()->DeclarationScope();
- if (declaration_scope->is_global_scope()) {
+ if (declaration_scope->is_global_scope() ||
+ declaration_scope->is_module_scope()) {
// Contexts nested in the global context have a canonical empty function
// as their closure, not the anonymous closure containing the global
// code. Pass a smi sentinel and let the runtime look up the empty
diff --git a/src/3rdparty/v8/src/mips/ic-mips.cc b/src/3rdparty/v8/src/mips/ic-mips.cc
index 2c4da1a..964a7e2 100644
--- a/src/3rdparty/v8/src/mips/ic-mips.cc
+++ b/src/3rdparty/v8/src/mips/ic-mips.cc
@@ -767,7 +767,7 @@ static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm,
__ Branch(slow_case, lt, scratch2, Operand(FIRST_JS_RECEIVER_TYPE));
// Check that the key is a positive smi.
- __ And(scratch1, key, Operand(0x8000001));
+ __ And(scratch1, key, Operand(0x80000001));
__ Branch(slow_case, ne, scratch1, Operand(zero_reg));
// Load the elements into scratch1 and check its map.
@@ -1688,12 +1688,12 @@ void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
// Activate inlined smi code.
if (previous_state == UNINITIALIZED) {
- PatchInlinedSmiCode(address());
+ PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
}
}
-void PatchInlinedSmiCode(Address address) {
+void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
Address andi_instruction_address =
address + Assembler::kCallTargetAddressOffset;
@@ -1727,33 +1727,30 @@ void PatchInlinedSmiCode(Address address) {
Instr instr_at_patch = Assembler::instr_at(patch_address);
Instr branch_instr =
Assembler::instr_at(patch_address + Instruction::kInstrSize);
- ASSERT(Assembler::IsAndImmediate(instr_at_patch));
- ASSERT_EQ(0, Assembler::GetImmediate16(instr_at_patch));
+ // This is patching a conditional "jump if not smi/jump if smi" site.
+ // Enabling by changing from
+ // andi at, rx, 0
+ // Branch <target>, eq, at, Operand(zero_reg)
+ // to:
+ // andi at, rx, #kSmiTagMask
+ // Branch <target>, ne, at, Operand(zero_reg)
+ // and vice-versa to be disabled again.
+ CodePatcher patcher(patch_address, 2);
+ Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
+ if (check == ENABLE_INLINED_SMI_CHECK) {
+ ASSERT(Assembler::IsAndImmediate(instr_at_patch));
+ ASSERT_EQ(0, Assembler::GetImmediate16(instr_at_patch));
+ patcher.masm()->andi(at, reg, kSmiTagMask);
+ } else {
+ ASSERT(check == DISABLE_INLINED_SMI_CHECK);
+ ASSERT(Assembler::IsAndImmediate(instr_at_patch));
+ patcher.masm()->andi(at, reg, 0);
+ }
ASSERT(Assembler::IsBranch(branch_instr));
if (Assembler::IsBeq(branch_instr)) {
- // This is patching a "jump if not smi" site to be active.
- // Changing:
- // andi at, rx, 0
- // Branch <target>, eq, at, Operand(zero_reg)
- // to:
- // andi at, rx, #kSmiTagMask
- // Branch <target>, ne, at, Operand(zero_reg)
- CodePatcher patcher(patch_address, 2);
- Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
- patcher.masm()->andi(at, reg, kSmiTagMask);
patcher.ChangeBranchCondition(ne);
} else {
ASSERT(Assembler::IsBne(branch_instr));
- // This is patching a "jump if smi" site to be active.
- // Changing:
- // andi at, rx, 0
- // Branch <target>, ne, at, Operand(zero_reg)
- // to:
- // andi at, rx, #kSmiTagMask
- // Branch <target>, eq, at, Operand(zero_reg)
- CodePatcher patcher(patch_address, 2);
- Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
- patcher.masm()->andi(at, reg, kSmiTagMask);
patcher.ChangeBranchCondition(eq);
}
}
diff --git a/src/3rdparty/v8/src/mips/lithium-codegen-mips.cc b/src/3rdparty/v8/src/mips/lithium-codegen-mips.cc
index 18f6a85..a4de721 100644
--- a/src/3rdparty/v8/src/mips/lithium-codegen-mips.cc
+++ b/src/3rdparty/v8/src/mips/lithium-codegen-mips.cc
@@ -172,13 +172,12 @@ bool LCodeGen::GeneratePrologue() {
// Possibly allocate a local context.
int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
- if (heap_slots > 0 ||
- (scope()->is_qml_mode() && scope()->is_global_scope())) {
+ if (heap_slots > 0) {
Comment(";;; Allocate local context");
// Argument to NewContext is the function, which is in a1.
__ push(a1);
if (heap_slots <= FastNewContextStub::kMaximumSlots) {
- FastNewContextStub stub((heap_slots < 0)?0:heap_slots);
+ FastNewContextStub stub(heap_slots);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kNewFunctionContext, 1);
@@ -2140,8 +2139,7 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
RelocInfo::CODE_TARGET,
instr,
RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
- ASSERT(instr->HasDeoptimizationEnvironment());
- LEnvironment* env = instr->deoptimization_environment();
+ LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
// Put the result value into the result register slot and
// restore all registers.
@@ -2345,40 +2343,37 @@ void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
Register object = ToRegister(instr->object());
Register result = ToRegister(instr->result());
Register scratch = scratch0();
+
int map_count = instr->hydrogen()->types()->length();
+ bool need_generic = instr->hydrogen()->need_generic();
+
+ if (map_count == 0 && !need_generic) {
+ DeoptimizeIf(al, instr->environment());
+ return;
+ }
Handle<String> name = instr->hydrogen()->name();
- if (map_count == 0) {
- ASSERT(instr->hydrogen()->need_generic());
- __ li(a2, Operand(name));
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- CallCode(ic, RelocInfo::CODE_TARGET, instr);
- } else {
- Label done;
- __ lw(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
- for (int i = 0; i < map_count - 1; ++i) {
- Handle<Map> map = instr->hydrogen()->types()->at(i);
+ Label done;
+ __ lw(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
+ for (int i = 0; i < map_count; ++i) {
+ bool last = (i == map_count - 1);
+ Handle<Map> map = instr->hydrogen()->types()->at(i);
+ if (last && !need_generic) {
+ DeoptimizeIf(ne, instr->environment(), scratch, Operand(map));
+ EmitLoadFieldOrConstantFunction(result, object, map, name);
+ } else {
Label next;
__ Branch(&next, ne, scratch, Operand(map));
EmitLoadFieldOrConstantFunction(result, object, map, name);
__ Branch(&done);
__ bind(&next);
}
- Handle<Map> map = instr->hydrogen()->types()->last();
- if (instr->hydrogen()->need_generic()) {
- Label generic;
- __ Branch(&generic, ne, scratch, Operand(map));
- EmitLoadFieldOrConstantFunction(result, object, map, name);
- __ Branch(&done);
- __ bind(&generic);
- __ li(a2, Operand(name));
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- CallCode(ic, RelocInfo::CODE_TARGET, instr);
- } else {
- DeoptimizeIf(ne, instr->environment(), scratch, Operand(map));
- EmitLoadFieldOrConstantFunction(result, object, map, name);
- }
- __ bind(&done);
}
+ if (need_generic) {
+ __ li(a2, Operand(name));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ }
+ __ bind(&done);
}
@@ -2652,16 +2647,20 @@ void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
Register temp = scratch1();
Register result = ToRegister(instr->result());
- // Check if the calling frame is an arguments adaptor frame.
- Label done, adapted;
- __ lw(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
- __ lw(result, MemOperand(scratch, StandardFrameConstants::kContextOffset));
- __ Xor(temp, result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
-
- // Result is the frame pointer for the frame if not adapted and for the real
- // frame below the adaptor frame if adapted.
- __ Movn(result, fp, temp); // Move only if temp is not equal to zero (ne).
- __ Movz(result, scratch, temp); // Move only if temp is equal to zero (eq).
+ if (instr->hydrogen()->from_inlined()) {
+ __ Subu(result, sp, 2 * kPointerSize);
+ } else {
+ // Check if the calling frame is an arguments adaptor frame.
+ Label done, adapted;
+ __ lw(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+ __ lw(result, MemOperand(scratch, StandardFrameConstants::kContextOffset));
+ __ Xor(temp, result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
+
+ // Result is the frame pointer for the frame if not adapted and for the real
+ // frame below the adaptor frame if adapted.
+ __ Movn(result, fp, temp); // Move only if temp is not equal to zero (ne).
+ __ Movz(result, scratch, temp); // Move only if temp is equal to zero (eq).
+ }
}
@@ -2769,7 +2768,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
__ sll(scratch, length, 2);
__ bind(&invoke);
- ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ ASSERT(instr->HasPointerMap());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator safepoint_generator(
@@ -2794,6 +2793,11 @@ void LCodeGen::DoPushArgument(LPushArgument* instr) {
}
+void LCodeGen::DoDrop(LDrop* instr) {
+ __ Drop(instr->count());
+}
+
+
void LCodeGen::DoThisFunction(LThisFunction* instr) {
Register result = ToRegister(instr->result());
__ LoadHeapObject(result, instr->hydrogen()->closure());
@@ -2825,7 +2829,7 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
Register result = ToRegister(instr->result());
- __ lw(result, ContextOperand(cp, instr->qml_global()?Context::QML_GLOBAL_INDEX:Context::GLOBAL_INDEX));
+ __ lw(result, ContextOperand(cp, Context::GLOBAL_INDEX));
}
@@ -2839,7 +2843,8 @@ void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
- CallKind call_kind) {
+ CallKind call_kind,
+ A1State a1_state) {
bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
function->shared()->formal_parameter_count() == arity;
@@ -2847,7 +2852,10 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
RecordPosition(pointers->position());
if (can_invoke_directly) {
- __ LoadHeapObject(a1, function);
+ if (a1_state == A1_UNINITIALIZED) {
+ __ LoadHeapObject(a1, function);
+ }
+
// Change context if needed.
bool change_context =
(info()->closure()->context() != function->context()) ||
@@ -2884,7 +2892,11 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
ASSERT(ToRegister(instr->result()).is(v0));
__ mov(a0, v0);
- CallKnownFunction(instr->function(), instr->arity(), instr, CALL_AS_METHOD);
+ CallKnownFunction(instr->function(),
+ instr->arity(),
+ instr,
+ CALL_AS_METHOD,
+ A1_UNINITIALIZED);
}
@@ -3210,7 +3222,7 @@ void LCodeGen::DoRandom(LRandom* instr) {
// state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
__ And(a3, a1, Operand(0xFFFF));
__ li(t0, Operand(18273));
- __ mul(a3, a3, t0);
+ __ Mul(a3, a3, t0);
__ srl(a1, a1, 16);
__ Addu(a1, a3, a1);
// Save state[0].
@@ -3219,7 +3231,7 @@ void LCodeGen::DoRandom(LRandom* instr) {
// state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
__ And(a3, a0, Operand(0xFFFF));
__ li(t0, Operand(36969));
- __ mul(a3, a3, t0);
+ __ Mul(a3, a3, t0);
__ srl(a0, a0, 16),
__ Addu(a0, a3, a0);
// Save state[1].
@@ -3320,13 +3332,21 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(ToRegister(instr->function()).is(a1));
ASSERT(instr->HasPointerMap());
- ASSERT(instr->HasDeoptimizationEnvironment());
- LPointerMap* pointers = instr->pointer_map();
- RecordPosition(pointers->position());
- SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
- ParameterCount count(instr->arity());
- __ InvokeFunction(a1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
- __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+
+ if (instr->known_function().is_null()) {
+ LPointerMap* pointers = instr->pointer_map();
+ RecordPosition(pointers->position());
+ SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+ ParameterCount count(instr->arity());
+ __ InvokeFunction(a1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
+ __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ } else {
+ CallKnownFunction(instr->known_function(),
+ instr->arity(),
+ instr,
+ CALL_AS_METHOD,
+ A1_CONTAINS_TARGET);
+ }
}
@@ -3381,7 +3401,11 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(v0));
- CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
+ CallKnownFunction(instr->target(),
+ instr->arity(),
+ instr,
+ CALL_AS_FUNCTION,
+ A1_UNINITIALIZED);
}
@@ -3537,14 +3561,16 @@ void LCodeGen::DoStoreKeyedFastDoubleElement(
Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
}
- Label is_nan;
- // Check for NaN. All NaNs must be canonicalized.
- __ BranchF(NULL, &is_nan, eq, value, value);
- __ Branch(&not_nan);
+ 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);
- __ Move(value, FixedDoubleArray::canonical_not_the_hole_nan_as_double());
+ // Only load canonical NaN if the comparison above set the overflow.
+ __ bind(&is_nan);
+ __ Move(value, FixedDoubleArray::canonical_not_the_hole_nan_as_double());
+ }
__ bind(&not_nan);
__ sdc1(value, MemOperand(scratch));
@@ -4545,9 +4571,10 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
__ sw(a2, FieldMemOperand(result, total_offset + 4));
}
} else if (elements->IsFixedArray()) {
+ Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
for (int i = 0; i < elements_length; i++) {
int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
- Handle<Object> value = JSObject::GetElement(object, i);
+ Handle<Object> value(fast_elements->get(i));
if (value->IsJSObject()) {
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
__ Addu(a2, result, Operand(*offset));
@@ -4571,6 +4598,23 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
int size = instr->hydrogen()->total_size();
+ ElementsKind boilerplate_elements_kind =
+ instr->hydrogen()->boilerplate()->GetElementsKind();
+
+ // Deopt if the literal boilerplate ElementsKind is of a type different than
+ // the expected one. The check isn't necessary if the boilerplate has already
+ // been converted to FAST_ELEMENTS.
+ if (boilerplate_elements_kind != FAST_ELEMENTS) {
+ __ LoadHeapObject(a1, instr->hydrogen()->boilerplate());
+ // Load map into a2.
+ __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
+ // Load the map's "bit field 2".
+ __ lbu(a2, FieldMemOperand(a2, Map::kBitField2Offset));
+ // Retrieve elements_kind from bit field 2.
+ __ Ext(a2, a2, Map::kElementsKindShift, Map::kElementsKindBitCount);
+ DeoptimizeIf(ne, instr->environment(), a2,
+ Operand(boilerplate_elements_kind));
+ }
// Allocate all objects that are part of the literal in one big
// allocation. This avoids multiple limit checks.
@@ -4906,7 +4950,7 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
Register strict = scratch0();
__ li(strict, Operand(Smi::FromInt(strict_mode_flag())));
__ Push(object, key, strict);
- ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ ASSERT(instr->HasPointerMap());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator safepoint_generator(
@@ -4919,7 +4963,7 @@ void LCodeGen::DoIn(LIn* instr) {
Register obj = ToRegister(instr->object());
Register key = ToRegister(instr->key());
__ Push(key, obj);
- ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ ASSERT(instr->HasPointerMap());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt);
diff --git a/src/3rdparty/v8/src/mips/lithium-codegen-mips.h b/src/3rdparty/v8/src/mips/lithium-codegen-mips.h
index b508256..94bb945 100644
--- a/src/3rdparty/v8/src/mips/lithium-codegen-mips.h
+++ b/src/3rdparty/v8/src/mips/lithium-codegen-mips.h
@@ -212,12 +212,18 @@ class LCodeGen BASE_EMBEDDED {
int argc,
LInstruction* instr);
+ enum A1State {
+ A1_UNINITIALIZED,
+ A1_CONTAINS_TARGET
+ };
+
// Generate a direct call to a known function. Expects the function
// to be in a1.
void CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
- CallKind call_kind);
+ CallKind call_kind,
+ A1State a1_state);
void LoadHeapObject(Register result, Handle<HeapObject> object);
diff --git a/src/3rdparty/v8/src/mips/lithium-mips.cc b/src/3rdparty/v8/src/mips/lithium-mips.cc
index 48b4ca2..1eb3ab7 100644
--- a/src/3rdparty/v8/src/mips/lithium-mips.cc
+++ b/src/3rdparty/v8/src/mips/lithium-mips.cc
@@ -108,22 +108,17 @@ void LInstruction::PrintTo(StringStream* stream) {
}
-template<int R, int I, int T>
-void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) {
+void LInstruction::PrintDataTo(StringStream* stream) {
stream->Add("= ");
- for (int i = 0; i < inputs_.length(); i++) {
+ for (int i = 0; i < InputCount(); i++) {
if (i > 0) stream->Add(" ");
- inputs_[i]->PrintTo(stream);
+ InputAt(i)->PrintTo(stream);
}
}
-template<int R, int I, int T>
-void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) {
- for (int i = 0; i < results_.length(); i++) {
- if (i > 0) stream->Add(" ");
- results_[i]->PrintTo(stream);
- }
+void LInstruction::PrintOutputOperandTo(StringStream* stream) {
+ if (HasResult()) result()->PrintTo(stream);
}
@@ -732,22 +727,6 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
}
-LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
- LInstruction* instr, int ast_id) {
- ASSERT(instruction_pending_deoptimization_environment_ == NULL);
- ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
- instruction_pending_deoptimization_environment_ = instr;
- pending_deoptimization_ast_id_ = ast_id;
- return instr;
-}
-
-
-void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
- instruction_pending_deoptimization_environment_ = NULL;
- pending_deoptimization_ast_id_ = AstNode::kNoNumber;
-}
-
-
LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
HInstruction* hinstr,
CanDeoptimize can_deoptimize) {
@@ -760,8 +739,10 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
if (hinstr->HasObservableSideEffects()) {
ASSERT(hinstr->next()->IsSimulate());
HSimulate* sim = HSimulate::cast(hinstr->next());
- instr = SetInstructionPendingDeoptimizationEnvironment(
- instr, sim->ast_id());
+ ASSERT(instruction_pending_deoptimization_environment_ == NULL);
+ ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
+ instruction_pending_deoptimization_environment_ = instr;
+ pending_deoptimization_ast_id_ = sim->ast_id();
}
// If instruction does not have side-effects lazy deoptimization
@@ -779,12 +760,6 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
}
-LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
- instr->MarkAsSaveDoubles();
- return instr;
-}
-
-
LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
ASSERT(!instr->HasPointerMap());
instr->set_pointer_map(new(zone()) LPointerMap(position_));
@@ -1150,7 +1125,7 @@ LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
LOperand* context = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new(zone()) LGlobalObject(context, instr->qml_global()));
+ return DefineAsRegister(new(zone()) LGlobalObject(context));
}
@@ -1225,7 +1200,7 @@ LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
argument_count_ -= instr->argument_count();
- return MarkAsCall(DefineFixed(new(zone()) LCallGlobal(instr->qml_global()), v0), instr);
+ return MarkAsCall(DefineFixed(new(zone()) LCallGlobal, v0), instr);
}
@@ -1296,6 +1271,7 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
ASSERT(instr->value()->representation().IsInteger32());
ASSERT(instr->representation().IsInteger32());
+ if (instr->HasNoUses()) return NULL;
LOperand* value = UseRegisterAtStart(instr->value());
return DefineAsRegister(new(zone()) LBitNotI(value));
}
@@ -1320,6 +1296,12 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
}
+LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
if (instr->representation().IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
@@ -2247,9 +2229,12 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
if (pending_deoptimization_ast_id_ == instr->ast_id()) {
LInstruction* result = new(zone()) LLazyBailout;
result = AssignEnvironment(result);
+ // Store the lazy deopt environment with the instruction if needed. Right
+ // now it is only used for LInstanceOfKnownGlobal.
instruction_pending_deoptimization_environment_->
- set_deoptimization_environment(result->environment());
- ClearInstructionPendingDeoptimizationEnvironment();
+ SetDeferredLazyDeoptimizationEnvironment(result->environment());
+ instruction_pending_deoptimization_environment_ = NULL;
+ pending_deoptimization_ast_id_ = AstNode::kNoNumber;
return result;
}
@@ -2276,8 +2261,8 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
undefined,
instr->call_kind(),
instr->is_construct());
- if (instr->arguments() != NULL) {
- inner->Bind(instr->arguments(), graph()->GetArgumentsObject());
+ if (instr->arguments_var() != NULL) {
+ inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
}
current_block_->UpdateEnvironment(inner);
chunk_->AddInlinedClosure(instr->closure());
@@ -2286,10 +2271,21 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
+ LInstruction* pop = NULL;
+
+ HEnvironment* env = current_block_->last_environment();
+
+ if (instr->arguments_pushed()) {
+ int argument_count = env->arguments_environment()->parameter_count();
+ pop = new(zone()) LDrop(argument_count);
+ argument_count_ -= argument_count;
+ }
+
HEnvironment* outer = current_block_->last_environment()->
DiscardInlined(false);
current_block_->UpdateEnvironment(outer);
- return NULL;
+
+ return pop;
}
diff --git a/src/3rdparty/v8/src/mips/lithium-mips.h b/src/3rdparty/v8/src/mips/lithium-mips.h
index e1fec8b..a04b429 100644
--- a/src/3rdparty/v8/src/mips/lithium-mips.h
+++ b/src/3rdparty/v8/src/mips/lithium-mips.h
@@ -179,7 +179,8 @@ class LCodeGen;
V(CheckMapValue) \
V(LoadFieldByIndex) \
V(DateField) \
- V(WrapReceiver)
+ V(WrapReceiver) \
+ V(Drop)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
virtual Opcode opcode() const { return LInstruction::k##type; } \
@@ -202,15 +203,14 @@ class LInstruction: public ZoneObject {
LInstruction()
: environment_(NULL),
hydrogen_value_(NULL),
- is_call_(false),
- is_save_doubles_(false) { }
+ is_call_(false) { }
virtual ~LInstruction() { }
virtual void CompileToNative(LCodeGen* generator) = 0;
virtual const char* Mnemonic() const = 0;
virtual void PrintTo(StringStream* stream);
- virtual void PrintDataTo(StringStream* stream) = 0;
- virtual void PrintOutputOperandTo(StringStream* stream) = 0;
+ virtual void PrintDataTo(StringStream* stream);
+ virtual void PrintOutputOperandTo(StringStream* stream);
enum Opcode {
// Declare a unique enum value for each instruction.
@@ -245,22 +245,12 @@ class LInstruction: public ZoneObject {
void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; }
HValue* hydrogen_value() const { return hydrogen_value_; }
- void set_deoptimization_environment(LEnvironment* env) {
- deoptimization_environment_.set(env);
- }
- LEnvironment* deoptimization_environment() const {
- return deoptimization_environment_.get();
- }
- bool HasDeoptimizationEnvironment() const {
- return deoptimization_environment_.is_set();
- }
+ virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { }
void MarkAsCall() { is_call_ = true; }
- void MarkAsSaveDoubles() { is_save_doubles_ = true; }
// Interface to the register allocator and iterators.
bool IsMarkedAsCall() const { return is_call_; }
- bool IsMarkedAsSaveDoubles() const { return is_save_doubles_; }
virtual bool HasResult() const = 0;
virtual LOperand* result() = 0;
@@ -281,7 +271,6 @@ class LInstruction: public ZoneObject {
LEnvironment* environment_;
SetOncePointer<LPointerMap> pointer_map_;
HValue* hydrogen_value_;
- SetOncePointer<LEnvironment> deoptimization_environment_;
bool is_call_;
bool is_save_doubles_;
};
@@ -305,9 +294,6 @@ class LTemplateInstruction: public LInstruction {
int TempCount() { return T; }
LOperand* TempAt(int i) { return temps_[i]; }
- virtual void PrintDataTo(StringStream* stream);
- virtual void PrintOutputOperandTo(StringStream* stream);
-
protected:
EmbeddedContainer<LOperand*, R> results_;
EmbeddedContainer<LOperand*, I> inputs_;
@@ -533,9 +519,8 @@ class LArgumentsLength: public LTemplateInstruction<1, 1, 0> {
class LArgumentsElements: public LTemplateInstruction<1, 0, 0> {
public:
- LArgumentsElements() { }
-
DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements")
+ DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements)
};
@@ -833,6 +818,15 @@ class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> {
DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal)
Handle<JSFunction> function() const { return hydrogen()->function(); }
+ LEnvironment* GetDeferredLazyDeoptimizationEnvironment() {
+ return lazy_deopt_env_;
+ }
+ virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) {
+ lazy_deopt_env_ = env;
+ }
+
+ private:
+ LEnvironment* lazy_deopt_env_;
};
@@ -1358,6 +1352,19 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> {
};
+class LDrop: public LTemplateInstruction<0, 0, 0> {
+ public:
+ explicit LDrop(int count) : count_(count) { }
+
+ int count() const { return count_; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Drop, "drop")
+
+ private:
+ int count_;
+};
+
+
class LThisFunction: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function")
@@ -1392,17 +1399,13 @@ class LDeclareGlobals: public LTemplateInstruction<0, 0, 0> {
class LGlobalObject: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LGlobalObject(LOperand* context, bool qml_global) {
+ explicit LGlobalObject(LOperand* context) {
inputs_[0] = context;
- qml_global_ = qml_global;
}
DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object")
LOperand* context() { return InputAt(0); }
- bool qml_global() { return qml_global_; }
- private:
- bool qml_global_;
};
@@ -1444,6 +1447,7 @@ class LInvokeFunction: public LTemplateInstruction<1, 1, 0> {
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
+ Handle<JSFunction> known_function() { return hydrogen()->known_function(); }
};
@@ -1494,16 +1498,10 @@ class LCallGlobal: public LTemplateInstruction<1, 0, 0> {
DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call-global")
DECLARE_HYDROGEN_ACCESSOR(CallGlobal)
- explicit LCallGlobal(bool qml_global) : qml_global_(qml_global) {}
-
virtual void PrintDataTo(StringStream* stream);
Handle<String> name() const {return hydrogen()->name(); }
int arity() const { return hydrogen()->argument_count() - 1; }
-
- bool qml_global() { return qml_global_; }
- private:
- bool qml_global_;
};
@@ -1729,6 +1727,8 @@ class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
+
+ bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
};
@@ -2359,11 +2359,6 @@ class LChunkBuilder BASE_EMBEDDED {
LInstruction* instr,
HInstruction* hinstr,
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
- LInstruction* MarkAsSaveDoubles(LInstruction* instr);
-
- LInstruction* SetInstructionPendingDeoptimizationEnvironment(
- LInstruction* instr, int ast_id);
- void ClearInstructionPendingDeoptimizationEnvironment();
LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
int* argument_index_accumulator);
diff --git a/src/3rdparty/v8/src/mips/macro-assembler-mips.cc b/src/3rdparty/v8/src/mips/macro-assembler-mips.cc
index e93a417..2c2445b 100644
--- a/src/3rdparty/v8/src/mips/macro-assembler-mips.cc
+++ b/src/3rdparty/v8/src/mips/macro-assembler-mips.cc
@@ -5378,7 +5378,7 @@ CodePatcher::CodePatcher(byte* address, int instructions)
: address_(address),
instructions_(instructions),
size_(instructions * Assembler::kInstrSize),
- masm_(Isolate::Current(), address, size_ + Assembler::kGap) {
+ masm_(NULL, address, size_ + Assembler::kGap) {
// Create a new macro assembler pointing to the address of the code to patch.
// The size is adjusted with kGap on order for the assembler to generate size
// bytes of instructions without failing with buffer size constraints.
diff --git a/src/3rdparty/v8/src/mips/macro-assembler-mips.h b/src/3rdparty/v8/src/mips/macro-assembler-mips.h
index b5897e4..f57418f 100644
--- a/src/3rdparty/v8/src/mips/macro-assembler-mips.h
+++ b/src/3rdparty/v8/src/mips/macro-assembler-mips.h
@@ -112,11 +112,6 @@ inline MemOperand GlobalObjectOperand() {
}
-static inline MemOperand QmlGlobalObjectOperand() {
- return ContextOperand(cp, Context::QML_GLOBAL_INDEX);
-}
-
-
// Generate a MemOperand for loading a field from an object.
inline MemOperand FieldMemOperand(Register object, int offset) {
return MemOperand(object, offset - kHeapObjectTag);
diff --git a/src/3rdparty/v8/src/mips/regexp-macro-assembler-mips.cc b/src/3rdparty/v8/src/mips/regexp-macro-assembler-mips.cc
index dde4a65..c48bcc4 100644
--- a/src/3rdparty/v8/src/mips/regexp-macro-assembler-mips.cc
+++ b/src/3rdparty/v8/src/mips/regexp-macro-assembler-mips.cc
@@ -158,7 +158,7 @@ int RegExpMacroAssemblerMIPS::stack_limit_slack() {
void RegExpMacroAssemblerMIPS::AdvanceCurrentPosition(int by) {
if (by != 0) {
__ Addu(current_input_offset(),
- current_input_offset(), Operand(by * char_size()));
+ current_input_offset(), Operand(by * char_size()));
}
}
@@ -229,9 +229,9 @@ void RegExpMacroAssemblerMIPS::CheckCharacterLT(uc16 limit, Label* on_less) {
void RegExpMacroAssemblerMIPS::CheckCharacters(Vector<const uc16> str,
- int cp_offset,
- Label* on_failure,
- bool check_end_of_string) {
+ int cp_offset,
+ Label* on_failure,
+ bool check_end_of_string) {
if (on_failure == NULL) {
// Instead of inlining a backtrack for each test, (re)use the global
// backtrack target.
@@ -452,24 +452,26 @@ void RegExpMacroAssemblerMIPS::CheckNotRegistersEqual(int reg1,
void RegExpMacroAssemblerMIPS::CheckNotCharacter(uint32_t c,
- Label* on_not_equal) {
+ Label* on_not_equal) {
BranchOrBacktrack(on_not_equal, ne, current_character(), Operand(c));
}
void RegExpMacroAssemblerMIPS::CheckCharacterAfterAnd(uint32_t c,
- uint32_t mask,
- Label* on_equal) {
+ uint32_t mask,
+ Label* on_equal) {
__ And(a0, current_character(), Operand(mask));
- BranchOrBacktrack(on_equal, eq, a0, Operand(c));
+ Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c);
+ BranchOrBacktrack(on_equal, eq, a0, rhs);
}
void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterAnd(uint32_t c,
- uint32_t mask,
- Label* on_not_equal) {
+ uint32_t mask,
+ Label* on_not_equal) {
__ And(a0, current_character(), Operand(mask));
- BranchOrBacktrack(on_not_equal, ne, a0, Operand(c));
+ Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c);
+ BranchOrBacktrack(on_not_equal, ne, a0, rhs);
}
@@ -478,7 +480,10 @@ void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterMinusAnd(
uc16 minus,
uc16 mask,
Label* on_not_equal) {
- UNIMPLEMENTED_MIPS();
+ ASSERT(minus < String::kMaxUtf16CodeUnit);
+ __ Subu(a0, current_character(), Operand(minus));
+ __ And(a0, a0, Operand(mask));
+ BranchOrBacktrack(on_not_equal, ne, a0, Operand(c));
}
@@ -519,7 +524,7 @@ void RegExpMacroAssemblerMIPS::CheckBitInTable(
bool RegExpMacroAssemblerMIPS::CheckSpecialCharacterClass(uc16 type,
- Label* on_no_match) {
+ Label* on_no_match) {
// Range checks (c in min..max) are generally implemented by an unsigned
// (c - min) <= (max - min) check.
switch (type) {
@@ -884,23 +889,23 @@ void RegExpMacroAssemblerMIPS::GoTo(Label* to) {
void RegExpMacroAssemblerMIPS::IfRegisterGE(int reg,
- int comparand,
- Label* if_ge) {
+ int comparand,
+ Label* if_ge) {
__ lw(a0, register_location(reg));
BranchOrBacktrack(if_ge, ge, a0, Operand(comparand));
}
void RegExpMacroAssemblerMIPS::IfRegisterLT(int reg,
- int comparand,
- Label* if_lt) {
+ int comparand,
+ Label* if_lt) {
__ lw(a0, register_location(reg));
BranchOrBacktrack(if_lt, lt, a0, Operand(comparand));
}
void RegExpMacroAssemblerMIPS::IfRegisterEqPos(int reg,
- Label* if_eq) {
+ Label* if_eq) {
__ lw(a0, register_location(reg));
BranchOrBacktrack(if_eq, eq, a0, Operand(current_input_offset()));
}
@@ -913,9 +918,9 @@ RegExpMacroAssembler::IrregexpImplementation
void RegExpMacroAssemblerMIPS::LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds,
- int characters) {
+ Label* on_end_of_input,
+ bool check_bounds,
+ int characters) {
ASSERT(cp_offset >= -1); // ^ and \b can look behind one character.
ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works).
if (check_bounds) {
@@ -966,7 +971,7 @@ void RegExpMacroAssemblerMIPS::PushCurrentPosition() {
void RegExpMacroAssemblerMIPS::PushRegister(int register_index,
- StackCheckFlag check_stack_limit) {
+ StackCheckFlag check_stack_limit) {
__ lw(a0, register_location(register_index));
Push(a0);
if (check_stack_limit) CheckStackLimit();
@@ -1013,7 +1018,7 @@ void RegExpMacroAssemblerMIPS::Succeed() {
void RegExpMacroAssemblerMIPS::WriteCurrentPositionToRegister(int reg,
- int cp_offset) {
+ int cp_offset) {
if (cp_offset == 0) {
__ sw(current_input_offset(), register_location(reg));
} else {
@@ -1170,7 +1175,7 @@ MemOperand RegExpMacroAssemblerMIPS::register_location(int register_index) {
void RegExpMacroAssemblerMIPS::CheckPosition(int cp_offset,
- Label* on_outside_input) {
+ Label* on_outside_input) {
BranchOrBacktrack(on_outside_input,
ge,
current_input_offset(),
@@ -1198,8 +1203,10 @@ void RegExpMacroAssemblerMIPS::BranchOrBacktrack(Label* to,
}
-void RegExpMacroAssemblerMIPS::SafeCall(Label* to, Condition cond, Register rs,
- const Operand& rt) {
+void RegExpMacroAssemblerMIPS::SafeCall(Label* to,
+ Condition cond,
+ Register rs,
+ const Operand& rt) {
__ BranchAndLink(to, cond, rs, rt);
}
@@ -1270,7 +1277,7 @@ void RegExpMacroAssemblerMIPS::CallCFunctionUsingStub(
void RegExpMacroAssemblerMIPS::LoadCurrentCharacterUnchecked(int cp_offset,
- int characters) {
+ int characters) {
Register offset = current_input_offset();
if (cp_offset != 0) {
__ Addu(a0, current_input_offset(), Operand(cp_offset * char_size()));
diff --git a/src/3rdparty/v8/src/mips/stub-cache-mips.cc b/src/3rdparty/v8/src/mips/stub-cache-mips.cc
index ec63fb6..18a5f5f 100644
--- a/src/3rdparty/v8/src/mips/stub-cache-mips.cc
+++ b/src/3rdparty/v8/src/mips/stub-cache-mips.cc
@@ -429,8 +429,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
// a0 : value.
Label exit;
// Check that the map of the object hasn't changed.
+ CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
+ : REQUIRE_EXACT_MAP;
__ CheckMap(receiver_reg, scratch, Handle<Map>(object->map()), miss_label,
- DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ DO_SMI_CHECK, mode);
// Perform global security token check if needed.
if (object->IsJSGlobalProxy()) {
@@ -563,6 +565,8 @@ static void PushInterceptorArguments(MacroAssembler* masm,
__ Push(scratch, receiver, holder);
__ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
__ push(scratch);
+ __ li(scratch, Operand(ExternalReference::isolate_address()));
+ __ push(scratch);
}
@@ -577,7 +581,7 @@ static void CompileCallLoadPropertyWithInterceptor(
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
masm->isolate());
- __ PrepareCEntryArgs(5);
+ __ PrepareCEntryArgs(6);
__ PrepareCEntryFunction(ref);
CEntryStub stub(1);
@@ -585,10 +589,10 @@ static void CompileCallLoadPropertyWithInterceptor(
}
-static const int kFastApiCallArguments = 3;
+static const int kFastApiCallArguments = 4;
-// Reserves space for the extra arguments to FastHandleApiCall in the
+// Reserves space for the extra arguments to API function in the
// caller's frame.
//
// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
@@ -614,7 +618,8 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
// -- sp[0] : holder (set by CheckPrototypes)
// -- sp[4] : callee JS function
// -- sp[8] : call data
- // -- sp[12] : last JS argument
+ // -- sp[12] : isolate
+ // -- sp[16] : last JS argument
// -- ...
// -- sp[(argc + 3) * 4] : first JS argument
// -- sp[(argc + 4) * 4] : receiver
@@ -624,7 +629,7 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
__ LoadHeapObject(t1, function);
__ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
- // Pass the additional arguments FastHandleApiCall expects.
+ // Pass the additional arguments.
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Handle<Object> call_data(api_call_info->data());
if (masm->isolate()->heap()->InNewSpace(*call_data)) {
@@ -634,14 +639,17 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
__ li(t2, call_data);
}
- // Store JS function and call data.
+ __ li(t3, Operand(ExternalReference::isolate_address()));
+ // Store JS function, call data and isolate.
__ sw(t1, MemOperand(sp, 1 * kPointerSize));
__ sw(t2, MemOperand(sp, 2 * kPointerSize));
+ __ sw(t3, MemOperand(sp, 3 * kPointerSize));
- // a2 points to call data as expected by Arguments
- // (refer to layout above).
- __ Addu(a2, sp, Operand(2 * kPointerSize));
+ // Prepare arguments.
+ __ Addu(a2, sp, Operand(3 * kPointerSize));
+ // Allocate the v8::Arguments structure in the arguments' space since
+ // it's not controlled by GC.
const int kApiStackSpace = 4;
FrameScope frame_scope(masm, StackFrame::MANUAL);
@@ -656,9 +664,9 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
// Arguments is built at sp + 1 (sp is a reserved spot for ra).
__ Addu(a1, sp, kPointerSize);
- // v8::Arguments::implicit_args = data
+ // v8::Arguments::implicit_args_
__ sw(a2, MemOperand(a1, 0 * kPointerSize));
- // v8::Arguments::values = last argument
+ // v8::Arguments::values_
__ Addu(t0, a2, Operand(argc * kPointerSize));
__ sw(t0, MemOperand(a1, 1 * kPointerSize));
// v8::Arguments::length_ = argc
@@ -836,7 +844,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
masm->isolate()),
- 5);
+ 6);
// Restore the name_ register.
__ pop(name_);
// Leave the internal frame.
@@ -1204,7 +1212,13 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
} else {
__ li(scratch3, Handle<Object>(callback->data()));
}
- __ Push(reg, scratch3, name_reg);
+ __ Subu(sp, sp, 4 * kPointerSize);
+ __ sw(reg, MemOperand(sp, 3 * kPointerSize));
+ __ sw(scratch3, MemOperand(sp, 2 * kPointerSize));
+ __ li(scratch3, Operand(ExternalReference::isolate_address()));
+ __ sw(scratch3, MemOperand(sp, 1 * kPointerSize));
+ __ sw(name_reg, MemOperand(sp, 0 * kPointerSize));
+
__ mov(a2, scratch2); // Saved in case scratch2 == a1.
__ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
@@ -1223,7 +1237,7 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
// a2 (second argument - see note above) = AccessorInfo&
__ Addu(a2, sp, kPointerSize);
- const int kStackUnwindSpace = 4;
+ const int kStackUnwindSpace = 5;
Address getter_address = v8::ToCData<Address>(callback->getter());
ApiFunction fun(getter_address);
ExternalReference ref =
@@ -1273,12 +1287,19 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
name, miss);
ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
+ // Preserve the receiver register explicitly whenever it is different from
+ // the holder and it is needed should the interceptor return without any
+ // result. The CALLBACKS case needs the receiver to be passed into C++ code,
+ // the FIELD case might cause a miss during the prototype check.
+ bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
+ bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
+ (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
+
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
{
FrameScope frame_scope(masm(), StackFrame::INTERNAL);
- if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
- // CALLBACKS case needs a receiver to be passed into C++ callback.
+ if (must_preserve_receiver_reg) {
__ Push(receiver, holder_reg, name_reg);
} else {
__ Push(holder_reg, name_reg);
@@ -1302,14 +1323,14 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
__ bind(&interceptor_failed);
__ pop(name_reg);
__ pop(holder_reg);
- if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
+ if (must_preserve_receiver_reg) {
__ pop(receiver);
}
// Leave the internal frame.
}
// Check that the maps from interceptor's holder to lookup's holder
// haven't changed. And load lookup's holder into |holder| register.
- if (*interceptor_holder != lookup->holder()) {
+ if (must_perfrom_prototype_check) {
holder_reg = CheckPrototypes(interceptor_holder,
holder_reg,
Handle<JSObject>(lookup->holder()),
@@ -1339,24 +1360,17 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
// Important invariant in CALLBACKS case: the code above must be
// structured to never clobber |receiver| register.
__ li(scratch2, callback);
- // holder_reg is either receiver or scratch1.
- if (!receiver.is(holder_reg)) {
- ASSERT(scratch1.is(holder_reg));
- __ Push(receiver, holder_reg);
- __ lw(scratch3,
- FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
- __ Push(scratch3, scratch2, name_reg);
- } else {
- __ push(receiver);
- __ lw(scratch3,
- FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
- __ Push(holder_reg, scratch3, scratch2, name_reg);
- }
+
+ __ Push(receiver, holder_reg);
+ __ lw(scratch3,
+ FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
+ __ li(scratch1, Operand(ExternalReference::isolate_address()));
+ __ Push(scratch3, scratch1, scratch2, name_reg);
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
masm()->isolate());
- __ TailCallExternalReference(ref, 5, 1);
+ __ TailCallExternalReference(ref, 6, 1);
}
} else { // !compile_followup_inline
// Call the runtime system to load the interceptor.
@@ -1369,7 +1383,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
ExternalReference ref = ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
- __ TailCallExternalReference(ref, 5, 1);
+ __ TailCallExternalReference(ref, 6, 1);
}
}
@@ -3370,6 +3384,45 @@ static bool IsElementTypeSigned(ElementsKind elements_kind) {
}
+static void GenerateSmiKeyCheck(MacroAssembler* masm,
+ Register key,
+ Register scratch0,
+ Register scratch1,
+ FPURegister double_scratch0,
+ Label* fail) {
+ if (CpuFeatures::IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+ Label key_ok;
+ // Check for smi or a smi inside a heap number. We convert the heap
+ // number and check if the conversion is exact and fits into the smi
+ // range.
+ __ JumpIfSmi(key, &key_ok);
+ __ CheckMap(key,
+ scratch0,
+ Heap::kHeapNumberMapRootIndex,
+ fail,
+ DONT_DO_SMI_CHECK);
+ __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
+ __ EmitFPUTruncate(kRoundToZero,
+ double_scratch0,
+ double_scratch0,
+ scratch0,
+ scratch1,
+ kCheckForInexactConversion);
+
+ __ Branch(fail, ne, scratch1, Operand(zero_reg));
+
+ __ mfc1(scratch0, double_scratch0);
+ __ SmiTagCheckOverflow(key, scratch0, scratch1);
+ __ BranchOnOverflow(fail, scratch1);
+ __ bind(&key_ok);
+ } else {
+ // Check that the key is a smi.
+ __ JumpIfNotSmi(key, fail);
+ }
+}
+
+
void KeyedLoadStubCompiler::GenerateLoadExternalArray(
MacroAssembler* masm,
ElementsKind elements_kind) {
@@ -3386,8 +3439,8 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
__ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// a3: elements array
@@ -3725,8 +3778,8 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
__ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
@@ -4105,9 +4158,8 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(a0, &miss_force_generic, at, USE_DELAY_SLOT);
- // The delay slot can be safely used here, a1 is an object pointer.
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, a0, t0, t1, f2, &miss_force_generic);
// Get the elements array.
__ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
@@ -4157,8 +4209,8 @@ void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(key_reg, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
// Get the elements array.
__ lw(elements_reg,
@@ -4231,8 +4283,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(key_reg, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
__ JumpIfNotSmi(value_reg, &transition_elements_kind);
@@ -4398,7 +4450,9 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- __ JumpIfNotSmi(key_reg, &miss_force_generic);
+
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
__ lw(elements_reg,
FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
@@ -4490,6 +4544,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
// Increment the length of the array.
__ li(length_reg, Operand(Smi::FromInt(1)));
__ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
+ __ lw(elements_reg,
+ FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
__ jmp(&finish_store);
__ bind(&check_capacity);
diff --git a/src/3rdparty/v8/src/mirror-debugger.js b/src/3rdparty/v8/src/mirror-debugger.js
index c43dd22..c7f0dcc 100644
--- a/src/3rdparty/v8/src/mirror-debugger.js
+++ b/src/3rdparty/v8/src/mirror-debugger.js
@@ -596,6 +596,23 @@ ObjectMirror.prototype.protoObject = function() {
};
+/**
+ * Return the primitive value if this is object of Boolean, Number or String
+ * type (but not Date). Otherwise return undefined.
+ */
+ObjectMirror.prototype.primitiveValue = function() {
+ if (!IS_STRING_WRAPPER(this.value_) && !IS_NUMBER_WRAPPER(this.value_) &&
+ !IS_BOOLEAN_WRAPPER(this.value_)) {
+ return void 0;
+ }
+ var primitiveValue = %_ValueOf(this.value_);
+ if (IS_UNDEFINED(primitiveValue)) {
+ return void 0;
+ }
+ return MakeMirror(primitiveValue);
+};
+
+
ObjectMirror.prototype.hasNamedInterceptor = function() {
// Get information on interceptors for this object.
var x = %GetInterceptorInfo(this.value_);
@@ -896,6 +913,22 @@ FunctionMirror.prototype.constructedBy = function(opt_max_instances) {
};
+FunctionMirror.prototype.scopeCount = function() {
+ if (this.resolved()) {
+ return %GetFunctionScopeCount(this.value());
+ } else {
+ return 0;
+ }
+};
+
+
+FunctionMirror.prototype.scope = function(index) {
+ if (this.resolved()) {
+ return new ScopeMirror(void 0, this, index);
+ }
+};
+
+
FunctionMirror.prototype.toText = function() {
return this.source();
};
@@ -1572,7 +1605,7 @@ FrameMirror.prototype.scopeCount = function() {
FrameMirror.prototype.scope = function(index) {
- return new ScopeMirror(this, index);
+ return new ScopeMirror(this, void 0, index);
};
@@ -1735,39 +1768,54 @@ FrameMirror.prototype.toText = function(opt_locals) {
var kScopeDetailsTypeIndex = 0;
var kScopeDetailsObjectIndex = 1;
-function ScopeDetails(frame, index) {
- this.break_id_ = frame.break_id_;
- this.details_ = %GetScopeDetails(frame.break_id_,
- frame.details_.frameId(),
- frame.details_.inlinedFrameIndex(),
- index);
+function ScopeDetails(frame, fun, index) {
+ if (frame) {
+ this.break_id_ = frame.break_id_;
+ this.details_ = %GetScopeDetails(frame.break_id_,
+ frame.details_.frameId(),
+ frame.details_.inlinedFrameIndex(),
+ index);
+ } else {
+ this.details_ = %GetFunctionScopeDetails(fun.value(), index);
+ this.break_id_ = undefined;
+ }
}
ScopeDetails.prototype.type = function() {
- %CheckExecutionState(this.break_id_);
+ if (!IS_UNDEFINED(this.break_id_)) {
+ %CheckExecutionState(this.break_id_);
+ }
return this.details_[kScopeDetailsTypeIndex];
};
ScopeDetails.prototype.object = function() {
- %CheckExecutionState(this.break_id_);
+ if (!IS_UNDEFINED(this.break_id_)) {
+ %CheckExecutionState(this.break_id_);
+ }
return this.details_[kScopeDetailsObjectIndex];
};
/**
- * Mirror object for scope.
+ * Mirror object for scope of frame or function. Either frame or function must
+ * be specified.
* @param {FrameMirror} frame The frame this scope is a part of
+ * @param {FunctionMirror} function The function this scope is a part of
* @param {number} index The scope index in the frame
* @constructor
* @extends Mirror
*/
-function ScopeMirror(frame, index) {
+function ScopeMirror(frame, function, index) {
%_CallFunction(this, SCOPE_TYPE, Mirror);
- this.frame_index_ = frame.index_;
+ if (frame) {
+ this.frame_index_ = frame.index_;
+ } else {
+ this.frame_index_ = undefined;
+ }
this.scope_index_ = index;
- this.details_ = new ScopeDetails(frame, index);
+ this.details_ = new ScopeDetails(frame, function, index);
}
inherits(ScopeMirror, Mirror);
@@ -2234,6 +2282,11 @@ JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
content.protoObject = this.serializeReference(mirror.protoObject());
content.prototypeObject = this.serializeReference(mirror.prototypeObject());
+ var primitiveValue = mirror.primitiveValue();
+ if (!IS_UNDEFINED(primitiveValue)) {
+ content.primitiveValue = this.serializeReference(primitiveValue);
+ }
+
// Add flags to indicate whether there are interceptors.
if (mirror.hasNamedInterceptor()) {
content.namedInterceptor = true;
@@ -2259,6 +2312,15 @@ JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
serializeLocationFields(mirror.sourceLocation(), content);
}
+
+ content.scopes = [];
+ for (var i = 0; i < mirror.scopeCount(); i++) {
+ var scope = mirror.scope(i);
+ content.scopes.push({
+ type: scope.scopeType(),
+ index: i
+ });
+ }
}
// Add date specific properties.
diff --git a/src/3rdparty/v8/src/objects-debug.cc b/src/3rdparty/v8/src/objects-debug.cc
index 8eefb23..9006abd 100644
--- a/src/3rdparty/v8/src/objects-debug.cc
+++ b/src/3rdparty/v8/src/objects-debug.cc
@@ -135,6 +135,9 @@ void HeapObject::HeapObjectVerify() {
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
JSObject::cast(this)->JSObjectVerify();
break;
+ case JS_MODULE_TYPE:
+ JSModule::cast(this)->JSModuleVerify();
+ break;
case JS_VALUE_TYPE:
JSValue::cast(this)->JSValueVerify();
break;
@@ -300,6 +303,8 @@ void Map::MapVerify() {
instance_size() < HEAP->Capacity()));
VerifyHeapPointer(prototype());
VerifyHeapPointer(instance_descriptors());
+ SLOW_ASSERT(instance_descriptors()->IsSortedNoDuplicates());
+ SLOW_ASSERT(instance_descriptors()->IsConsistentWithBackPointers(this));
}
@@ -366,6 +371,15 @@ void FixedDoubleArray::FixedDoubleArrayVerify() {
}
+void JSModule::JSModuleVerify() {
+ Object* v = context();
+ if (v->IsHeapObject()) {
+ VerifyHeapPointer(v);
+ }
+ CHECK(v->IsUndefined() || v->IsModuleContext());
+}
+
+
void JSValue::JSValueVerify() {
Object* v = value();
if (v->IsHeapObject()) {
@@ -882,6 +896,61 @@ bool DescriptorArray::IsSortedNoDuplicates() {
}
+static bool CheckOneBackPointer(Map* current_map, Object* target) {
+ return !target->IsMap() || Map::cast(target)->GetBackPointer() == current_map;
+}
+
+
+bool DescriptorArray::IsConsistentWithBackPointers(Map* current_map) {
+ for (int i = 0; i < number_of_descriptors(); ++i) {
+ switch (GetType(i)) {
+ case MAP_TRANSITION:
+ case CONSTANT_TRANSITION:
+ if (!CheckOneBackPointer(current_map, GetValue(i))) {
+ return false;
+ }
+ break;
+ case ELEMENTS_TRANSITION: {
+ Object* object = GetValue(i);
+ if (!CheckOneBackPointer(current_map, object)) {
+ return false;
+ }
+ if (object->IsFixedArray()) {
+ FixedArray* array = FixedArray::cast(object);
+ for (int i = 0; i < array->length(); ++i) {
+ if (!CheckOneBackPointer(current_map, array->get(i))) {
+ return false;
+ }
+ }
+ }
+ break;
+ }
+ case CALLBACKS: {
+ Object* object = GetValue(i);
+ if (object->IsAccessorPair()) {
+ AccessorPair* accessors = AccessorPair::cast(object);
+ if (!CheckOneBackPointer(current_map, accessors->getter())) {
+ return false;
+ }
+ if (!CheckOneBackPointer(current_map, accessors->setter())) {
+ return false;
+ }
+ }
+ break;
+ }
+ case NORMAL:
+ case FIELD:
+ case CONSTANT_FUNCTION:
+ case HANDLER:
+ case INTERCEPTOR:
+ case NULL_DESCRIPTOR:
+ break;
+ }
+ }
+ return true;
+}
+
+
void JSFunctionResultCache::JSFunctionResultCacheVerify() {
JSFunction::cast(get(kFactoryIndex))->Verify();
@@ -923,6 +992,28 @@ void NormalizedMapCache::NormalizedMapCacheVerify() {
}
+void Map::ZapInstanceDescriptors() {
+ DescriptorArray* descriptors = instance_descriptors();
+ if (descriptors == GetHeap()->empty_descriptor_array()) return;
+ FixedArray* contents = FixedArray::cast(
+ descriptors->get(DescriptorArray::kContentArrayIndex));
+ MemsetPointer(descriptors->data_start(),
+ GetHeap()->the_hole_value(),
+ descriptors->length());
+ MemsetPointer(contents->data_start(),
+ GetHeap()->the_hole_value(),
+ contents->length());
+}
+
+
+void Map::ZapPrototypeTransitions() {
+ FixedArray* proto_transitions = prototype_transitions();
+ MemsetPointer(proto_transitions->data_start(),
+ GetHeap()->the_hole_value(),
+ proto_transitions->length());
+}
+
+
#endif // DEBUG
} } // namespace v8::internal
diff --git a/src/3rdparty/v8/src/objects-inl.h b/src/3rdparty/v8/src/objects-inl.h
index f29cf6e..5444438 100644
--- a/src/3rdparty/v8/src/objects-inl.h
+++ b/src/3rdparty/v8/src/objects-inl.h
@@ -581,7 +581,8 @@ bool Object::IsContext() {
map == heap->catch_context_map() ||
map == heap->with_context_map() ||
map == heap->global_context_map() ||
- map == heap->block_context_map());
+ map == heap->block_context_map() ||
+ map == heap->module_context_map());
}
return false;
}
@@ -594,6 +595,13 @@ bool Object::IsGlobalContext() {
}
+bool Object::IsModuleContext() {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map() ==
+ HeapObject::cast(this)->GetHeap()->module_context_map();
+}
+
+
bool Object::IsScopeInfo() {
return Object::IsHeapObject() &&
HeapObject::cast(this)->map() ==
@@ -613,6 +621,7 @@ TYPE_CHECKER(Code, CODE_TYPE)
TYPE_CHECKER(Oddball, ODDBALL_TYPE)
TYPE_CHECKER(JSGlobalPropertyCell, JS_GLOBAL_PROPERTY_CELL_TYPE)
TYPE_CHECKER(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE)
+TYPE_CHECKER(JSModule, JS_MODULE_TYPE)
TYPE_CHECKER(JSValue, JS_VALUE_TYPE)
TYPE_CHECKER(JSDate, JS_DATE_TYPE)
TYPE_CHECKER(JSMessageObject, JS_MESSAGE_OBJECT_TYPE)
@@ -1383,7 +1392,9 @@ void JSObject::initialize_properties() {
void JSObject::initialize_elements() {
- ASSERT(map()->has_fast_elements() || map()->has_fast_smi_only_elements());
+ ASSERT(map()->has_fast_elements() ||
+ map()->has_fast_smi_only_elements() ||
+ map()->has_fast_double_elements());
ASSERT(!GetHeap()->InNewSpace(GetHeap()->empty_fixed_array()));
WRITE_FIELD(this, kElementsOffset, GetHeap()->empty_fixed_array());
}
@@ -1436,6 +1447,8 @@ int JSObject::GetHeaderSize() {
// field operations considerably on average.
if (type == JS_OBJECT_TYPE) return JSObject::kHeaderSize;
switch (type) {
+ case JS_MODULE_TYPE:
+ return JSModule::kSize;
case JS_GLOBAL_PROXY_TYPE:
return JSGlobalProxy::kSize;
case JS_GLOBAL_OBJECT_TYPE:
@@ -1470,7 +1483,7 @@ int JSObject::GetInternalFieldCount() {
// Make sure to adjust for the number of in-object properties. These
// properties do contribute to the size, but are not internal fields.
return ((Size() - GetHeaderSize()) >> kPointerSizeLog2) -
- map()->inobject_properties() - (map()->has_external_resource()?1:0);
+ map()->inobject_properties();
}
@@ -1510,23 +1523,6 @@ void JSObject::SetInternalField(int index, Smi* value) {
}
-void JSObject::SetExternalResourceObject(Object *value) {
- ASSERT(map()->has_external_resource());
- int offset = GetHeaderSize() + kPointerSize * GetInternalFieldCount();
- WRITE_FIELD(this, offset, value);
- WRITE_BARRIER(GetHeap(), this, offset, value);
-}
-
-
-Object *JSObject::GetExternalResourceObject() {
- if (map()->has_external_resource()) {
- return READ_FIELD(this, GetHeaderSize() + kPointerSize * GetInternalFieldCount());
- } else {
- return GetHeap()->undefined_value();
- }
-}
-
-
// Access fast-case object properties at index. The use of these routines
// is needed to correctly distinguish between properties stored in-object and
// properties stored in the properties array.
@@ -1939,15 +1935,15 @@ Object* DescriptorArray::GetValue(int descriptor_number) {
}
-Smi* DescriptorArray::GetDetails(int descriptor_number) {
+PropertyDetails DescriptorArray::GetDetails(int descriptor_number) {
ASSERT(descriptor_number < number_of_descriptors());
- return Smi::cast(GetContentArray()->get(ToDetailsIndex(descriptor_number)));
+ Object* details = GetContentArray()->get(ToDetailsIndex(descriptor_number));
+ return PropertyDetails(Smi::cast(details));
}
PropertyType DescriptorArray::GetType(int descriptor_number) {
- ASSERT(descriptor_number < number_of_descriptors());
- return PropertyDetails(GetDetails(descriptor_number)).type();
+ return GetDetails(descriptor_number).type();
}
@@ -2010,15 +2006,10 @@ bool DescriptorArray::IsNullDescriptor(int descriptor_number) {
}
-bool DescriptorArray::IsDontEnum(int descriptor_number) {
- return PropertyDetails(GetDetails(descriptor_number)).IsDontEnum();
-}
-
-
void DescriptorArray::Get(int descriptor_number, Descriptor* desc) {
desc->Init(GetKey(descriptor_number),
GetValue(descriptor_number),
- PropertyDetails(GetDetails(descriptor_number)));
+ GetDetails(descriptor_number));
}
@@ -2206,7 +2197,6 @@ SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
SMI_ACCESSORS(FreeSpace, size, kSizeOffset)
SMI_ACCESSORS(String, length, kLengthOffset)
-SMI_ACCESSORS(SeqString, symbol_id, kSymbolIdOffset)
uint32_t String::hash_field() {
@@ -2908,14 +2898,14 @@ bool Map::is_extensible() {
void Map::set_attached_to_shared_function_info(bool value) {
if (value) {
- set_bit_field3(bit_field3() | (1 << kAttachedToSharedFunctionInfo));
+ set_bit_field2(bit_field2() | (1 << kAttachedToSharedFunctionInfo));
} else {
- set_bit_field3(bit_field3() & ~(1 << kAttachedToSharedFunctionInfo));
+ set_bit_field2(bit_field2() & ~(1 << kAttachedToSharedFunctionInfo));
}
}
bool Map::attached_to_shared_function_info() {
- return ((1 << kAttachedToSharedFunctionInfo) & bit_field3()) != 0;
+ return ((1 << kAttachedToSharedFunctionInfo) & bit_field2()) != 0;
}
@@ -2931,46 +2921,6 @@ bool Map::is_shared() {
return ((1 << kIsShared) & bit_field3()) != 0;
}
-void Map::set_has_external_resource(bool value) {
- if (value) {
- set_bit_field(bit_field() | (1 << kHasExternalResource));
- } else {
- set_bit_field(bit_field() & ~(1 << kHasExternalResource));
- }
-}
-
-bool Map::has_external_resource()
-{
- return ((1 << kHasExternalResource) & bit_field()) != 0;
-}
-
-
-void Map::set_use_user_object_comparison(bool value) {
- if (value) {
- set_bit_field2(bit_field2() | (1 << kUseUserObjectComparison));
- } else {
- set_bit_field2(bit_field2() & ~(1 << kUseUserObjectComparison));
- }
-}
-
-
-bool Map::use_user_object_comparison() {
- return ((1 << kUseUserObjectComparison) & bit_field2()) != 0;
-}
-
-
-void Map::set_named_interceptor_is_fallback(bool value) {
- if (value) {
- set_bit_field3(bit_field3() | (1 << kNamedInterceptorIsFallback));
- } else {
- set_bit_field3(bit_field3() & ~(1 << kNamedInterceptorIsFallback));
- }
-}
-
-bool Map::named_interceptor_is_fallback() {
- return ((1 << kNamedInterceptorIsFallback) & bit_field3()) != 0;
-}
-
JSFunction* Map::unchecked_constructor() {
return reinterpret_cast<JSFunction*>(READ_FIELD(this, kConstructorOffset));
@@ -3243,6 +3193,18 @@ void Code::set_compare_state(byte value) {
}
+byte Code::compare_operation() {
+ ASSERT(is_compare_ic_stub());
+ return READ_BYTE_FIELD(this, kCompareOperationOffset);
+}
+
+
+void Code::set_compare_operation(byte value) {
+ ASSERT(is_compare_ic_stub());
+ WRITE_BYTE_FIELD(this, kCompareOperationOffset, value);
+}
+
+
byte Code::to_boolean_state() {
ASSERT(is_to_boolean_ic_stub());
return READ_BYTE_FIELD(this, kToBooleanTypeOffset);
@@ -3389,6 +3351,9 @@ void Map::clear_instance_descriptors() {
Object* object = READ_FIELD(this,
kInstanceDescriptorsOrBitField3Offset);
if (!object->IsSmi()) {
+#ifdef DEBUG
+ ZapInstanceDescriptors();
+#endif
WRITE_FIELD(
this,
kInstanceDescriptorsOrBitField3Offset,
@@ -3414,6 +3379,11 @@ void Map::set_instance_descriptors(DescriptorArray* value,
}
}
ASSERT(!is_shared());
+#ifdef DEBUG
+ if (value != instance_descriptors()) {
+ ZapInstanceDescriptors();
+ }
+#endif
WRITE_FIELD(this, kInstanceDescriptorsOrBitField3Offset, value);
CONDITIONAL_WRITE_BARRIER(
heap, this, kInstanceDescriptorsOrBitField3Offset, value, mode);
@@ -3445,14 +3415,71 @@ void Map::set_bit_field3(int value) {
}
-FixedArray* Map::unchecked_prototype_transitions() {
- return reinterpret_cast<FixedArray*>(
- READ_FIELD(this, kPrototypeTransitionsOffset));
+Object* Map::GetBackPointer() {
+ Object* object = READ_FIELD(this, kPrototypeTransitionsOrBackPointerOffset);
+ if (object->IsFixedArray()) {
+ return FixedArray::cast(object)->get(kProtoTransitionBackPointerOffset);
+ } else {
+ return object;
+ }
+}
+
+
+void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
+ Heap* heap = GetHeap();
+ ASSERT(instance_type() >= FIRST_JS_RECEIVER_TYPE);
+ ASSERT((value->IsUndefined() && GetBackPointer()->IsMap()) ||
+ (value->IsMap() && GetBackPointer()->IsUndefined()));
+ Object* object = READ_FIELD(this, kPrototypeTransitionsOrBackPointerOffset);
+ if (object->IsFixedArray()) {
+ FixedArray::cast(object)->set(
+ kProtoTransitionBackPointerOffset, value, mode);
+ } else {
+ WRITE_FIELD(this, kPrototypeTransitionsOrBackPointerOffset, value);
+ CONDITIONAL_WRITE_BARRIER(
+ heap, this, kPrototypeTransitionsOrBackPointerOffset, value, mode);
+ }
+}
+
+
+FixedArray* Map::prototype_transitions() {
+ Object* object = READ_FIELD(this, kPrototypeTransitionsOrBackPointerOffset);
+ if (object->IsFixedArray()) {
+ return FixedArray::cast(object);
+ } else {
+ return GetHeap()->empty_fixed_array();
+ }
+}
+
+
+void Map::set_prototype_transitions(FixedArray* value, WriteBarrierMode mode) {
+ Heap* heap = GetHeap();
+ ASSERT(value != heap->empty_fixed_array());
+ value->set(kProtoTransitionBackPointerOffset, GetBackPointer());
+#ifdef DEBUG
+ if (value != prototype_transitions()) {
+ ZapPrototypeTransitions();
+ }
+#endif
+ WRITE_FIELD(this, kPrototypeTransitionsOrBackPointerOffset, value);
+ CONDITIONAL_WRITE_BARRIER(
+ heap, this, kPrototypeTransitionsOrBackPointerOffset, value, mode);
+}
+
+
+void Map::init_prototype_transitions(Object* undefined) {
+ ASSERT(undefined->IsUndefined());
+ WRITE_FIELD(this, kPrototypeTransitionsOrBackPointerOffset, undefined);
+}
+
+
+HeapObject* Map::unchecked_prototype_transitions() {
+ Object* object = READ_FIELD(this, kPrototypeTransitionsOrBackPointerOffset);
+ return reinterpret_cast<HeapObject*>(object);
}
ACCESSORS(Map, code_cache, Object, kCodeCacheOffset)
-ACCESSORS(Map, prototype_transitions, FixedArray, kPrototypeTransitionsOffset)
ACCESSORS(Map, constructor, Object, kConstructorOffset)
ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
@@ -3487,7 +3514,6 @@ ACCESSORS(InterceptorInfo, query, Object, kQueryOffset)
ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset)
ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset)
ACCESSORS(InterceptorInfo, data, Object, kDataOffset)
-ACCESSORS(InterceptorInfo, is_fallback, Smi, kFallbackOffset)
ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset)
ACCESSORS(CallHandlerInfo, data, Object, kDataOffset)
@@ -3519,10 +3545,6 @@ ACCESSORS_TO_SMI(FunctionTemplateInfo, flag, kFlagOffset)
ACCESSORS(ObjectTemplateInfo, constructor, Object, kConstructorOffset)
ACCESSORS(ObjectTemplateInfo, internal_field_count, Object,
kInternalFieldCountOffset)
-ACCESSORS(ObjectTemplateInfo, has_external_resource, Object,
- kHasExternalResourceOffset)
-ACCESSORS(ObjectTemplateInfo, use_user_object_comparison, Object,
- kUseUserObjectComparisonOffset)
ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset)
ACCESSORS(SignatureInfo, args, Object, kArgsOffset)
@@ -3715,6 +3737,12 @@ void SharedFunctionInfo::set_optimization_disabled(bool disable) {
}
+int SharedFunctionInfo::profiler_ticks() {
+ if (code()->kind() != Code::FUNCTION) return 0;
+ return code()->profiler_ticks();
+}
+
+
LanguageMode SharedFunctionInfo::language_mode() {
int hints = compiler_hints();
if (BooleanBit::get(hints, kExtendedModeFunction)) {
@@ -3748,8 +3776,6 @@ bool SharedFunctionInfo::is_classic_mode() {
BOOL_GETTER(SharedFunctionInfo, compiler_hints, is_extended_mode,
kExtendedModeFunction)
-BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, qml_mode,
- kQmlModeFunction)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, native, kNative)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints,
name_should_print_as_anonymous,
@@ -4143,6 +4169,16 @@ void Foreign::set_foreign_address(Address value) {
}
+ACCESSORS(JSModule, context, Object, kContextOffset)
+
+
+JSModule* JSModule::cast(Object* obj) {
+ ASSERT(obj->IsJSModule());
+ ASSERT(HeapObject::cast(obj)->Size() == JSModule::kSize);
+ return reinterpret_cast<JSModule*>(obj);
+}
+
+
ACCESSORS(JSValue, value, Object, kValueOffset)
diff --git a/src/3rdparty/v8/src/objects-printer.cc b/src/3rdparty/v8/src/objects-printer.cc
index 2353a95..febdaab 100644
--- a/src/3rdparty/v8/src/objects-printer.cc
+++ b/src/3rdparty/v8/src/objects-printer.cc
@@ -135,6 +135,9 @@ void HeapObject::HeapObjectPrint(FILE* out) {
case ODDBALL_TYPE:
Oddball::cast(this)->to_string()->Print(out);
break;
+ case JS_MODULE_TYPE:
+ JSModule::cast(this)->JSModulePrint(out);
+ break;
case JS_FUNCTION_TYPE:
JSFunction::cast(this)->JSFunctionPrint(out);
break;
@@ -152,7 +155,7 @@ void HeapObject::HeapObjectPrint(FILE* out) {
JSValue::cast(this)->value()->Print(out);
break;
case JS_DATE_TYPE:
- JSDate::cast(this)->value()->Print(out);
+ JSDate::cast(this)->JSDatePrint(out);
break;
case CODE_TYPE:
Code::cast(this)->CodePrint(out);
@@ -328,14 +331,16 @@ void JSObject::PrintElements(FILE* out) {
}
case FAST_DOUBLE_ELEMENTS: {
// Print in array notation for non-sparse arrays.
- FixedDoubleArray* p = FixedDoubleArray::cast(elements());
- for (int i = 0; i < p->length(); i++) {
- if (p->is_the_hole(i)) {
- PrintF(out, " %d: <the hole>", i);
- } else {
- PrintF(out, " %d: %g", i, p->get_scalar(i));
+ if (elements()->length() > 0) {
+ FixedDoubleArray* p = FixedDoubleArray::cast(elements());
+ for (int i = 0; i < p->length(); i++) {
+ if (p->is_the_hole(i)) {
+ PrintF(out, " %d: <the hole>", i);
+ } else {
+ PrintF(out, " %d: %g", i, p->get_scalar(i));
+ }
+ PrintF(out, "\n");
}
- PrintF(out, "\n");
}
break;
}
@@ -437,6 +442,19 @@ void JSObject::JSObjectPrint(FILE* out) {
}
+void JSModule::JSModulePrint(FILE* out) {
+ HeapObject::PrintHeader(out, "JSModule");
+ PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - context = ");
+ context()->Print(out);
+ PrintElementsKind(out, this->map()->elements_kind());
+ PrintF(out, " {\n");
+ PrintProperties(out);
+ PrintElements(out);
+ PrintF(out, " }\n");
+}
+
+
static const char* TypeToString(InstanceType type) {
switch (type) {
case INVALID_TYPE: return "INVALID";
@@ -483,6 +501,7 @@ static const char* TypeToString(InstanceType type) {
case ODDBALL_TYPE: return "ODDBALL";
case JS_GLOBAL_PROPERTY_CELL_TYPE: return "JS_GLOBAL_PROPERTY_CELL";
case SHARED_FUNCTION_INFO_TYPE: return "SHARED_FUNCTION_INFO";
+ case JS_MODULE_TYPE: return "JS_MODULE";
case JS_FUNCTION_TYPE: return "JS_FUNCTION";
case CODE_TYPE: return "CODE";
case JS_ARRAY_TYPE: return "JS_ARRAY";
diff --git a/src/3rdparty/v8/src/objects-visiting-inl.h b/src/3rdparty/v8/src/objects-visiting-inl.h
index 627d1bc..8ba92f7 100644
--- a/src/3rdparty/v8/src/objects-visiting-inl.h
+++ b/src/3rdparty/v8/src/objects-visiting-inl.h
@@ -72,9 +72,7 @@ void StaticNewSpaceVisitor<StaticVisitor>::Initialize() {
table_.Register(kVisitSeqTwoByteString, &VisitSeqTwoByteString);
- table_.Register(kVisitJSFunction,
- &JSObjectVisitor::
- template VisitSpecialized<JSFunction::kSize>);
+ table_.Register(kVisitJSFunction, &VisitJSFunction);
table_.Register(kVisitFreeSpace, &VisitFreeSpace);
diff --git a/src/3rdparty/v8/src/objects-visiting.cc b/src/3rdparty/v8/src/objects-visiting.cc
index c7c8a87..a2dc43e 100644
--- a/src/3rdparty/v8/src/objects-visiting.cc
+++ b/src/3rdparty/v8/src/objects-visiting.cc
@@ -133,6 +133,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
case JS_OBJECT_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
+ case JS_MODULE_TYPE:
case JS_VALUE_TYPE:
case JS_DATE_TYPE:
case JS_ARRAY_TYPE:
diff --git a/src/3rdparty/v8/src/objects-visiting.h b/src/3rdparty/v8/src/objects-visiting.h
index 26e79ae..b476dfe 100644
--- a/src/3rdparty/v8/src/objects-visiting.h
+++ b/src/3rdparty/v8/src/objects-visiting.h
@@ -289,6 +289,23 @@ class StaticNewSpaceVisitor : public StaticVisitorBase {
}
private:
+ static inline int VisitJSFunction(Map* map, HeapObject* object) {
+ Heap* heap = map->GetHeap();
+ VisitPointers(heap,
+ HeapObject::RawField(object, JSFunction::kPropertiesOffset),
+ HeapObject::RawField(object, JSFunction::kCodeEntryOffset));
+
+ // Don't visit code entry. We are using this visitor only during scavenges.
+
+ VisitPointers(
+ heap,
+ HeapObject::RawField(object,
+ JSFunction::kCodeEntryOffset + kPointerSize),
+ HeapObject::RawField(object,
+ JSFunction::kNonWeakFieldsEndOffset));
+ return JSFunction::kSize;
+ }
+
static inline int VisitByteArray(Map* map, HeapObject* object) {
return reinterpret_cast<ByteArray*>(object)->ByteArraySize();
}
diff --git a/src/3rdparty/v8/src/objects.cc b/src/3rdparty/v8/src/objects.cc
index f7f2879..cb87c71 100644
--- a/src/3rdparty/v8/src/objects.cc
+++ b/src/3rdparty/v8/src/objects.cc
@@ -1338,6 +1338,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
break;
case JS_OBJECT_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
+ case JS_MODULE_TYPE:
case JS_VALUE_TYPE:
case JS_DATE_TYPE:
case JS_ARRAY_TYPE:
@@ -1603,6 +1604,7 @@ MaybeObject* JSObject::AddFastProperty(String* name,
// We have now allocated all the necessary objects.
// All the changes can be applied at once, so they are atomic.
map()->set_instance_descriptors(old_descriptors);
+ new_map->SetBackPointer(map());
new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
set_map(new_map);
return FastPropertyAtPut(index, value);
@@ -1663,6 +1665,7 @@ MaybeObject* JSObject::AddConstantFunctionProperty(
}
}
old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
+ Map::cast(new_map)->SetBackPointer(old_map);
return function;
}
@@ -1823,6 +1826,7 @@ MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
}
}
old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
+ map()->SetBackPointer(old_map);
return result;
}
@@ -1936,11 +1940,9 @@ Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
Handle<String> key,
Handle<Object> value,
PropertyAttributes attributes,
- StrictModeFlag strict_mode,
- bool skip_fallback_interceptor) {
+ StrictModeFlag strict_mode) {
CALL_HEAP_FUNCTION(object->GetIsolate(),
- object->SetProperty(*key, *value, attributes, strict_mode,
- skip_fallback_interceptor),
+ object->SetProperty(*key, *value, attributes, strict_mode),
Object);
}
@@ -1948,10 +1950,9 @@ Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
MaybeObject* JSReceiver::SetProperty(String* name,
Object* value,
PropertyAttributes attributes,
- StrictModeFlag strict_mode,
- bool skip_fallback_interceptor) {
+ StrictModeFlag strict_mode) {
LookupResult result(GetIsolate());
- LocalLookup(name, &result, skip_fallback_interceptor);
+ LocalLookup(name, &result);
return SetProperty(&result, name, value, attributes, strict_mode);
}
@@ -2324,7 +2325,7 @@ Object* Map::GetDescriptorContents(String* sentinel_name,
}
// If the transition already exists, return its descriptor.
if (index != DescriptorArray::kNotFound) {
- PropertyDetails details(descriptors->GetDetails(index));
+ PropertyDetails details = descriptors->GetDetails(index);
if (details.type() == ELEMENTS_TRANSITION) {
return descriptors->GetValue(index);
} else {
@@ -2410,6 +2411,7 @@ MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind,
return maybe_new_descriptors;
}
set_instance_descriptors(DescriptorArray::cast(new_descriptors));
+ transitioned_map->SetBackPointer(this);
return this;
}
@@ -3028,7 +3030,6 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
String* name,
Object* value,
PropertyAttributes attributes) {
-
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
AssertNoContextChange ncc;
@@ -3097,7 +3098,6 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
case HANDLER:
UNREACHABLE();
- return value;
}
UNREACHABLE(); // keep the compiler happy
return value;
@@ -3348,7 +3348,7 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
DescriptorArray* descs = map_of_this->instance_descriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
- PropertyDetails details(descs->GetDetails(i));
+ PropertyDetails details = descs->GetDetails(i);
switch (details.type()) {
case CONSTANT_FUNCTION: {
PropertyDetails d =
@@ -4210,7 +4210,7 @@ int Map::NumberOfDescribedProperties(PropertyAttributes filter) {
int result = 0;
DescriptorArray* descs = instance_descriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
- PropertyDetails details(descs->GetDetails(i));
+ PropertyDetails details = descs->GetDetails(i);
if (descs->IsProperty(i) && (details.attributes() & filter) == 0) {
result++;
}
@@ -4254,8 +4254,7 @@ AccessorDescriptor* Map::FindAccessor(String* name) {
}
-void JSReceiver::LocalLookup(String* name, LookupResult* result,
- bool skip_fallback_interceptor) {
+void JSReceiver::LocalLookup(String* name, LookupResult* result) {
ASSERT(name->IsString());
Heap* heap = GetHeap();
@@ -4287,33 +4286,23 @@ void JSReceiver::LocalLookup(String* name, LookupResult* result,
}
// Check for lookup interceptor except when bootstrapping.
- bool wouldIntercept = js_object->HasNamedInterceptor() &&
- !heap->isolate()->bootstrapper()->IsActive();
- if (wouldIntercept && !map()->named_interceptor_is_fallback()) {
+ if (js_object->HasNamedInterceptor() &&
+ !heap->isolate()->bootstrapper()->IsActive()) {
result->InterceptorResult(js_object);
return;
}
js_object->LocalLookupRealNamedProperty(name, result);
-
- if (wouldIntercept && !skip_fallback_interceptor && !result->IsProperty() &&
- map()->named_interceptor_is_fallback()) {
- result->InterceptorResult(js_object);
- return;
- }
}
-void JSReceiver::Lookup(String* name, LookupResult* result,
- bool skip_fallback_interceptor) {
+void JSReceiver::Lookup(String* name, LookupResult* result) {
// Ecma-262 3rd 8.6.2.4
Heap* heap = GetHeap();
for (Object* current = this;
current != heap->null_value();
current = JSObject::cast(current)->GetPrototype()) {
- JSReceiver::cast(current)->LocalLookup(name,
- result,
- skip_fallback_interceptor);
+ JSReceiver::cast(current)->LocalLookup(name, result);
if (result->IsProperty()) return;
}
result->NotFound();
@@ -4424,37 +4413,29 @@ MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
}
-MaybeObject* JSObject::DefinePropertyAccessor(String* name,
- Object* getter,
- Object* setter,
- PropertyAttributes attributes) {
- // Lookup the name.
+MaybeObject* JSObject::CreateAccessorPairFor(String* name) {
LookupResult result(GetHeap()->isolate());
LocalLookupRealNamedProperty(name, &result);
- if (result.IsFound()) {
- if (result.type() == CALLBACKS) {
- ASSERT(!result.IsDontDelete());
- Object* obj = result.GetCallbackObject();
- // Need to preserve old getters/setters.
- if (obj->IsAccessorPair()) {
- AccessorPair* copy;
- { MaybeObject* maybe_copy =
- AccessorPair::cast(obj)->CopyWithoutTransitions();
- if (!maybe_copy->To(&copy)) return maybe_copy;
- }
- copy->SetComponents(getter, setter);
- // Use set to update attributes.
- return SetPropertyCallback(name, copy, attributes);
- }
+ if (result.IsProperty() && result.type() == CALLBACKS) {
+ ASSERT(!result.IsDontDelete());
+ Object* obj = result.GetCallbackObject();
+ if (obj->IsAccessorPair()) {
+ return AccessorPair::cast(obj)->CopyWithoutTransitions();
}
}
+ return GetHeap()->AllocateAccessorPair();
+}
+
+MaybeObject* JSObject::DefinePropertyAccessor(String* name,
+ Object* getter,
+ Object* setter,
+ PropertyAttributes attributes) {
AccessorPair* accessors;
- { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
+ { MaybeObject* maybe_accessors = CreateAccessorPairFor(name);
if (!maybe_accessors->To(&accessors)) return maybe_accessors;
}
accessors->SetComponents(getter, setter);
-
return SetPropertyCallback(name, accessors, attributes);
}
@@ -4982,7 +4963,7 @@ class IntrusiveMapTransitionIterator {
// underlying array while it is running.
class IntrusivePrototypeTransitionIterator {
public:
- explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans)
+ explicit IntrusivePrototypeTransitionIterator(HeapObject* proto_trans)
: proto_trans_(proto_trans) { }
void Start() {
@@ -5007,7 +4988,7 @@ class IntrusivePrototypeTransitionIterator {
private:
bool HasTransitions() {
- return proto_trans_->length() >= Map::kProtoTransitionHeaderSize;
+ return proto_trans_->map()->IsSmi() || proto_trans_->IsFixedArray();
}
Object** Header() {
@@ -5015,12 +4996,16 @@ class IntrusivePrototypeTransitionIterator {
}
int NumberOfTransitions() {
- Object* num = proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset);
+ ASSERT(HasTransitions());
+ FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
+ Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
return Smi::cast(num)->value();
}
Map* GetTransition(int transitionNumber) {
- return Map::cast(proto_trans_->get(IndexFor(transitionNumber)));
+ ASSERT(HasTransitions());
+ FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
+ return Map::cast(proto_trans->get(IndexFor(transitionNumber)));
}
int IndexFor(int transitionNumber) {
@@ -5029,7 +5014,7 @@ class IntrusivePrototypeTransitionIterator {
transitionNumber * Map::kProtoTransitionElementsPerEntry;
}
- FixedArray* proto_trans_;
+ HeapObject* proto_trans_;
};
@@ -5710,7 +5695,7 @@ MaybeObject* DescriptorArray::CopyFrom(int dst_index,
int src_index,
const WhitenessWitness& witness) {
Object* value = src->GetValue(src_index);
- PropertyDetails details(src->GetDetails(src_index));
+ PropertyDetails details = src->GetDetails(src_index);
if (details.type() == CALLBACKS && value->IsAccessorPair()) {
MaybeObject* maybe_copy =
AccessorPair::cast(value)->CopyWithoutTransitions();
@@ -5753,7 +5738,7 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
if (replacing) {
// We are replacing an existing descriptor. We keep the enumeration
// index of a visible property.
- PropertyType t = PropertyDetails(GetDetails(index)).type();
+ PropertyType t = GetDetails(index).type();
if (t == CONSTANT_FUNCTION ||
t == FIELD ||
t == CALLBACKS ||
@@ -5780,8 +5765,7 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
int enumeration_index = NextEnumerationIndex();
if (!descriptor->ContainsTransition()) {
if (keep_enumeration_index) {
- descriptor->SetEnumerationIndex(
- PropertyDetails(GetDetails(index)).index());
+ descriptor->SetEnumerationIndex(GetDetails(index).index());
} else {
descriptor->SetEnumerationIndex(enumeration_index);
++enumeration_index;
@@ -5925,10 +5909,10 @@ int DescriptorArray::BinarySearch(String* name, int low, int high) {
ASSERT(hash == mid_hash);
// There might be more, so we find the first one and
// check them all to see if we have a match.
- if (name == mid_name && !is_null_descriptor(mid)) return mid;
+ if (name == mid_name && !IsNullDescriptor(mid)) return mid;
while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
- if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
+ if (GetKey(mid)->Equals(name) && !IsNullDescriptor(mid)) return mid;
}
break;
}
@@ -5942,7 +5926,7 @@ int DescriptorArray::LinearSearch(String* name, int len) {
String* entry = GetKey(number);
if ((entry->Hash() == hash) &&
name->Equals(entry) &&
- !is_null_descriptor(number)) {
+ !IsNullDescriptor(number)) {
return number;
}
}
@@ -6870,72 +6854,6 @@ static inline bool CompareStringContentsPartial(Isolate* isolate,
}
-bool String::SlowEqualsExternal(uc16 *string, int length) {
- int len = this->length();
- if (len != length) return false;
- if (len == 0) return true;
-
- // We know the strings are both non-empty. Compare the first chars
- // before we try to flatten the strings.
- if (this->Get(0) != string[0]) return false;
-
- String* lhs = this->TryFlattenGetString();
-
- if (lhs->IsFlat()) {
- String::FlatContent lhs_content = lhs->GetFlatContent();
- if (lhs->IsAsciiRepresentation()) {
- Vector<const char> vec1 = lhs_content.ToAsciiVector();
- VectorIterator<char> buf1(vec1);
- VectorIterator<uc16> ib(string, length);
- return CompareStringContents(&buf1, &ib);
- } else {
- Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
- Vector<const uc16> vec2(string, length);
- return CompareRawStringContents(vec1, vec2);
- }
- } else {
- Isolate* isolate = GetIsolate();
- isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
- VectorIterator<uc16> ib(string, length);
- return CompareStringContents(isolate->objects_string_compare_buffer_a(),
- &ib);
- }
-}
-
-
-bool String::SlowEqualsExternal(char *string, int length) {
- int len = this->length();
- if (len != length) return false;
- if (len == 0) return true;
-
- // We know the strings are both non-empty. Compare the first chars
- // before we try to flatten the strings.
- if (this->Get(0) != string[0]) return false;
-
- String* lhs = this->TryFlattenGetString();
-
- if (StringShape(lhs).IsSequentialAscii()) {
- const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
- return CompareRawStringContents(Vector<const char>(str1, len),
- Vector<const char>(string, len));
- }
-
- if (lhs->IsFlat()) {
- String::FlatContent lhs_content = lhs->GetFlatContent();
- Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
- VectorIterator<const uc16> buf1(vec1);
- VectorIterator<char> buf2(string, length);
- return CompareStringContents(&buf1, &buf2);
- } else {
- Isolate* isolate = GetIsolate();
- isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
- VectorIterator<char> ib(string, length);
- return CompareStringContents(isolate->objects_string_compare_buffer_a(),
- &ib);
- }
-}
-
-
bool String::SlowEquals(String* other) {
// Fast check: negative check with lengths.
int len = length();
@@ -7258,85 +7176,23 @@ void String::PrintOn(FILE* file) {
}
-void Map::CreateOneBackPointer(Object* transition_target) {
- if (!transition_target->IsMap()) return;
- Map* target = Map::cast(transition_target);
-#ifdef DEBUG
- // Verify target.
- Object* source_prototype = prototype();
- Object* target_prototype = target->prototype();
- ASSERT(source_prototype->IsJSReceiver() ||
- source_prototype->IsMap() ||
- source_prototype->IsNull());
- ASSERT(target_prototype->IsJSReceiver() ||
- target_prototype->IsNull());
- ASSERT(source_prototype->IsMap() ||
- source_prototype == target_prototype);
-#endif
- // Point target back to source. set_prototype() will not let us set
- // the prototype to a map, as we do here.
- *RawField(target, kPrototypeOffset) = this;
-}
-
-
-void Map::CreateBackPointers() {
- DescriptorArray* descriptors = instance_descriptors();
- for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
- switch (descriptors->GetType(i)) {
- case MAP_TRANSITION:
- case CONSTANT_TRANSITION:
- CreateOneBackPointer(descriptors->GetValue(i));
- break;
- case ELEMENTS_TRANSITION: {
- Object* object = descriptors->GetValue(i);
- if (object->IsMap()) {
- CreateOneBackPointer(object);
- } else {
- FixedArray* array = FixedArray::cast(object);
- for (int i = 0; i < array->length(); ++i) {
- CreateOneBackPointer(array->get(i));
- }
- }
- break;
- }
- case CALLBACKS: {
- Object* object = descriptors->GetValue(i);
- if (object->IsAccessorPair()) {
- AccessorPair* accessors = AccessorPair::cast(object);
- CreateOneBackPointer(accessors->getter());
- CreateOneBackPointer(accessors->setter());
- }
- break;
- }
- case NORMAL:
- case FIELD:
- case CONSTANT_FUNCTION:
- case HANDLER:
- case INTERCEPTOR:
- case NULL_DESCRIPTOR:
- break;
- }
- }
-}
-
-
-bool Map::RestoreOneBackPointer(Object* object,
- Object* real_prototype,
- bool* keep_entry) {
- if (!object->IsMap()) return false;
- Map* map = Map::cast(object);
+// Clear a possible back pointer in case the transition leads to a dead map.
+// Return true in case a back pointer has been cleared and false otherwise.
+// Set *keep_entry to true when a live map transition has been found.
+static bool ClearBackPointer(Heap* heap, Object* target, bool* keep_entry) {
+ if (!target->IsMap()) return false;
+ Map* map = Map::cast(target);
if (Marking::MarkBitFrom(map).Get()) {
*keep_entry = true;
return false;
+ } else {
+ map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
+ return true;
}
- ASSERT(map->prototype() == this || map->prototype() == real_prototype);
- // Getter prototype() is read-only, set_prototype() has side effects.
- *RawField(map, Map::kPrototypeOffset) = real_prototype;
- return true;
}
-void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
+void Map::ClearNonLiveTransitions(Heap* heap) {
DescriptorArray* d = DescriptorArray::cast(
*RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
if (d->IsEmpty()) return;
@@ -7349,24 +7205,22 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
// If the pair (value, details) is a map transition, check if the target is
// live. If not, null the descriptor. Also drop the back pointer for that
// map transition, so that this map is not reached again by following a back
- // pointer from a non-live object.
+ // pointer from that non-live map.
bool keep_entry = false;
PropertyDetails details(Smi::cast(contents->get(i + 1)));
switch (details.type()) {
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
- RestoreOneBackPointer(contents->get(i), real_prototype, &keep_entry);
+ ClearBackPointer(heap, contents->get(i), &keep_entry);
break;
case ELEMENTS_TRANSITION: {
Object* object = contents->get(i);
if (object->IsMap()) {
- RestoreOneBackPointer(object, real_prototype, &keep_entry);
+ ClearBackPointer(heap, object, &keep_entry);
} else {
FixedArray* array = FixedArray::cast(object);
for (int j = 0; j < array->length(); ++j) {
- if (RestoreOneBackPointer(array->get(j),
- real_prototype,
- &keep_entry)) {
+ if (ClearBackPointer(heap, array->get(j), &keep_entry)) {
array->set_undefined(j);
}
}
@@ -7377,14 +7231,10 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
Object* object = contents->get(i);
if (object->IsAccessorPair()) {
AccessorPair* accessors = AccessorPair::cast(object);
- if (RestoreOneBackPointer(accessors->getter(),
- real_prototype,
- &keep_entry)) {
+ if (ClearBackPointer(heap, accessors->getter(), &keep_entry)) {
accessors->set_getter(heap->the_hole_value());
}
- if (RestoreOneBackPointer(accessors->setter(),
- real_prototype,
- &keep_entry)) {
+ if (ClearBackPointer(heap, accessors->setter(), &keep_entry)) {
accessors->set_setter(heap->the_hole_value());
}
} else {
@@ -7914,8 +7764,8 @@ void SharedFunctionInfo::DetachInitialMap() {
Map* map = reinterpret_cast<Map*>(initial_map());
// Make the map remember to restore the link if it survives the GC.
- map->set_bit_field3(
- map->bit_field3() | (1 << Map::kAttachedToSharedFunctionInfo));
+ map->set_bit_field2(
+ map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
// Undo state changes made by StartInobjectTracking (except the
// construction_count). This way if the initial map does not survive the GC
@@ -7935,8 +7785,8 @@ void SharedFunctionInfo::DetachInitialMap() {
// Called from GC, hence reinterpret_cast and unchecked accessors.
void SharedFunctionInfo::AttachInitialMap(Map* map) {
- map->set_bit_field3(
- map->bit_field3() & ~(1 << Map::kAttachedToSharedFunctionInfo));
+ map->set_bit_field2(
+ map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
// Resume inobject slack tracking.
set_initial_map(map);
@@ -8232,6 +8082,20 @@ void Code::ClearInlineCaches() {
}
+void Code::ClearTypeFeedbackCells(Heap* heap) {
+ Object* raw_info = type_feedback_info();
+ if (raw_info->IsTypeFeedbackInfo()) {
+ TypeFeedbackCells* type_feedback_cells =
+ TypeFeedbackInfo::cast(raw_info)->type_feedback_cells();
+ for (int i = 0; i < type_feedback_cells->CellCount(); i++) {
+ ASSERT(type_feedback_cells->AstId(i)->IsSmi());
+ JSGlobalPropertyCell* cell = type_feedback_cells->Cell(i);
+ cell->set_value(TypeFeedbackCells::RawUninitializedSentinel(heap));
+ }
+ }
+}
+
+
#ifdef ENABLE_DISASSEMBLER
void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
@@ -8464,6 +8328,14 @@ void Code::Disassemble(const char* name, FILE* out) {
if (is_call_stub() || is_keyed_call_stub()) {
PrintF(out, "argc = %d\n", arguments_count());
}
+ if (is_compare_ic_stub()) {
+ CompareIC::State state = CompareIC::ComputeState(this);
+ PrintF(out, "compare_state = %s\n", CompareIC::GetStateName(state));
+ }
+ if (is_compare_ic_stub() && major_key() == CodeStub::CompareIC) {
+ Token::Value op = CompareIC::ComputeOperation(this);
+ PrintF(out, "compare_operation = %s\n", Token::Name(op));
+ }
}
if ((name != NULL) && (name[0] != '\0')) {
PrintF(out, "name = %s\n", name);
@@ -8569,8 +8441,10 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(
ElementsKind to_kind = (elements_kind == FAST_SMI_ONLY_ELEMENTS)
? FAST_SMI_ONLY_ELEMENTS
: FAST_ELEMENTS;
- // int copy_size = Min(old_elements_raw->length(), new_elements->length());
- accessor->CopyElements(this, new_elements, to_kind);
+ { MaybeObject* maybe_obj =
+ accessor->CopyElements(this, new_elements, to_kind);
+ if (maybe_obj->IsFailure()) return maybe_obj;
+ }
if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
set_map_and_elements(new_map, new_elements);
} else {
@@ -8599,7 +8473,7 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
// We should never end in here with a pixel or external array.
ASSERT(!HasExternalArrayElements());
- FixedDoubleArray* elems;
+ FixedArrayBase* elems;
{ MaybeObject* maybe_obj =
heap->AllocateUninitializedFixedDoubleArray(capacity);
if (!maybe_obj->To(&elems)) return maybe_obj;
@@ -8614,7 +8488,10 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
FixedArrayBase* old_elements = elements();
ElementsKind elements_kind = GetElementsKind();
ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
- accessor->CopyElements(this, elems, FAST_DOUBLE_ELEMENTS);
+ { MaybeObject* maybe_obj =
+ accessor->CopyElements(this, elems, FAST_DOUBLE_ELEMENTS);
+ if (maybe_obj->IsFailure()) return maybe_obj;
+ }
if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
set_map_and_elements(new_map, elems);
} else {
@@ -9750,9 +9627,10 @@ MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
ElementsKind from_kind = map()->elements_kind();
Isolate* isolate = GetIsolate();
- if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
- (to_kind == FAST_ELEMENTS ||
- elements() == isolate->heap()->empty_fixed_array())) {
+ if ((from_kind == FAST_SMI_ONLY_ELEMENTS ||
+ elements() == isolate->heap()->empty_fixed_array()) &&
+ to_kind == FAST_ELEMENTS) {
+ ASSERT(from_kind != FAST_ELEMENTS);
MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind);
Map* new_map;
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
@@ -10796,27 +10674,9 @@ class AsciiSymbolKey : public SequentialSymbolKey<char> {
MaybeObject* AsObject() {
if (hash_field_ == 0) Hash();
- MaybeObject *result = HEAP->AllocateAsciiSymbol(string_, hash_field_);
- if (!result->IsFailure() && result->ToObjectUnchecked()->IsSeqString()) {
- while (true) {
- Atomic32 my_symbol_id = next_symbol_id;
- if (my_symbol_id > Smi::kMaxValue)
- break;
- if (my_symbol_id == NoBarrier_CompareAndSwap(&next_symbol_id,
- my_symbol_id,
- my_symbol_id + 1)) {
- SeqString::cast(result->ToObjectUnchecked())->
- set_symbol_id(my_symbol_id);
- break;
- }
- }
- }
- return result;
+ return HEAP->AllocateAsciiSymbol(string_, hash_field_);
}
-
- static Atomic32 next_symbol_id;
};
-Atomic32 AsciiSymbolKey::next_symbol_id = 1;
class SubStringAsciiSymbolKey : public HashTableKey {
@@ -11166,7 +11026,6 @@ template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
-#ifndef __INTEL_COMPILER
template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
Allocate(int at_least_space_for);
@@ -11259,7 +11118,7 @@ int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
template
int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
-#endif
+
// Collates undefined and unexisting elements below limit from position
// zero of the elements. The object stays in Dictionary mode.
@@ -12949,7 +12808,7 @@ int BreakPointInfo::GetBreakPointCount() {
#endif // ENABLE_DEBUGGER_SUPPORT
-MaybeObject* JSDate::GetField(Object* object, Smi* index) {
+Object* JSDate::GetField(Object* object, Smi* index) {
return JSDate::cast(object)->DoGetField(
static_cast<FieldIndex>(index->value()));
}
diff --git a/src/3rdparty/v8/src/objects.h b/src/3rdparty/v8/src/objects.h
index 73629b8..4fd29ad 100644
--- a/src/3rdparty/v8/src/objects.h
+++ b/src/3rdparty/v8/src/objects.h
@@ -59,6 +59,7 @@
// - JSWeakMap
// - JSRegExp
// - JSFunction
+// - JSModule
// - GlobalObject
// - JSGlobalObject
// - JSBuiltinsObject
@@ -306,6 +307,7 @@ const int kVariableSizeSentinel = 0;
V(JS_DATE_TYPE) \
V(JS_OBJECT_TYPE) \
V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \
+ V(JS_MODULE_TYPE) \
V(JS_GLOBAL_OBJECT_TYPE) \
V(JS_BUILTINS_OBJECT_TYPE) \
V(JS_GLOBAL_PROXY_TYPE) \
@@ -626,6 +628,7 @@ enum InstanceType {
JS_DATE_TYPE,
JS_OBJECT_TYPE,
JS_CONTEXT_EXTENSION_OBJECT_TYPE,
+ JS_MODULE_TYPE,
JS_GLOBAL_OBJECT_TYPE,
JS_BUILTINS_OBJECT_TYPE,
JS_GLOBAL_PROXY_TYPE,
@@ -677,6 +680,7 @@ const int kExternalArrayTypeCount =
STATIC_CHECK(JS_OBJECT_TYPE == Internals::kJSObjectType);
STATIC_CHECK(FIRST_NONSTRING_TYPE == Internals::kFirstNonstringType);
+STATIC_CHECK(ODDBALL_TYPE == Internals::kOddballType);
STATIC_CHECK(FOREIGN_TYPE == Internals::kForeignType);
@@ -803,6 +807,7 @@ class MaybeObject BASE_EMBEDDED {
V(JSReceiver) \
V(JSObject) \
V(JSContextExtensionObject) \
+ V(JSModule) \
V(Map) \
V(DescriptorArray) \
V(DeoptimizationInputData) \
@@ -812,6 +817,7 @@ class MaybeObject BASE_EMBEDDED {
V(FixedDoubleArray) \
V(Context) \
V(GlobalContext) \
+ V(ModuleContext) \
V(ScopeInfo) \
V(JSFunction) \
V(Code) \
@@ -1393,14 +1399,12 @@ class JSReceiver: public HeapObject {
Handle<String> key,
Handle<Object> value,
PropertyAttributes attributes,
- StrictModeFlag strict_mode,
- bool skip_fallback_interceptor = false);
+ StrictModeFlag strict_mode);
// Can cause GC.
MUST_USE_RESULT MaybeObject* SetProperty(String* key,
Object* value,
PropertyAttributes attributes,
- StrictModeFlag strict_mode,
- bool skip_fallback_interceptor = false);
+ StrictModeFlag strict_mode);
MUST_USE_RESULT MaybeObject* SetProperty(LookupResult* result,
String* key,
Object* value,
@@ -1453,12 +1457,8 @@ class JSReceiver: public HeapObject {
// Lookup a property. If found, the result is valid and has
// detailed information.
- void LocalLookup(String* name,
- LookupResult* result,
- bool skip_fallback_interceptor = false);
- void Lookup(String* name,
- LookupResult* result,
- bool skip_fallback_interceptor = false);
+ void LocalLookup(String* name, LookupResult* result);
+ void Lookup(String* name, LookupResult* result);
protected:
Smi* GenerateIdentityHash();
@@ -1857,9 +1857,6 @@ class JSObject: public JSReceiver {
inline void SetInternalField(int index, Object* value);
inline void SetInternalField(int index, Smi* value);
- inline void SetExternalResourceObject(Object *);
- inline Object *GetExternalResourceObject();
-
// The following lookup functions skip interceptors.
void LocalLookupRealNamedProperty(String* name, LookupResult* result);
void LookupRealNamedProperty(String* name, LookupResult* result);
@@ -2195,6 +2192,7 @@ class JSObject: public JSReceiver {
Object* getter,
Object* setter,
PropertyAttributes attributes);
+ MUST_USE_RESULT MaybeObject* CreateAccessorPairFor(String* name);
MUST_USE_RESULT MaybeObject* DefinePropertyAccessor(
String* name,
Object* getter,
@@ -2476,7 +2474,7 @@ class DescriptorArray: public FixedArray {
// Accessors for fetching instance descriptor at descriptor number.
inline String* GetKey(int descriptor_number);
inline Object* GetValue(int descriptor_number);
- inline Smi* GetDetails(int descriptor_number);
+ inline PropertyDetails GetDetails(int descriptor_number);
inline PropertyType GetType(int descriptor_number);
inline int GetFieldIndex(int descriptor_number);
inline JSFunction* GetConstantFunction(int descriptor_number);
@@ -2485,7 +2483,6 @@ class DescriptorArray: public FixedArray {
inline bool IsProperty(int descriptor_number);
inline bool IsTransitionOnly(int descriptor_number);
inline bool IsNullDescriptor(int descriptor_number);
- inline bool IsDontEnum(int descriptor_number);
class WhitenessWitness {
public:
@@ -2603,6 +2600,9 @@ class DescriptorArray: public FixedArray {
// Is the descriptor array sorted and without duplicates?
bool IsSortedNoDuplicates();
+ // Is the descriptor array consistent with the back pointers in targets?
+ bool IsConsistentWithBackPointers(Map* current_map);
+
// Are two DescriptorArrays equal?
bool IsEqualTo(DescriptorArray* other);
#endif
@@ -2639,10 +2639,6 @@ class DescriptorArray: public FixedArray {
return descriptor_number << 1;
}
- bool is_null_descriptor(int descriptor_number) {
- return PropertyDetails(GetDetails(descriptor_number)).type() ==
- NULL_DESCRIPTOR;
- }
// Swap operation on FixedArray without using write barriers.
static inline void NoIncrementalWriteBarrierSwap(
FixedArray* array, int first, int second);
@@ -3348,9 +3344,6 @@ class ScopeInfo : public FixedArray {
// Return the language mode of this scope.
LanguageMode language_mode();
- // Is this scope a qml mode scope?
- bool IsQmlMode();
-
// Does this scope make a non-strict eval call?
bool CallsNonStrictEval() {
return CallsEval() && (language_mode() == CLASSIC_MODE);
@@ -3373,7 +3366,7 @@ class ScopeInfo : public FixedArray {
// 3. One context slot for the function name if it is context allocated.
// Parameters allocated in the context count as context allocated locals. If
// no contexts are allocated for this scope ContextLength returns 0.
- int ContextLength(bool qml_function = false);
+ int ContextLength();
// Is this scope the scope of a named function expression?
bool HasFunctionName();
@@ -3425,8 +3418,8 @@ class ScopeInfo : public FixedArray {
// otherwise returns a value < 0. The name must be a symbol (canonicalized).
int ParameterIndex(String* name);
- // Lookup support for serialized scope info. Returns the
- // function context slot index if the function name is present (named
+ // Lookup support for serialized scope info. Returns the function context
+ // slot index if the function name is present and context-allocated (named
// function expressions, only), otherwise returns a value < 0. The name
// must be a symbol (canonicalized).
int FunctionContextSlotIndex(String* name, VariableMode* mode);
@@ -3522,9 +3515,8 @@ class ScopeInfo : public FixedArray {
class TypeField: public BitField<ScopeType, 0, 3> {};
class CallsEvalField: public BitField<bool, 3, 1> {};
class LanguageModeField: public BitField<LanguageMode, 4, 2> {};
- class QmlModeField: public BitField<bool, 6, 1> {};
- class FunctionVariableField: public BitField<FunctionVariableInfo, 7, 2> {};
- class FunctionVariableMode: public BitField<VariableMode, 9, 3> {};
+ class FunctionVariableField: public BitField<FunctionVariableInfo, 6, 2> {};
+ class FunctionVariableMode: public BitField<VariableMode, 8, 3> {};
// BitFields representing the encoded information for context locals in the
// ContextLocalInfoEntries part.
@@ -4302,6 +4294,11 @@ class Code: public HeapObject {
inline byte compare_state();
inline void set_compare_state(byte value);
+ // [compare_operation]: For kind COMPARE_IC tells what compare operation the
+ // stub was generated for.
+ inline byte compare_operation();
+ inline void set_compare_operation(byte value);
+
// [to_boolean_foo]: For kind TO_BOOLEAN_IC tells what state the stub is in.
inline byte to_boolean_state();
inline void set_to_boolean_state(byte value);
@@ -4437,6 +4434,7 @@ class Code: public HeapObject {
void CodeVerify();
#endif
void ClearInlineCaches();
+ void ClearTypeFeedbackCells(Heap* heap);
// Max loop nesting marker used to postpose OSR. We don't take loop
// nesting that is deeper than 5 levels into account.
@@ -4485,6 +4483,8 @@ class Code: public HeapObject {
static const int kBinaryOpReturnTypeOffset = kBinaryOpTypeOffset + 1;
+ static const int kCompareOperationOffset = kCompareStateOffset + 1;
+
static const int kAllowOSRAtLoopNestingLevelOffset = kFullCodeFlags + 1;
static const int kProfilerTicksOffset = kAllowOSRAtLoopNestingLevelOffset + 1;
@@ -4614,11 +4614,11 @@ class Map: public HeapObject {
// Tells whether the instance has a call-as-function handler.
inline void set_has_instance_call_handler() {
- set_bit_field3(bit_field3() | (1 << kHasInstanceCallHandler));
+ set_bit_field(bit_field() | (1 << kHasInstanceCallHandler));
}
inline bool has_instance_call_handler() {
- return ((1 << kHasInstanceCallHandler) & bit_field3()) != 0;
+ return ((1 << kHasInstanceCallHandler) & bit_field()) != 0;
}
inline void set_is_extensible(bool value);
@@ -4691,20 +4691,6 @@ class Map: public HeapObject {
inline void set_is_access_check_needed(bool access_check_needed);
inline bool is_access_check_needed();
- // Whether the named interceptor is a fallback interceptor or not
- inline void set_named_interceptor_is_fallback(bool value);
- inline bool named_interceptor_is_fallback();
-
- // Tells whether the instance has the space for an external resource
- // object
- inline void set_has_external_resource(bool value);
- inline bool has_external_resource();
-
- // Tells whether the user object comparison callback should be used for
- // comparisons involving this object
- inline void set_use_user_object_comparison(bool value);
- inline bool use_user_object_comparison();
-
// [prototype]: implicit prototype object.
DECL_ACCESSORS(prototype, Object)
@@ -4727,19 +4713,30 @@ class Map: public HeapObject {
// [stub cache]: contains stubs compiled for this map.
DECL_ACCESSORS(code_cache, Object)
+ // [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);
+
// [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 + 2 * i: prototype
- // 2 + 2 * i: target map
+ // 1: back pointer that overlaps with prototype transitions field.
+ // 2 + 2 * i: prototype
+ // 3 + 2 * i: target map
DECL_ACCESSORS(prototype_transitions, FixedArray)
- inline FixedArray* unchecked_prototype_transitions();
+ inline void init_prototype_transitions(Object* undefined);
+ inline HeapObject* unchecked_prototype_transitions();
- static const int kProtoTransitionHeaderSize = 1;
+ static const int kProtoTransitionHeaderSize = 2;
static const int kProtoTransitionNumberOfEntriesOffset = 0;
+ static const int kProtoTransitionBackPointerOffset = 1;
static const int kProtoTransitionElementsPerEntry = 2;
static const int kProtoTransitionPrototypeOffset = 0;
static const int kProtoTransitionMapOffset = 1;
@@ -4811,25 +4808,10 @@ class Map: public HeapObject {
// Removes a code object from the code cache at the given index.
void RemoveFromCodeCache(String* name, Code* code, int index);
- // For every transition in this map, makes the transition's
- // target's prototype pointer point back to this map.
- // This is undone in MarkCompactCollector::ClearNonLiveTransitions().
- void CreateBackPointers();
-
- void CreateOneBackPointer(Object* transition_target);
-
- // Set all map transitions from this map to dead maps to null.
- // Also, restore the original prototype on the targets of these
- // transitions, so that we do not process this map again while
- // following back pointers.
- void ClearNonLiveTransitions(Heap* heap, Object* real_prototype);
-
- // Restore a possible back pointer in the prototype field of object.
- // Return true in that case and false otherwise. Set *keep_entry to
- // true when a live map transition has been found.
- bool RestoreOneBackPointer(Object* object,
- Object* real_prototype,
- bool* keep_entry);
+ // 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();
@@ -4864,6 +4846,14 @@ class Map: public HeapObject {
Handle<Map> FindTransitionedMap(MapHandleList* candidates);
Map* FindTransitionedMap(MapList* candidates);
+ // Zaps the contents of backing data structures in debug mode. 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.
+#ifdef DEBUG
+ void ZapInstanceDescriptors();
+ void ZapPrototypeTransitions();
+#endif
// Dispatched behavior.
#ifdef OBJECT_PRINT
@@ -4911,16 +4901,17 @@ class Map: public HeapObject {
kConstructorOffset + kPointerSize;
static const int kCodeCacheOffset =
kInstanceDescriptorsOrBitField3Offset + kPointerSize;
- static const int kPrototypeTransitionsOffset =
+ static const int kPrototypeTransitionsOrBackPointerOffset =
kCodeCacheOffset + kPointerSize;
- static const int kPadStart = kPrototypeTransitionsOffset + kPointerSize;
+ static const int kPadStart =
+ kPrototypeTransitionsOrBackPointerOffset + kPointerSize;
static const int kSize = MAP_POINTER_ALIGN(kPadStart);
// Layout of pointer fields. Heap iteration code relies on them
// being continuously allocated.
static const int kPointerFieldsBeginOffset = Map::kPrototypeOffset;
static const int kPointerFieldsEndOffset =
- Map::kPrototypeTransitionsOffset + kPointerSize;
+ kPrototypeTransitionsOrBackPointerOffset + kPointerSize;
// Byte offsets within kInstanceSizesOffset.
static const int kInstanceSizeOffset = kInstanceSizesOffset + 0;
@@ -4948,14 +4939,14 @@ class Map: public HeapObject {
static const int kHasNamedInterceptor = 3;
static const int kHasIndexedInterceptor = 4;
static const int kIsUndetectable = 5;
- static const int kHasExternalResource = 6;
+ static const int kHasInstanceCallHandler = 6;
static const int kIsAccessCheckNeeded = 7;
// Bit positions for bit field 2
static const int kIsExtensible = 0;
static const int kFunctionWithPrototype = 1;
static const int kStringWrapperSafeForDefaultValueOf = 2;
- static const int kUseUserObjectComparison = 3;
+ static const int kAttachedToSharedFunctionInfo = 3;
// No bits can be used after kElementsKindFirstBit, they are all reserved for
// storing ElementKind.
static const int kElementsKindShift = 4;
@@ -4972,9 +4963,6 @@ class Map: public HeapObject {
// Bit positions for bit field 3
static const int kIsShared = 0;
- static const int kNamedInterceptorIsFallback = 1;
- static const int kHasInstanceCallHandler = 2;
- static const int kAttachedToSharedFunctionInfo = 3;
// Layout of the default cache. It holds alternating name and code objects.
static const int kCodeCacheEntrySize = 2;
@@ -5362,6 +5350,8 @@ class SharedFunctionInfo: public HeapObject {
inline int deopt_counter();
inline void set_deopt_counter(int counter);
+ inline int profiler_ticks();
+
// Inline cache age is used to infer whether the function survived a context
// disposal or not. In the former case we reset the opt_count.
inline int ic_age();
@@ -5413,9 +5403,6 @@ class SharedFunctionInfo: public HeapObject {
// Indicates whether the language mode of this function is EXTENDED_MODE.
inline bool is_extended_mode();
- // Indicates whether the function is a qml mode function.
- DECL_BOOLEAN_ACCESSORS(qml_mode)
-
// False if the function definitely does not allocate an arguments object.
DECL_BOOLEAN_ACCESSORS(uses_arguments)
@@ -5658,7 +5645,6 @@ class SharedFunctionInfo: public HeapObject {
kOptimizationDisabled = kCodeAgeShift + kCodeAgeSize,
kStrictModeFunction,
kExtendedModeFunction,
- kQmlModeFunction,
kUsesArguments,
kHasDuplicateParameters,
kNative,
@@ -5724,6 +5710,35 @@ class SharedFunctionInfo: public HeapObject {
};
+// Representation for module instance objects.
+class JSModule: public JSObject {
+ public:
+ // [context]: the context holding the module's locals, or undefined if none.
+ DECL_ACCESSORS(context, Object)
+
+ // Casting.
+ static inline JSModule* cast(Object* obj);
+
+ // Dispatched behavior.
+#ifdef OBJECT_PRINT
+ inline void JSModulePrint() {
+ JSModulePrint(stdout);
+ }
+ void JSModulePrint(FILE* out);
+#endif
+#ifdef DEBUG
+ void JSModuleVerify();
+#endif
+
+ // Layout description.
+ static const int kContextOffset = JSObject::kHeaderSize;
+ static const int kSize = kContextOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSModule);
+};
+
+
// JSFunction describes JavaScript functions.
class JSFunction: public JSObject {
public:
@@ -6123,7 +6138,7 @@ class JSDate: public JSObject {
// Returns the date field with the specified index.
// See FieldIndex for the list of date fields.
- static MaybeObject* GetField(Object* date, Smi* index);
+ static Object* GetField(Object* date, Smi* index);
void SetValue(Object* value, bool is_value_nan);
@@ -6872,7 +6887,7 @@ class String: public HeapObject {
inline void Set(int index, uint16_t value);
// Get individual two byte char in the string. Repeated calls
// to this method are not efficient unless the string is flat.
- inline uint16_t Get(int index);
+ INLINE(uint16_t Get(int index));
// Try to flatten the string. Checks first inline to see if it is
// necessary. Does nothing if the string is not a cons string.
@@ -6922,9 +6937,6 @@ class String: public HeapObject {
bool IsAsciiEqualTo(Vector<const char> str);
bool IsTwoByteEqualTo(Vector<const uc16> str);
- bool SlowEqualsExternal(uc16 *string, int length);
- bool SlowEqualsExternal(char *string, int length);
-
// Return a UTF8 representation of the string. The string is null
// terminated but may optionally contain nulls. Length is returned
// in length_output if length_output is not a null pointer The string
@@ -7180,13 +7192,8 @@ class SeqString: public String {
// Casting.
static inline SeqString* cast(Object* obj);
- // Get and set the symbol id of the string
- inline int symbol_id();
- inline void set_symbol_id(int value);
-
// Layout description.
- static const int kSymbolIdOffset = String::kSize;
- static const int kHeaderSize = kSymbolIdOffset + kPointerSize;
+ static const int kHeaderSize = String::kSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(SeqString);
@@ -7648,6 +7655,10 @@ class Oddball: public HeapObject {
kToNumberOffset + kPointerSize,
kSize> BodyDescriptor;
+ STATIC_CHECK(kKindOffset == Internals::kOddballKindOffset);
+ STATIC_CHECK(kNull == Internals::kNullOddballKind);
+ STATIC_CHECK(kUndefined == Internals::kUndefinedOddballKind);
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Oddball);
};
@@ -8182,7 +8193,6 @@ class InterceptorInfo: public Struct {
DECL_ACCESSORS(deleter, Object)
DECL_ACCESSORS(enumerator, Object)
DECL_ACCESSORS(data, Object)
- DECL_ACCESSORS(is_fallback, Smi)
static inline InterceptorInfo* cast(Object* obj);
@@ -8202,8 +8212,7 @@ class InterceptorInfo: public Struct {
static const int kDeleterOffset = kQueryOffset + kPointerSize;
static const int kEnumeratorOffset = kDeleterOffset + kPointerSize;
static const int kDataOffset = kEnumeratorOffset + kPointerSize;
- static const int kFallbackOffset = kDataOffset + kPointerSize;
- static const int kSize = kFallbackOffset + kPointerSize;
+ static const int kSize = kDataOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptorInfo);
@@ -8326,8 +8335,6 @@ class ObjectTemplateInfo: public TemplateInfo {
public:
DECL_ACCESSORS(constructor, Object)
DECL_ACCESSORS(internal_field_count, Object)
- DECL_ACCESSORS(has_external_resource, Object)
- DECL_ACCESSORS(use_user_object_comparison, Object)
static inline ObjectTemplateInfo* cast(Object* obj);
@@ -8344,9 +8351,7 @@ class ObjectTemplateInfo: public TemplateInfo {
static const int kConstructorOffset = TemplateInfo::kHeaderSize;
static const int kInternalFieldCountOffset =
kConstructorOffset + kPointerSize;
- static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize;
- static const int kUseUserObjectComparisonOffset = kHasExternalResourceOffset + kPointerSize;
- static const int kSize = kUseUserObjectComparisonOffset + kPointerSize;
+ static const int kSize = kInternalFieldCountOffset + kPointerSize;
};
diff --git a/src/3rdparty/v8/src/parser.cc b/src/3rdparty/v8/src/parser.cc
index fba6b48..8620519 100644
--- a/src/3rdparty/v8/src/parser.cc
+++ b/src/3rdparty/v8/src/parser.cc
@@ -617,9 +617,6 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
scope->set_end_position(source->length());
FunctionState function_state(this, scope, isolate());
top_scope_->SetLanguageMode(info->language_mode());
- if (info->is_qml_mode()) {
- scope->EnableQmlModeFlag();
- }
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16);
bool ok = true;
int beg_loc = scanner().location().beg_pos;
@@ -718,9 +715,6 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
info->is_extended_mode());
ASSERT(info->language_mode() == shared_info->language_mode());
scope->SetLanguageMode(shared_info->language_mode());
- if (shared_info->qml_mode()) {
- top_scope_->EnableQmlModeFlag();
- }
FunctionLiteral::Type type = shared_info->is_expression()
? (shared_info->is_anonymous()
? FunctionLiteral::ANONYMOUS_EXPRESSION
@@ -1339,11 +1333,19 @@ Module* Parser::ParseModuleLiteral(bool* ok) {
Expect(Token::RBRACE, CHECK_OK);
scope->set_end_position(scanner().location().end_pos);
- body->set_block_scope(scope);
+ body->set_scope(scope);
- scope->interface()->Freeze(ok);
+ // Instance objects have to be created ahead of time (before code generation
+ // linking them) because of potentially cyclic references between them.
+ // We create them here, to avoid another pass over the AST.
+ Interface* interface = scope->interface();
+ interface->MakeModule(ok);
+ ASSERT(ok);
+ interface->MakeSingleton(Isolate::Current()->factory()->NewJSModule(), ok);
ASSERT(ok);
- return factory()->NewModuleLiteral(body, scope->interface());
+ interface->Freeze(ok);
+ ASSERT(ok);
+ return factory()->NewModuleLiteral(body, interface);
}
@@ -1409,7 +1411,14 @@ Module* Parser::ParseModuleUrl(bool* ok) {
#ifdef DEBUG
if (FLAG_print_interface_details) PrintF("# Url ");
#endif
- return factory()->NewModuleUrl(symbol);
+
+ Module* result = factory()->NewModuleUrl(symbol);
+ Interface* interface = result->interface();
+ interface->MakeSingleton(Isolate::Current()->factory()->NewJSModule(), ok);
+ ASSERT(ok);
+ interface->Freeze(ok);
+ ASSERT(ok);
+ return result;
}
@@ -2021,7 +2030,7 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
Expect(Token::RBRACE, CHECK_OK);
block_scope->set_end_position(scanner().location().end_pos);
block_scope = block_scope->FinalizeBlockScope();
- body->set_block_scope(block_scope);
+ body->set_scope(block_scope);
return body;
}
@@ -2260,7 +2269,7 @@ Block* Parser::ParseVariableDeclarations(
// Global variable declarations must be compiled in a specific
// way. When the script containing the global variable declaration
// is entered, the global variable must be declared, so that if it
- // doesn't exist (not even in a prototype of the global object) it
+ // doesn't exist (on the global object itself, see ES5 errata) it
// gets created with an initial undefined value. This is handled
// by the declarations part of the function representing the
// top-level global code; see Runtime::DeclareGlobalVariable. If
@@ -2287,11 +2296,6 @@ Block* Parser::ParseVariableDeclarations(
arguments->Add(value);
value = NULL; // zap the value to avoid the unnecessary assignment
- int qml_mode = 0;
- if (top_scope_->is_qml_mode() && !Isolate::Current()->global()->HasProperty(*name))
- qml_mode = 1;
- arguments->Add(factory()->NewNumberLiteral(qml_mode));
-
// Construct the call to Runtime_InitializeConstGlobal
// and add it to the initialization statement block.
// Note that the function does different things depending on
@@ -2306,11 +2310,6 @@ Block* Parser::ParseVariableDeclarations(
LanguageMode language_mode = initialization_scope->language_mode();
arguments->Add(factory()->NewNumberLiteral(language_mode));
- int qml_mode = 0;
- if (top_scope_->is_qml_mode() && !Isolate::Current()->global()->HasProperty(*name))
- qml_mode = 1;
- arguments->Add(factory()->NewNumberLiteral(qml_mode));
-
// Be careful not to assign a value to the global variable if
// we're in a with. The initialization value should not
// necessarily be stored in the global object in that case,
@@ -2933,7 +2932,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
top_scope_ = saved_scope;
for_scope->set_end_position(scanner().location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
- body_block->set_block_scope(for_scope);
+ body_block->set_scope(for_scope);
// Parsed for-in loop w/ let declaration.
return loop;
@@ -3013,7 +3012,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
Block* result = factory()->NewBlock(NULL, 2, false);
result->AddStatement(init);
result->AddStatement(loop);
- result->set_block_scope(for_scope);
+ result->set_scope(for_scope);
if (loop) loop->Initialize(NULL, cond, next, body);
return result;
} else {
@@ -4476,15 +4475,15 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
Variable* fvar = NULL;
Token::Value fvar_init_op = Token::INIT_CONST;
if (type == FunctionLiteral::NAMED_EXPRESSION) {
- VariableMode fvar_mode;
- if (is_extended_mode()) {
- fvar_mode = CONST_HARMONY;
- fvar_init_op = Token::INIT_CONST_HARMONY;
- } else {
- fvar_mode = CONST;
- }
- fvar =
- top_scope_->DeclareFunctionVar(function_name, fvar_mode, factory());
+ if (is_extended_mode()) fvar_init_op = Token::INIT_CONST_HARMONY;
+ VariableMode fvar_mode = is_extended_mode() ? CONST_HARMONY : CONST;
+ fvar = new(zone()) Variable(top_scope_,
+ function_name, fvar_mode, true /* is valid LHS */,
+ Variable::NORMAL, kCreatedInitialized);
+ VariableProxy* proxy = factory()->NewVariableProxy(fvar);
+ VariableDeclaration* fvar_declaration =
+ factory()->NewVariableDeclaration(proxy, fvar_mode, top_scope_);
+ top_scope_->DeclareFunctionVar(fvar_declaration);
}
// Determine whether the function will be lazily compiled.
diff --git a/src/3rdparty/v8/src/platform-cygwin.cc b/src/3rdparty/v8/src/platform-cygwin.cc
index 8b1e381..089ea38 100644
--- a/src/3rdparty/v8/src/platform-cygwin.cc
+++ b/src/3rdparty/v8/src/platform-cygwin.cc
@@ -620,11 +620,8 @@ class SamplerThread : public Thread {
: Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
interval_(interval) {}
- static void SetUp() {
- if (!mutex_) {
- mutex_ = OS::CreateMutex();
- }
- }
+ static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
+ static void TearDown() { delete mutex_; }
static void AddActiveSampler(Sampler* sampler) {
ScopedLock lock(mutex_);
@@ -749,6 +746,12 @@ void OS::SetUp() {
}
+void OS::TearDown() {
+ SamplerThread::TearDown();
+ delete limit_mutex;
+}
+
+
Sampler::Sampler(Isolate* isolate, int interval)
: isolate_(isolate),
interval_(interval),
diff --git a/src/3rdparty/v8/src/platform-freebsd.cc b/src/3rdparty/v8/src/platform-freebsd.cc
index 6b1c987..511759c 100644
--- a/src/3rdparty/v8/src/platform-freebsd.cc
+++ b/src/3rdparty/v8/src/platform-freebsd.cc
@@ -554,6 +554,7 @@ class FreeBSDMutex : public Mutex {
ASSERT(result == 0);
result = pthread_mutex_init(&mutex_, &attrs);
ASSERT(result == 0);
+ USE(result);
}
virtual ~FreeBSDMutex() { pthread_mutex_destroy(&mutex_); }
@@ -716,11 +717,8 @@ class SignalSender : public Thread {
: Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
interval_(interval) {}
- static void SetUp() {
- if (!mutex_) {
- mutex_ = OS::CreateMutex();
- }
- }
+ static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
+ static void TearDown() { delete mutex_; }
static void AddActiveSampler(Sampler* sampler) {
ScopedLock lock(mutex_);
@@ -864,6 +862,12 @@ void OS::SetUp() {
}
+void OS::TearDown() {
+ SignalSender::TearDown();
+ delete limit_mutex;
+}
+
+
Sampler::Sampler(Isolate* isolate, int interval)
: isolate_(isolate),
interval_(interval),
diff --git a/src/3rdparty/v8/src/platform-linux.cc b/src/3rdparty/v8/src/platform-linux.cc
index 9bea32d..f6db423 100644
--- a/src/3rdparty/v8/src/platform-linux.cc
+++ b/src/3rdparty/v8/src/platform-linux.cc
@@ -964,6 +964,25 @@ typedef struct ucontext {
__sigset_t uc_sigmask;
} ucontext_t;
+#elif !defined(__GLIBC__) && defined(__i386__)
+// x86 version for Android.
+struct sigcontext {
+ uint32_t gregs[19];
+ void* fpregs;
+ uint32_t oldmask;
+ uint32_t cr2;
+};
+
+typedef uint32_t __sigset_t;
+typedef struct sigcontext mcontext_t;
+typedef struct ucontext {
+ uint32_t uc_flags;
+ struct ucontext* uc_link;
+ stack_t uc_stack;
+ mcontext_t uc_mcontext;
+ __sigset_t uc_sigmask;
+} ucontext_t;
+enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
#endif
@@ -1055,11 +1074,8 @@ class SignalSender : public Thread {
vm_tgid_(getpid()),
interval_(interval) {}
- static void SetUp() {
- if (!mutex_) {
- mutex_ = OS::CreateMutex();
- }
- }
+ static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
+ static void TearDown() { delete mutex_; }
static void InstallSignalHandler() {
struct sigaction sa;
@@ -1238,6 +1254,12 @@ void OS::SetUp() {
}
+void OS::TearDown() {
+ SignalSender::TearDown();
+ delete limit_mutex;
+}
+
+
Sampler::Sampler(Isolate* isolate, int interval)
: isolate_(isolate),
interval_(interval),
diff --git a/src/3rdparty/v8/src/platform-macos.cc b/src/3rdparty/v8/src/platform-macos.cc
index afcd80a..a937ed3 100644
--- a/src/3rdparty/v8/src/platform-macos.cc
+++ b/src/3rdparty/v8/src/platform-macos.cc
@@ -743,11 +743,8 @@ class SamplerThread : public Thread {
: Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
interval_(interval) {}
- static void SetUp() {
- if (!mutex_) {
- mutex_ = OS::CreateMutex();
- }
- }
+ static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
+ static void TearDown() { delete mutex_; }
static void AddActiveSampler(Sampler* sampler) {
ScopedLock lock(mutex_);
@@ -881,6 +878,12 @@ void OS::SetUp() {
}
+void OS::TearDown() {
+ SamplerThread::TearDown();
+ delete limit_mutex;
+}
+
+
Sampler::Sampler(Isolate* isolate, int interval)
: isolate_(isolate),
interval_(interval),
diff --git a/src/3rdparty/v8/src/platform-nullos.cc b/src/3rdparty/v8/src/platform-nullos.cc
index 42799db..679ef8e 100644
--- a/src/3rdparty/v8/src/platform-nullos.cc
+++ b/src/3rdparty/v8/src/platform-nullos.cc
@@ -91,6 +91,11 @@ void OS::PostSetUp() {
}
+void OS::TearDown() {
+ UNIMPLEMENTED();
+}
+
+
// Returns the accumulated user time for thread.
int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
UNIMPLEMENTED();
diff --git a/src/3rdparty/v8/src/platform-openbsd.cc b/src/3rdparty/v8/src/platform-openbsd.cc
index 2b2d530..ba33a84 100644
--- a/src/3rdparty/v8/src/platform-openbsd.cc
+++ b/src/3rdparty/v8/src/platform-openbsd.cc
@@ -793,11 +793,8 @@ class SignalSender : public Thread {
vm_tgid_(getpid()),
interval_(interval) {}
- static void SetUp() {
- if (!mutex_) {
- mutex_ = OS::CreateMutex();
- }
- }
+ static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
+ static void TearDown() { delete mutex_; }
static void InstallSignalHandler() {
struct sigaction sa;
@@ -948,6 +945,12 @@ void OS::SetUp() {
}
+void OS::TearDown() {
+ SignalSender::TearDown();
+ delete limit_mutex;
+}
+
+
Sampler::Sampler(Isolate* isolate, int interval)
: isolate_(isolate),
interval_(interval),
diff --git a/src/3rdparty/v8/src/platform-posix.cc b/src/3rdparty/v8/src/platform-posix.cc
index 6631659..d942d78 100644
--- a/src/3rdparty/v8/src/platform-posix.cc
+++ b/src/3rdparty/v8/src/platform-posix.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -421,7 +421,11 @@ Socket* POSIXSocket::Accept() const {
return NULL;
}
- int socket = accept(socket_, NULL, NULL);
+ int socket;
+ do {
+ socket = accept(socket_, NULL, NULL);
+ } while (socket == -1 && errno == EINTR);
+
if (socket == -1) {
return NULL;
} else {
@@ -448,7 +452,9 @@ bool POSIXSocket::Connect(const char* host, const char* port) {
}
// Connect.
- status = connect(socket_, result->ai_addr, result->ai_addrlen);
+ do {
+ status = connect(socket_, result->ai_addr, result->ai_addrlen);
+ } while (status == -1 && errno == EINTR);
freeaddrinfo(result);
return status == 0;
}
@@ -467,14 +473,29 @@ bool POSIXSocket::Shutdown() {
int POSIXSocket::Send(const char* data, int len) const {
- int status = send(socket_, data, len, 0);
- return status;
+ if (len <= 0) return 0;
+ int written = 0;
+ while (written < len) {
+ int status = send(socket_, data + written, len - written, 0);
+ if (status == 0) {
+ break;
+ } else if (status > 0) {
+ written += status;
+ } else if (errno != EINTR) {
+ return 0;
+ }
+ }
+ return written;
}
int POSIXSocket::Receive(char* data, int len) const {
- int status = recv(socket_, data, len, 0);
- return status;
+ if (len <= 0) return 0;
+ int status;
+ do {
+ status = recv(socket_, data, len, 0);
+ } while (status == -1 && errno == EINTR);
+ return (status < 0) ? 0 : status;
}
diff --git a/src/3rdparty/v8/src/platform-qnx.cc b/src/3rdparty/v8/src/platform-qnx.cc
deleted file mode 100644
index 53e6cf5..0000000
--- a/src/3rdparty/v8/src/platform-qnx.cc
+++ /dev/null
@@ -1,1078 +0,0 @@
-// Copyright 2012 Research in Motion. 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.
-
-// Platform specific code for QNX goes here. For the POSIX comaptible parts
-// the implementation is in platform-posix.cc.
-
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <ucontext.h>
-#include <backtrace.h>
-
-// QNX requires memory pages to be marked as
-// executable. Otherwise, OS raises an exception when executing code
-// in that page.
-#include <sys/types.h> // mmap & munmap
-#include <sys/mman.h> // mmap & munmap
-#include <sys/stat.h> // open
-#include <fcntl.h> // open
-#include <unistd.h> // sysconf
-#include <strings.h> // index
-#include <errno.h>
-#include <stdarg.h>
-#include <sys/procfs.h>
-#include <sys/syspage.h>
-
-#undef MAP_TYPE
-
-#include "v8.h"
-
-#include "platform.h"
-#include "platform-posix.h"
-#include "v8threads.h"
-#include "vm-state-inl.h"
-
-
-namespace v8 {
-namespace internal {
-
-// 0 is never a valid thread id on QNX since tids and pids share a
-// name space and pid 0 is reserved (see man 2 kill).
-static const pthread_t kNoThread = (pthread_t) 0;
-
-
-double ceiling(double x) {
- return ceil(x);
-}
-
-
-static Mutex* limit_mutex = NULL;
-
-
-void OS::SetUp() {
- // Seed the random number generator. We preserve microsecond resolution.
- uint64_t seed = Ticks() ^ (getpid() << 16);
- srandom(static_cast<unsigned int>(seed));
- limit_mutex = CreateMutex();
-
-#ifdef __arm__
- // When running on ARM hardware check that the EABI used by V8 and
- // by the C code is the same.
- bool hard_float = OS::ArmUsingHardFloat();
- if (hard_float) {
-#if !USE_EABI_HARDFLOAT
- PrintF("ERROR: Binary compiled with -mfloat-abi=hard but without "
- "-DUSE_EABI_HARDFLOAT\n");
- exit(1);
-#endif
- } else {
-#if USE_EABI_HARDFLOAT
- PrintF("ERROR: Binary not compiled with -mfloat-abi=hard but with "
- "-DUSE_EABI_HARDFLOAT\n");
- exit(1);
-#endif
- }
-#endif
-}
-
-
-void OS::PostSetUp() {
- POSIXPostSetUp();
-}
-
-
-uint64_t OS::CpuFeaturesImpliedByPlatform() {
- return 0; // QNX runs on anything.
-}
-
-
-#ifdef __arm__
-static bool CPUInfoContainsString(const char * search_string) {
- const char* file_name = "/proc/cpuinfo";
- // This is written as a straight shot one pass parser
- // and not using STL string and ifstream because,
- // on QNX, it's reading from a (non-mmap-able)
- // character special device.
- FILE* f = NULL;
- const char* what = search_string;
-
- if (NULL == (f = fopen(file_name, "r")))
- return false;
-
- int k;
- while (EOF != (k = fgetc(f))) {
- if (k == *what) {
- ++what;
- while ((*what != '\0') && (*what == fgetc(f))) {
- ++what;
- }
- if (*what == '\0') {
- fclose(f);
- return true;
- } else {
- what = search_string;
- }
- }
- }
- fclose(f);
-
- // Did not find string in the proc file.
- return false;
-}
-
-
-bool OS::ArmCpuHasFeature(CpuFeature feature) {
- switch (feature) {
- case VFP3:
- // All shipping devices currently support this and QNX has no easy way to
- // determine this at runtime.
- return true;
- case ARMv7:
- return (SYSPAGE_ENTRY(cpuinfo)->flags & ARM_CPU_FLAG_V7) != 0;
- default:
- UNREACHABLE();
- }
-
- return false;
-}
-
-
-// Simple helper function to detect whether the C code is compiled with
-// option -mfloat-abi=hard. The register d0 is loaded with 1.0 and the register
-// pair r0, r1 is loaded with 0.0. If -mfloat-abi=hard is pased to GCC then
-// calling this will return 1.0 and otherwise 0.0.
-static void ArmUsingHardFloatHelper() {
- asm("mov r0, #0");
-#if defined(__VFP_FP__) && !defined(__SOFTFP__)
- // Load 0x3ff00000 into r1 using instructions available in both ARM
- // and Thumb mode.
- asm("mov r1, #3");
- asm("mov r2, #255");
- asm("lsl r1, r1, #8");
- asm("orr r1, r1, r2");
- asm("lsl r1, r1, #20");
- // For vmov d0, r0, r1 use ARM mode.
-#ifdef __thumb__
- asm volatile(
- "@ Enter ARM Mode \n\t"
- " adr r3, 1f \n\t"
- " bx r3 \n\t"
- " .ALIGN 4 \n\t"
- " .ARM \n"
- "1: vmov d0, r0, r1 \n\t"
- "@ Enter THUMB Mode\n\t"
- " adr r3, 2f+1 \n\t"
- " bx r3 \n\t"
- " .THUMB \n"
- "2: \n\t");
-#else
- asm("vmov d0, r0, r1");
-#endif // __thumb__
-#endif // defined(__VFP_FP__) && !defined(__SOFTFP__)
- asm("mov r1, #0");
-}
-
-
-bool OS::ArmUsingHardFloat() {
- // Cast helper function from returning void to returning double.
- typedef double (*F)();
- F f = FUNCTION_CAST<F>(FUNCTION_ADDR(ArmUsingHardFloatHelper));
- return f() == 1.0;
-}
-#endif // def __arm__
-
-
-int OS::ActivationFrameAlignment() {
-#ifdef V8_TARGET_ARCH_ARM
- // On EABI ARM targets this is required for fp correctness in the
- // runtime system.
- return 8;
-#endif
- // With gcc 4.4 the tree vectorization optimizer can generate code
- // that requires 16 byte alignment such as movdqa on x86.
- return 16;
-}
-
-
-void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
-#if defined(V8_TARGET_ARCH_ARM) && defined(__arm__)
- // Only use on ARM hardware.
- MemoryBarrier();
-#else
- __asm__ __volatile__("" : : : "memory");
- // An x86 store acts as a release barrier.
-#endif
- *ptr = value;
-}
-
-
-const char* OS::LocalTimezone(double time) {
- if (isnan(time)) return "";
- time_t tv = static_cast<time_t>(floor(time/msPerSecond));
- struct tm* t = localtime(&tv);
- if (NULL == t) return "";
- return t->tm_zone;
-}
-
-
-double OS::LocalTimeOffset() {
- time_t tv = time(NULL);
- struct tm* t = localtime(&tv);
- // tm_gmtoff includes any daylight savings offset, so subtract it.
- return static_cast<double>(t->tm_gmtoff * msPerSecond -
- (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
-}
-
-
-// We keep the lowest and highest addresses mapped as a quick way of
-// determining that pointers are outside the heap (used mostly in assertions
-// and verification). The estimate is conservative, ie, not all addresses in
-// 'allocated' space are actually allocated to our heap. The range is
-// [lowest, highest), inclusive on the low and and exclusive on the high end.
-static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
-static void* highest_ever_allocated = reinterpret_cast<void*>(0);
-
-
-static void UpdateAllocatedSpaceLimits(void* address, int size) {
- ASSERT(limit_mutex != NULL);
- ScopedLock lock(limit_mutex);
-
- lowest_ever_allocated = Min(lowest_ever_allocated, address);
- highest_ever_allocated =
- Max(highest_ever_allocated,
- reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
-}
-
-
-bool OS::IsOutsideAllocatedSpace(void* address) {
- return address < lowest_ever_allocated || address >= highest_ever_allocated;
-}
-
-
-size_t OS::AllocateAlignment() {
- return sysconf(_SC_PAGESIZE);
-}
-
-
-void* OS::Allocate(const size_t requested,
- size_t* allocated,
- bool is_executable) {
- const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE));
- int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
- void* addr = GetRandomMmapAddr();
- void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (mbase == MAP_FAILED) {
- LOG(i::Isolate::Current(),
- StringEvent("OS::Allocate", "mmap failed"));
- return NULL;
- }
- *allocated = msize;
- UpdateAllocatedSpaceLimits(mbase, msize);
- return mbase;
-}
-
-
-void OS::Free(void* address, const size_t size) {
- // TODO(1240712): munmap has a return value which is ignored here.
- int result = munmap(address, size);
- USE(result);
- ASSERT(result == 0);
-}
-
-
-void OS::Sleep(int milliseconds) {
- unsigned int ms = static_cast<unsigned int>(milliseconds);
- usleep(1000 * ms);
-}
-
-
-void OS::Abort() {
- // Redirect to std abort to signal abnormal program termination.
- abort();
-}
-
-
-void OS::DebugBreak() {
-// TODO(lrn): Introduce processor define for runtime system (!= V8_ARCH_x,
-// which is the architecture of generated code).
-#if (defined(__arm__) || defined(__thumb__))
-# if defined(CAN_USE_ARMV5_INSTRUCTIONS)
- asm("bkpt 0");
-# endif
-#else
- asm("int $3");
-#endif
-}
-
-
-class PosixMemoryMappedFile : public OS::MemoryMappedFile {
- public:
- PosixMemoryMappedFile(FILE* file, void* memory, int size)
- : file_(file), memory_(memory), size_(size) { }
- virtual ~PosixMemoryMappedFile();
- virtual void* memory() { return memory_; }
- virtual int size() { return size_; }
- private:
- FILE* file_;
- void* memory_;
- int size_;
-};
-
-
-OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
- FILE* file = fopen(name, "r+");
- if (file == NULL) return NULL;
-
- fseek(file, 0, SEEK_END);
- int size = ftell(file);
-
- void* memory =
- mmap(OS::GetRandomMmapAddr(),
- size,
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- fileno(file),
- 0);
- return new PosixMemoryMappedFile(file, memory, size);
-}
-
-
-OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
- void* initial) {
- FILE* file = fopen(name, "w+");
- if (file == NULL) return NULL;
- int result = fwrite(initial, size, 1, file);
- if (result < 1) {
- fclose(file);
- return NULL;
- }
- void* memory =
- mmap(OS::GetRandomMmapAddr(),
- size,
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- fileno(file),
- 0);
- return new PosixMemoryMappedFile(file, memory, size);
-}
-
-
-PosixMemoryMappedFile::~PosixMemoryMappedFile() {
- if (memory_) munmap(memory_, size_);
- fclose(file_);
-}
-
-
-void OS::LogSharedLibraryAddresses() {
- procfs_mapinfo *mapinfos = NULL, *mapinfo;
- int proc_fd, num, i;
-
- struct {
- procfs_debuginfo info;
- char buff[PATH_MAX];
- } map;
-
- char buf[PATH_MAX + 1];
- sprintf(buf, "/proc/%d/as", getpid());
-
- if ((proc_fd = open(buf, O_RDONLY)) == -1) {
- close(proc_fd);
- return;
- }
-
- /* Get the number of map entrys. */
- if (devctl(proc_fd, DCMD_PROC_MAPINFO, NULL, 0, &num) != EOK) {
- close(proc_fd);
- return;
- }
-
- mapinfos =(procfs_mapinfo *)malloc(num * sizeof(procfs_mapinfo));
- if (mapinfos == NULL) {
- close(proc_fd);
- return;
- }
-
- /* Fill the map entrys. */
- if (devctl(proc_fd, DCMD_PROC_PAGEDATA, mapinfos, num * sizeof(procfs_mapinfo), &num) != EOK) {
- free(mapinfos);
- close(proc_fd);
- return;
- }
-
- i::Isolate* isolate = ISOLATE;
-
- for (i = 0; i < num; i++) {
- mapinfo = mapinfos + i;
- if (mapinfo->flags & MAP_ELF) {
- map.info.vaddr = mapinfo->vaddr;
- if (devctl(proc_fd, DCMD_PROC_MAPDEBUG, &map, sizeof(map), 0) != EOK)
- continue;
-
- LOG(isolate, SharedLibraryEvent(map.info.path, mapinfo->vaddr, mapinfo->vaddr + mapinfo->size));
- }
- }
- free(mapinfos);
- close(proc_fd);
-}
-
-
-static const char kGCFakeMmap[] = "/tmp/__v8_gc__";
-
-
-void OS::SignalCodeMovingGC() {
- // Support for ll_prof.py.
- //
- // The QNX profiler built into the kernel logs all mmap's with
- // PROT_EXEC so that analysis tools can properly attribute ticks. We
- // do a mmap with a name known by ll_prof.py and immediately munmap
- // it. This injects a GC marker into the stream of events generated
- // by the kernel and allows us to synchronize V8 code log and the
- // kernel log.
- int size = sysconf(_SC_PAGESIZE);
- FILE* f = fopen(kGCFakeMmap, "w+");
- void* addr = mmap(OS::GetRandomMmapAddr(),
- size,
- PROT_READ | PROT_EXEC,
- MAP_PRIVATE,
- fileno(f),
- 0);
- ASSERT(addr != MAP_FAILED);
- munmap(addr, size);
- fclose(f);
-}
-
-
-int OS::StackWalk(Vector<OS::StackFrame> frames) {
- int frames_size = frames.length();
- bt_addr_t addresses[frames_size];
- bt_accessor_t acc;
- bt_memmap_t memmap;
- bt_init_accessor(&acc, BT_SELF);
- bt_load_memmap(&acc, &memmap);
- int frames_count = bt_get_backtrace(&acc, addresses, frames_size);
- bt_addr_t temp_addr[1];
- for (int i = 0; i < frames_count; i++) {
- frames[i].address = reinterpret_cast<void*>(addresses[i]);
- temp_addr[0] = addresses[i];
- // Format a text representation of the frame based on the information
- // available.
- bt_sprnf_addrs(&memmap, temp_addr, 1, "%a", frames[i].text, kStackWalkMaxTextLen, 0);
- // Make sure line termination is in place.
- frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
- }
- bt_unload_memmap(&memmap);
- bt_release_accessor(&acc);
- return 0;
-}
-
-
-// Constants used for mmap.
-static const int kMmapFd = -1;
-static const int kMmapFdOffset = 0;
-
-VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
-
-VirtualMemory::VirtualMemory(size_t size) {
- address_ = ReserveRegion(size);
- size_ = size;
-}
-
-
-VirtualMemory::VirtualMemory(size_t size, size_t alignment)
- : address_(NULL), size_(0) {
- ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
- size_t request_size = RoundUp(size + alignment,
- static_cast<intptr_t>(OS::AllocateAlignment()));
- void* reservation = mmap(OS::GetRandomMmapAddr(),
- request_size,
- PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- kMmapFd,
- kMmapFdOffset);
- if (reservation == MAP_FAILED) return;
-
- Address base = static_cast<Address>(reservation);
- Address aligned_base = RoundUp(base, alignment);
- ASSERT_LE(base, aligned_base);
-
- // Unmap extra memory reserved before and after the desired block.
- if (aligned_base != base) {
- size_t prefix_size = static_cast<size_t>(aligned_base - base);
- OS::Free(base, prefix_size);
- request_size -= prefix_size;
- }
-
- size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
- ASSERT_LE(aligned_size, request_size);
-
- if (aligned_size != request_size) {
- size_t suffix_size = request_size - aligned_size;
- OS::Free(aligned_base + aligned_size, suffix_size);
- request_size -= suffix_size;
- }
-
- ASSERT(aligned_size == request_size);
-
- address_ = static_cast<void*>(aligned_base);
- size_ = aligned_size;
-}
-
-
-VirtualMemory::~VirtualMemory() {
- if (IsReserved()) {
- bool result = ReleaseRegion(address(), size());
- ASSERT(result);
- USE(result);
- }
-}
-
-
-bool VirtualMemory::IsReserved() {
- return address_ != NULL;
-}
-
-
-void VirtualMemory::Reset() {
- address_ = NULL;
- size_ = 0;
-}
-
-
-bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
- return CommitRegion(address, size, is_executable);
-}
-
-
-bool VirtualMemory::Uncommit(void* address, size_t size) {
- return UncommitRegion(address, size);
-}
-
-
-bool VirtualMemory::Guard(void* address) {
- OS::Guard(address, OS::CommitPageSize());
- return true;
-}
-
-
-void* VirtualMemory::ReserveRegion(size_t size) {
- void* result = mmap(OS::GetRandomMmapAddr(),
- size,
- PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- kMmapFd,
- kMmapFdOffset);
-
- if (result == MAP_FAILED) return NULL;
-
- return result;
-}
-
-
-bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
- int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
- if (MAP_FAILED == mmap(base,
- size,
- prot,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
- kMmapFd,
- kMmapFdOffset)) {
- return false;
- }
-
- UpdateAllocatedSpaceLimits(base, size);
- return true;
-}
-
-
-bool VirtualMemory::UncommitRegion(void* base, size_t size) {
- return mmap(base,
- size,
- PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
- kMmapFd,
- kMmapFdOffset) != MAP_FAILED;
-}
-
-
-bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
- return munmap(base, size) == 0;
-}
-
-
-class Thread::PlatformData : public Malloced {
- public:
- PlatformData() : thread_(kNoThread) {}
-
- pthread_t thread_; // Thread handle for pthread.
-};
-
-Thread::Thread(const Options& options)
- : data_(new PlatformData()),
- stack_size_(options.stack_size()) {
- set_name(options.name());
-}
-
-
-Thread::~Thread() {
- delete data_;
-}
-
-
-static void* ThreadEntry(void* arg) {
- Thread* thread = reinterpret_cast<Thread*>(arg);
- // This is also initialized by the first argument to pthread_create() but we
- // don't know which thread will run first (the original thread or the new
- // one) so we initialize it here too.
-#ifdef PR_SET_NAME
- prctl(PR_SET_NAME,
- reinterpret_cast<unsigned long>(thread->name()), // NOLINT
- 0, 0, 0);
-#endif
- thread->data()->thread_ = pthread_self();
- ASSERT(thread->data()->thread_ != kNoThread);
- thread->Run();
- return NULL;
-}
-
-
-void Thread::set_name(const char* name) {
- strncpy(name_, name, sizeof(name_));
- name_[sizeof(name_) - 1] = '\0';
-}
-
-
-void Thread::Start() {
- pthread_attr_t* attr_ptr = NULL;
- pthread_attr_t attr;
- if (stack_size_ > 0) {
- pthread_attr_init(&attr);
- pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
- attr_ptr = &attr;
- }
- int result = pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
- CHECK_EQ(0, result);
- ASSERT(data_->thread_ != kNoThread);
-}
-
-
-void Thread::Join() {
- pthread_join(data_->thread_, NULL);
-}
-
-
-Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
- pthread_key_t key;
- int result = pthread_key_create(&key, NULL);
- USE(result);
- ASSERT(result == 0);
- return static_cast<LocalStorageKey>(key);
-}
-
-
-void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
- pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
- int result = pthread_key_delete(pthread_key);
- USE(result);
- ASSERT(result == 0);
-}
-
-
-void* Thread::GetThreadLocal(LocalStorageKey key) {
- pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
- return pthread_getspecific(pthread_key);
-}
-
-
-void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
- pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
- pthread_setspecific(pthread_key, value);
-}
-
-
-void Thread::YieldCPU() {
- sched_yield();
-}
-
-
-class QNXMutex : public Mutex {
- public:
- QNXMutex() {
- pthread_mutexattr_t attrs;
- int result = pthread_mutexattr_init(&attrs);
- ASSERT(result == 0);
- result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
- ASSERT(result == 0);
- result = pthread_mutex_init(&mutex_, &attrs);
- ASSERT(result == 0);
- USE(result);
- }
-
- virtual ~QNXMutex() { pthread_mutex_destroy(&mutex_); }
-
- virtual int Lock() {
- int result = pthread_mutex_lock(&mutex_);
- return result;
- }
-
- virtual int Unlock() {
- int result = pthread_mutex_unlock(&mutex_);
- return result;
- }
-
- virtual bool TryLock() {
- int result = pthread_mutex_trylock(&mutex_);
- // Return false if the lock is busy and locking failed.
- if (result == EBUSY) {
- return false;
- }
- ASSERT(result == 0); // Verify no other errors.
- return true;
- }
-
- private:
- pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
-};
-
-
-Mutex* OS::CreateMutex() {
- return new QNXMutex();
-}
-
-
-class QNXSemaphore : public Semaphore {
- public:
- explicit QNXSemaphore(int count) { sem_init(&sem_, 0, count); }
- virtual ~QNXSemaphore() { sem_destroy(&sem_); }
-
- virtual void Wait();
- virtual bool Wait(int timeout);
- virtual void Signal() { sem_post(&sem_); }
- private:
- sem_t sem_;
-};
-
-
-void QNXSemaphore::Wait() {
- while (true) {
- int result = sem_wait(&sem_);
- if (result == 0) return; // Successfully got semaphore.
- CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
- }
-}
-
-
-#ifndef TIMEVAL_TO_TIMESPEC
-#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
- (ts)->tv_sec = (tv)->tv_sec; \
- (ts)->tv_nsec = (tv)->tv_usec * 1000; \
-} while (false)
-#endif
-
-
-bool QNXSemaphore::Wait(int timeout) {
- const long kOneSecondMicros = 1000000; // NOLINT
-
- // Split timeout into second and nanosecond parts.
- struct timeval delta;
- delta.tv_usec = timeout % kOneSecondMicros;
- delta.tv_sec = timeout / kOneSecondMicros;
-
- struct timeval current_time;
- // Get the current time.
- if (gettimeofday(&current_time, NULL) == -1) {
- return false;
- }
-
- // Calculate time for end of timeout.
- struct timeval end_time;
- timeradd(&current_time, &delta, &end_time);
-
- struct timespec ts;
- TIMEVAL_TO_TIMESPEC(&end_time, &ts);
- // Wait for semaphore signalled or timeout.
- while (true) {
- int result = sem_timedwait(&sem_, &ts);
- if (result == 0) return true; // Successfully got semaphore.
- if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
- CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
- }
-}
-
-
-Semaphore* OS::CreateSemaphore(int count) {
- return new QNXSemaphore(count);
-}
-
-
-static int GetThreadID() {
- pthread_t thread_id = pthread_self();
- return thread_id;
-}
-
-
-static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
- USE(info);
- if (signal != SIGPROF) return;
- Isolate* isolate = Isolate::UncheckedCurrent();
- if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
- // We require a fully initialized and entered isolate.
- return;
- }
- if (v8::Locker::IsActive() &&
- !isolate->thread_manager()->IsLockedByCurrentThread()) {
- return;
- }
-
- Sampler* sampler = isolate->logger()->sampler();
- if (sampler == NULL || !sampler->IsActive()) return;
-
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
- if (sample == NULL) sample = &sample_obj;
-
- // Extracting the sample from the context is extremely machine dependent.
- ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
- mcontext_t& mcontext = ucontext->uc_mcontext;
- sample->state = isolate->current_vm_state();
-#if V8_HOST_ARCH_IA32
- sample->pc = reinterpret_cast<Address>(mcontext.cpu.eip);
- sample->sp = reinterpret_cast<Address>(mcontext.cpu.esp);
- sample->fp = reinterpret_cast<Address>(mcontext.cpu.ebp);
-#elif V8_HOST_ARCH_X64
- sample->pc = reinterpret_cast<Address>(mcontext.cpu.rip);
- sample->sp = reinterpret_cast<Address>(mcontext.cpu.rsp);
- sample->fp = reinterpret_cast<Address>(mcontext.cpu.rbp);
-#elif V8_HOST_ARCH_ARM
- sample->pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]);
- sample->sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]);
- sample->fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]);
-#endif
- sampler->SampleStack(sample);
- sampler->Tick(sample);
-}
-
-
-class Sampler::PlatformData : public Malloced {
- public:
- PlatformData() : vm_tid_(GetThreadID()) {}
-
- int vm_tid() const { return vm_tid_; }
-
- private:
- const int vm_tid_;
-};
-
-
-class SignalSender : public Thread {
- public:
- enum SleepInterval {
- HALF_INTERVAL,
- FULL_INTERVAL
- };
-
- static const int kSignalSenderStackSize = 32 * KB;
-
- explicit SignalSender(int interval)
- : Thread("SignalSender"),
- vm_tgid_(getpid()),
- interval_(interval) {}
-
- static void InstallSignalHandler() {
- struct sigaction sa;
- sa.sa_sigaction = ProfilerSignalHandler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_SIGINFO;
- signal_handler_installed_ =
- (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
- }
-
- static void RestoreSignalHandler() {
- if (signal_handler_installed_) {
- sigaction(SIGPROF, &old_signal_handler_, 0);
- signal_handler_installed_ = false;
- }
- }
-
- static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::AddActiveSampler(sampler);
- if (instance_ == NULL) {
- // Start a thread that will send SIGPROF signal to VM threads,
- // when CPU profiling will be enabled.
- instance_ = new SignalSender(sampler->interval());
- instance_->Start();
- } else {
- ASSERT(instance_->interval_ == sampler->interval());
- }
- }
-
- static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::RemoveActiveSampler(sampler);
- if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
- RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
- delete instance_;
- instance_ = NULL;
- RestoreSignalHandler();
- }
- }
-
- // Implement Thread::Run().
- virtual void Run() {
- SamplerRegistry::State state;
- while ((state = SamplerRegistry::GetState()) !=
- SamplerRegistry::HAS_NO_SAMPLERS) {
- bool cpu_profiling_enabled =
- (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
- bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
- if (cpu_profiling_enabled && !signal_handler_installed_) {
- InstallSignalHandler();
- } else if (!cpu_profiling_enabled && signal_handler_installed_) {
- RestoreSignalHandler();
- }
- // When CPU profiling is enabled both JavaScript and C++ code is
- // profiled. We must not suspend.
- if (!cpu_profiling_enabled) {
- if (rate_limiter_.SuspendIfNecessary()) continue;
- }
- if (cpu_profiling_enabled && runtime_profiler_enabled) {
- if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
- return;
- }
- Sleep(HALF_INTERVAL);
- if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
- return;
- }
- Sleep(HALF_INTERVAL);
- } else {
- if (cpu_profiling_enabled) {
- if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
- this)) {
- return;
- }
- }
- if (runtime_profiler_enabled) {
- if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
- NULL)) {
- return;
- }
- }
- Sleep(FULL_INTERVAL);
- }
- }
- }
-
- static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
- if (!sampler->IsProfiling()) return;
- SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
- sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
- }
-
- static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
- if (!sampler->isolate()->IsInitialized()) return;
- sampler->isolate()->runtime_profiler()->NotifyTick();
- }
-
- void SendProfilingSignal(int tid) {
- if (!signal_handler_installed_) return;
- pthread_kill(tid, SIGPROF);
- }
-
- void Sleep(SleepInterval full_or_half) {
- // Convert ms to us and subtract 100 us to compensate delays
- // occuring during signal delivery.
- useconds_t interval = interval_ * 1000 - 100;
- if (full_or_half == HALF_INTERVAL) interval /= 2;
- int result = usleep(interval);
-#ifdef DEBUG
- if (result != 0 && errno != EINTR) {
- fprintf(stderr,
- "SignalSender usleep error; interval = %u, errno = %d\n",
- interval,
- errno);
- ASSERT(result == 0 || errno == EINTR);
- }
-#endif
- USE(result);
- }
-
- const int vm_tgid_;
- const int interval_;
- RuntimeProfilerRateLimiter rate_limiter_;
-
- // Protects the process wide state below.
- static Mutex* mutex_;
- static SignalSender* instance_;
- static bool signal_handler_installed_;
- static struct sigaction old_signal_handler_;
-
- DISALLOW_COPY_AND_ASSIGN(SignalSender);
-};
-
-
-Mutex* SignalSender::mutex_ = OS::CreateMutex();
-SignalSender* SignalSender::instance_ = NULL;
-struct sigaction SignalSender::old_signal_handler_;
-bool SignalSender::signal_handler_installed_ = false;
-
-
-Sampler::Sampler(Isolate* isolate, int interval)
- : isolate_(isolate),
- interval_(interval),
- profiling_(false),
- active_(false),
- samples_taken_(0) {
- data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
- ASSERT(!IsActive());
- delete data_;
-}
-
-
-void Sampler::Start() {
- ASSERT(!IsActive());
- SetActive(true);
- SignalSender::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
- ASSERT(IsActive());
- SignalSender::RemoveActiveSampler(this);
- SetActive(false);
-}
-
-
-} } // namespace v8::internal
diff --git a/src/3rdparty/v8/src/platform-solaris.cc b/src/3rdparty/v8/src/platform-solaris.cc
index be8bbfc..4248ea2 100644
--- a/src/3rdparty/v8/src/platform-solaris.cc
+++ b/src/3rdparty/v8/src/platform-solaris.cc
@@ -487,12 +487,10 @@ void Thread::set_name(const char* name) {
void Thread::Start() {
- pthread_attr_t* attr_ptr = NULL;
pthread_attr_t attr;
if (stack_size_ > 0) {
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
- attr_ptr = &attr;
}
pthread_create(&data_->thread_, NULL, ThreadEntry, this);
ASSERT(data_->thread_ != kNoThread);
@@ -712,11 +710,8 @@ class SignalSender : public Thread {
: Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
interval_(interval) {}
- static void SetUp() {
- if (!mutex_) {
- mutex_ = OS::CreateMutex();
- }
- }
+ static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
+ static void TearDown() { delete mutex_; }
static void InstallSignalHandler() {
struct sigaction sa;
@@ -870,6 +865,12 @@ void OS::SetUp() {
}
+void OS::TearDown() {
+ SignalSender::TearDown();
+ delete limit_mutex;
+}
+
+
Sampler::Sampler(Isolate* isolate, int interval)
: isolate_(isolate),
interval_(interval),
diff --git a/src/3rdparty/v8/src/platform-win32.cc b/src/3rdparty/v8/src/platform-win32.cc
index aa16c85..2473949 100644
--- a/src/3rdparty/v8/src/platform-win32.cc
+++ b/src/3rdparty/v8/src/platform-win32.cc
@@ -1848,14 +1848,26 @@ bool Win32Socket::Shutdown() {
int Win32Socket::Send(const char* data, int len) const {
- int status = send(socket_, data, len, 0);
- return status;
+ if (len <= 0) return 0;
+ int written = 0;
+ while (written < len) {
+ int status = send(socket_, data + written, len - written, 0);
+ if (status == 0) {
+ break;
+ } else if (status > 0) {
+ written += status;
+ } else {
+ return 0;
+ }
+ }
+ return written;
}
int Win32Socket::Receive(char* data, int len) const {
+ if (len <= 0) return 0;
int status = recv(socket_, data, len, 0);
- return status;
+ return (status == SOCKET_ERROR) ? 0 : status;
}
@@ -1949,11 +1961,8 @@ class SamplerThread : public Thread {
: Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
interval_(interval) {}
- static void SetUp() {
- if (!mutex_) {
- mutex_ = OS::CreateMutex();
- }
- }
+ static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
+ static void TearDown() { delete mutex_; }
static void AddActiveSampler(Sampler* sampler) {
ScopedLock lock(mutex_);
@@ -2078,6 +2087,12 @@ void OS::SetUp() {
}
+void OS::TearDown() {
+ SamplerThread::TearDown();
+ delete limit_mutex;
+}
+
+
Sampler::Sampler(Isolate* isolate, int interval)
: isolate_(isolate),
interval_(interval),
diff --git a/src/3rdparty/v8/src/platform.h b/src/3rdparty/v8/src/platform.h
index 3b2aa3c..a2ddf7a 100644
--- a/src/3rdparty/v8/src/platform.h
+++ b/src/3rdparty/v8/src/platform.h
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -123,6 +123,9 @@ class OS {
// called after CPU initialization.
static void PostSetUp();
+ // Clean up platform-OS-related things. Called once at VM shutdown.
+ static void TearDown();
+
// Returns the accumulated user time for thread. This routine
// can be used for profiling. The implementation should
// strive for high-precision timer resolution, preferable
@@ -650,6 +653,7 @@ class Socket {
virtual bool Shutdown() = 0;
// Data Transimission
+ // Return 0 on failure.
virtual int Send(const char* data, int len) const = 0;
virtual int Receive(char* data, int len) const = 0;
diff --git a/src/3rdparty/v8/src/preparser.cc b/src/3rdparty/v8/src/preparser.cc
index 20d3b9c..0c17eec 100644
--- a/src/3rdparty/v8/src/preparser.cc
+++ b/src/3rdparty/v8/src/preparser.cc
@@ -581,9 +581,8 @@ PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
ParseExpression(true, CHECK_OK);
Expect(i::Token::RPAREN, CHECK_OK);
- scope_->EnterWith();
+ Scope::InsideWith iw(scope_);
ParseStatement(CHECK_OK);
- scope_->LeaveWith();
return Statement::Default();
}
@@ -749,10 +748,9 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
return Statement::Default();
}
Expect(i::Token::RPAREN, CHECK_OK);
- scope_->EnterWith();
- ParseBlock(ok);
- scope_->LeaveWith();
- if (!*ok) Statement::Default();
+ { Scope::InsideWith iw(scope_);
+ ParseBlock(CHECK_OK);
+ }
catch_or_finally_seen = true;
}
if (peek() == i::Token::FINALLY) {
diff --git a/src/3rdparty/v8/src/preparser.h b/src/3rdparty/v8/src/preparser.h
index f3a4347..13261f7 100644
--- a/src/3rdparty/v8/src/preparser.h
+++ b/src/3rdparty/v8/src/preparser.h
@@ -470,8 +470,19 @@ class PreParser {
void set_language_mode(i::LanguageMode language_mode) {
language_mode_ = language_mode;
}
- void EnterWith() { with_nesting_count_++; }
- void LeaveWith() { with_nesting_count_--; }
+
+ class InsideWith {
+ public:
+ explicit InsideWith(Scope* scope) : scope_(scope) {
+ scope->with_nesting_count_++;
+ }
+
+ ~InsideWith() { scope_->with_nesting_count_--; }
+
+ private:
+ Scope* scope_;
+ DISALLOW_COPY_AND_ASSIGN(InsideWith);
+ };
private:
Scope** const variable_;
diff --git a/src/3rdparty/v8/src/prettyprinter.cc b/src/3rdparty/v8/src/prettyprinter.cc
index 16eb85a..0d8dadc 100644
--- a/src/3rdparty/v8/src/prettyprinter.cc
+++ b/src/3rdparty/v8/src/prettyprinter.cc
@@ -672,9 +672,6 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info,
EmbeddedVector<char, 256> buf;
int pos = OS::SNPrintF(buf, "%s (mode = %s", info,
Variable::Mode2String(var->mode()));
- if (var->is_qml_global()) {
- pos += OS::SNPrintF(buf + pos, ":QML");
- }
OS::SNPrintF(buf + pos, ")");
PrintLiteralIndented(buf.start(), value, true);
}
diff --git a/src/3rdparty/v8/src/profile-generator-inl.h b/src/3rdparty/v8/src/profile-generator-inl.h
index 65369be..9afc52f 100644
--- a/src/3rdparty/v8/src/profile-generator-inl.h
+++ b/src/3rdparty/v8/src/profile-generator-inl.h
@@ -95,6 +95,55 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
}
+HeapEntry* HeapGraphEdge::from() const {
+ return &snapshot()->entries()[from_index_];
+}
+
+
+HeapSnapshot* HeapGraphEdge::snapshot() const {
+ return to_entry_->snapshot();
+}
+
+
+int HeapEntry::index() const {
+ return static_cast<int>(this - &snapshot_->entries().first());
+}
+
+
+int HeapEntry::set_children_index(int index) {
+ children_index_ = index;
+ int next_index = index + children_count_;
+ children_count_ = 0;
+ return next_index;
+}
+
+
+int HeapEntry::set_retainers_index(int index) {
+ retainers_index_ = index;
+ int next_index = index + retainers_count_;
+ retainers_count_ = 0;
+ return next_index;
+}
+
+
+HeapGraphEdge** HeapEntry::children_arr() {
+ ASSERT(children_index_ >= 0);
+ return &snapshot_->children()[children_index_];
+}
+
+
+HeapGraphEdge** HeapEntry::retainers_arr() {
+ ASSERT(retainers_index_ >= 0);
+ return &snapshot_->retainers()[retainers_index_];
+}
+
+
+HeapEntry* HeapEntry::dominator() const {
+ ASSERT(dominator_ >= 0);
+ return &snapshot_->entries()[dominator_];
+}
+
+
SnapshotObjectId HeapObjectsMap::GetNthGcSubrootId(int delta) {
return kGcRootsFirstSubrootId + delta * kObjectIdStep;
}
diff --git a/src/3rdparty/v8/src/profile-generator.cc b/src/3rdparty/v8/src/profile-generator.cc
index 9bea610..da2a969 100644
--- a/src/3rdparty/v8/src/profile-generator.cc
+++ b/src/3rdparty/v8/src/profile-generator.cc
@@ -34,6 +34,7 @@
#include "scopeinfo.h"
#include "unicode.h"
#include "zone-inl.h"
+#include "debug.h"
namespace v8 {
namespace internal {
@@ -930,82 +931,71 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
}
-void HeapGraphEdge::Init(
- int child_index, Type type, const char* name, HeapEntry* to) {
+HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to)
+ : type_(type),
+ from_index_(from),
+ to_index_(to),
+ name_(name) {
ASSERT(type == kContextVariable
- || type == kProperty
- || type == kInternal
- || type == kShortcut);
- child_index_ = child_index;
- type_ = type;
- name_ = name;
- to_ = to;
+ || type == kProperty
+ || type == kInternal
+ || type == kShortcut);
}
-void HeapGraphEdge::Init(int child_index, Type type, int index, HeapEntry* to) {
+HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to)
+ : type_(type),
+ from_index_(from),
+ to_index_(to),
+ index_(index) {
ASSERT(type == kElement || type == kHidden || type == kWeak);
- child_index_ = child_index;
- type_ = type;
- index_ = index;
- to_ = to;
}
-void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) {
- Init(child_index, kElement, index, to);
+void HeapGraphEdge::ReplaceToIndexWithEntry(HeapSnapshot* snapshot) {
+ to_entry_ = &snapshot->entries()[to_index_];
}
-HeapEntry* HeapGraphEdge::From() {
- return reinterpret_cast<HeapEntry*>(this - child_index_) - 1;
-}
-
+const int HeapEntry::kNoEntry = -1;
-void HeapEntry::Init(HeapSnapshot* snapshot,
+HeapEntry::HeapEntry(HeapSnapshot* snapshot,
Type type,
const char* name,
SnapshotObjectId id,
- int self_size,
- int children_count,
- int retainers_count) {
- snapshot_ = snapshot;
- type_ = type;
- painted_ = false;
- name_ = name;
- self_size_ = self_size;
- retained_size_ = 0;
- entry_index_ = -1;
- children_count_ = children_count;
- retainers_count_ = retainers_count;
- dominator_ = NULL;
- id_ = id;
-}
+ int self_size)
+ : painted_(false),
+ user_reachable_(false),
+ dominator_(kNoEntry),
+ type_(type),
+ retainers_count_(0),
+ retainers_index_(-1),
+ children_count_(0),
+ children_index_(-1),
+ self_size_(self_size),
+ retained_size_(0),
+ id_(id),
+ snapshot_(snapshot),
+ name_(name) { }
void HeapEntry::SetNamedReference(HeapGraphEdge::Type type,
- int child_index,
const char* name,
- HeapEntry* entry,
- int retainer_index) {
- children()[child_index].Init(child_index, type, name, entry);
- entry->retainers()[retainer_index] = children_arr() + child_index;
+ HeapEntry* entry) {
+ HeapGraphEdge edge(type, name, this->index(), entry->index());
+ snapshot_->edges().Add(edge);
+ ++children_count_;
+ ++entry->retainers_count_;
}
void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type,
- int child_index,
int index,
- HeapEntry* entry,
- int retainer_index) {
- children()[child_index].Init(child_index, type, index, entry);
- entry->retainers()[retainer_index] = children_arr() + child_index;
-}
-
-
-void HeapEntry::SetUnidirElementReference(
- int child_index, int index, HeapEntry* entry) {
- children()[child_index].Init(child_index, index, entry);
+ HeapEntry* entry) {
+ HeapGraphEdge edge(type, index, this->index(), entry->index());
+ snapshot_->edges().Add(edge);
+ ++children_count_;
+ ++entry->retainers_count_;
}
@@ -1016,7 +1006,8 @@ Handle<HeapObject> HeapEntry::GetHeapObject() {
void HeapEntry::Print(
const char* prefix, const char* edge_name, int max_depth, int indent) {
- OS::Print("%6d %7d @%6llu %*c %s%s: ",
+ STATIC_CHECK(sizeof(unsigned) == sizeof(id()));
+ OS::Print("%6d %7d @%6u %*c %s%s: ",
self_size(), retained_size(), id(),
indent, ' ', prefix, edge_name);
if (type() != kString) {
@@ -1034,9 +1025,9 @@ void HeapEntry::Print(
OS::Print("\"\n");
}
if (--max_depth == 0) return;
- Vector<HeapGraphEdge> ch = children();
+ Vector<HeapGraphEdge*> ch = children();
for (int i = 0; i < ch.length(); ++i) {
- HeapGraphEdge& edge = ch[i];
+ HeapGraphEdge& edge = *ch[i];
const char* edge_prefix = "";
EmbeddedVector<char, 64> index;
const char* edge_name = index.start();
@@ -1092,15 +1083,6 @@ const char* HeapEntry::TypeAsString() {
}
-size_t HeapEntry::EntriesSize(int entries_count,
- int children_count,
- int retainers_count) {
- return sizeof(HeapEntry) * entries_count // NOLINT
- + sizeof(HeapGraphEdge) * children_count // NOLINT
- + sizeof(HeapGraphEdge*) * retainers_count; // NOLINT
-}
-
-
// It is very important to keep objects that form a heap snapshot
// as small as possible.
namespace { // Avoid littering the global namespace.
@@ -1109,7 +1091,7 @@ template <size_t ptr_size> struct SnapshotSizeConstants;
template <> struct SnapshotSizeConstants<4> {
static const int kExpectedHeapGraphEdgeSize = 12;
- static const int kExpectedHeapEntrySize = 36;
+ static const int kExpectedHeapEntrySize = 40;
static const size_t kMaxSerializableSnapshotRawSize = 256 * MB;
};
@@ -1130,10 +1112,9 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
type_(type),
title_(title),
uid_(uid),
- root_entry_(NULL),
- gc_roots_entry_(NULL),
- natives_root_entry_(NULL),
- raw_entries_(NULL),
+ root_index_(HeapEntry::kNoEntry),
+ gc_roots_index_(HeapEntry::kNoEntry),
+ natives_root_index_(HeapEntry::kNoEntry),
max_snapshot_js_object_id_(0) {
STATIC_CHECK(
sizeof(HeapGraphEdge) ==
@@ -1142,16 +1123,11 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
sizeof(HeapEntry) ==
SnapshotSizeConstants<kPointerSize>::kExpectedHeapEntrySize);
for (int i = 0; i < VisitorSynchronization::kNumberOfSyncTags; ++i) {
- gc_subroot_entries_[i] = NULL;
+ gc_subroot_indexes_[i] = HeapEntry::kNoEntry;
}
}
-HeapSnapshot::~HeapSnapshot() {
- DeleteArray(raw_entries_);
-}
-
-
void HeapSnapshot::Delete() {
collection_->RemoveSnapshot(this);
delete this;
@@ -1163,18 +1139,8 @@ void HeapSnapshot::RememberLastJSObjectId() {
}
-void HeapSnapshot::AllocateEntries(int entries_count,
- int children_count,
- int retainers_count) {
- ASSERT(raw_entries_ == NULL);
- raw_entries_size_ =
- HeapEntry::EntriesSize(entries_count, children_count, retainers_count);
- raw_entries_ = NewArray<char>(raw_entries_size_);
-}
-
-
-static void HeapEntryClearPaint(HeapEntry** entry_ptr) {
- (*entry_ptr)->clear_paint();
+static void HeapEntryClearPaint(HeapEntry* entry_ptr) {
+ entry_ptr->clear_paint();
}
@@ -1183,97 +1149,102 @@ void HeapSnapshot::ClearPaint() {
}
-HeapEntry* HeapSnapshot::AddRootEntry(int children_count) {
- ASSERT(root_entry_ == NULL);
+HeapEntry* HeapSnapshot::AddRootEntry() {
+ ASSERT(root_index_ == HeapEntry::kNoEntry);
ASSERT(entries_.is_empty()); // Root entry must be the first one.
- return (root_entry_ = AddEntry(HeapEntry::kObject,
- "",
- HeapObjectsMap::kInternalRootObjectId,
- 0,
- children_count,
- 0));
+ HeapEntry* entry = AddEntry(HeapEntry::kObject,
+ "",
+ HeapObjectsMap::kInternalRootObjectId,
+ 0);
+ root_index_ = entry->index();
+ ASSERT(root_index_ == 0);
+ return entry;
}
-HeapEntry* HeapSnapshot::AddGcRootsEntry(int children_count,
- int retainers_count) {
- ASSERT(gc_roots_entry_ == NULL);
- return (gc_roots_entry_ = AddEntry(HeapEntry::kObject,
- "(GC roots)",
- HeapObjectsMap::kGcRootsObjectId,
- 0,
- children_count,
- retainers_count));
+HeapEntry* HeapSnapshot::AddGcRootsEntry() {
+ ASSERT(gc_roots_index_ == HeapEntry::kNoEntry);
+ HeapEntry* entry = AddEntry(HeapEntry::kObject,
+ "(GC roots)",
+ HeapObjectsMap::kGcRootsObjectId,
+ 0);
+ gc_roots_index_ = entry->index();
+ return entry;
}
-HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag,
- int children_count,
- int retainers_count) {
- ASSERT(gc_subroot_entries_[tag] == NULL);
+HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag) {
+ ASSERT(gc_subroot_indexes_[tag] == HeapEntry::kNoEntry);
ASSERT(0 <= tag && tag < VisitorSynchronization::kNumberOfSyncTags);
- return (gc_subroot_entries_[tag] = AddEntry(
+ HeapEntry* entry = AddEntry(
HeapEntry::kObject,
VisitorSynchronization::kTagNames[tag],
HeapObjectsMap::GetNthGcSubrootId(tag),
- 0,
- children_count,
- retainers_count));
+ 0);
+ gc_subroot_indexes_[tag] = entry->index();
+ return entry;
}
HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
const char* name,
SnapshotObjectId id,
- int size,
- int children_count,
- int retainers_count) {
- HeapEntry* entry = GetNextEntryToInit();
- entry->Init(this, type, name, id, size, children_count, retainers_count);
- return entry;
+ int size) {
+ HeapEntry entry(this, type, name, id, size);
+ entries_.Add(entry);
+ return &entries_.last();
+}
+
+
+void HeapSnapshot::FillChildrenAndRetainers() {
+ ASSERT(children().is_empty());
+ children().Allocate(edges().length());
+ ASSERT(retainers().is_empty());
+ retainers().Allocate(edges().length());
+ int children_index = 0;
+ int retainers_index = 0;
+ for (int i = 0; i < entries().length(); ++i) {
+ HeapEntry* entry = &entries()[i];
+ children_index = entry->set_children_index(children_index);
+ retainers_index = entry->set_retainers_index(retainers_index);
+ }
+ ASSERT(edges().length() == children_index);
+ ASSERT(edges().length() == retainers_index);
+ for (int i = 0; i < edges().length(); ++i) {
+ HeapGraphEdge* edge = &edges()[i];
+ edge->ReplaceToIndexWithEntry(this);
+ edge->from()->add_child(edge);
+ edge->to()->add_retainer(edge);
+ }
}
void HeapSnapshot::SetDominatorsToSelf() {
for (int i = 0; i < entries_.length(); ++i) {
- HeapEntry* entry = entries_[i];
- if (entry->dominator() == NULL) entry->set_dominator(entry);
+ entries_[i].set_dominator(&entries_[i]);
}
}
-HeapEntry* HeapSnapshot::GetNextEntryToInit() {
- if (entries_.length() > 0) {
- HeapEntry* last_entry = entries_.last();
- entries_.Add(reinterpret_cast<HeapEntry*>(
- reinterpret_cast<char*>(last_entry) + last_entry->EntrySize()));
- } else {
- entries_.Add(reinterpret_cast<HeapEntry*>(raw_entries_));
+class FindEntryById {
+ public:
+ explicit FindEntryById(SnapshotObjectId id) : id_(id) { }
+ int operator()(HeapEntry* const* entry) {
+ if ((*entry)->id() == id_) return 0;
+ return (*entry)->id() < id_ ? -1 : 1;
}
- ASSERT(reinterpret_cast<char*>(entries_.last()) <
- (raw_entries_ + raw_entries_size_));
- return entries_.last();
-}
+ private:
+ SnapshotObjectId id_;
+};
HeapEntry* HeapSnapshot::GetEntryById(SnapshotObjectId id) {
List<HeapEntry*>* entries_by_id = GetSortedEntriesList();
-
// Perform a binary search by id.
- int low = 0;
- int high = entries_by_id->length() - 1;
- while (low <= high) {
- int mid =
- (static_cast<unsigned int>(low) + static_cast<unsigned int>(high)) >> 1;
- SnapshotObjectId mid_id = entries_by_id->at(mid)->id();
- if (mid_id > id)
- high = mid - 1;
- else if (mid_id < id)
- low = mid + 1;
- else
- return entries_by_id->at(mid);
- }
- return NULL;
+ int index = SortedListBSearch(*entries_by_id, FindEntryById(id));
+ if (index == -1)
+ return NULL;
+ return entries_by_id->at(index);
}
@@ -1287,7 +1258,10 @@ static int SortByIds(const T* entry1_ptr,
List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() {
if (sorted_entries_.is_empty()) {
- sorted_entries_.AddAll(entries_);
+ sorted_entries_.Allocate(entries_.length());
+ for (int i = 0; i < entries_.length(); ++i) {
+ sorted_entries_[i] = &entries_[i];
+ }
sorted_entries_.Sort(SortByIds);
}
return &sorted_entries_;
@@ -1299,6 +1273,22 @@ void HeapSnapshot::Print(int max_depth) {
}
+template<typename T, class P>
+static size_t GetMemoryUsedByList(const List<T, P>& list) {
+ return list.capacity() * sizeof(T);
+}
+
+
+size_t HeapSnapshot::RawSnapshotSize() const {
+ return
+ GetMemoryUsedByList(entries_) +
+ GetMemoryUsedByList(edges_) +
+ GetMemoryUsedByList(children_) +
+ GetMemoryUsedByList(retainers_) +
+ GetMemoryUsedByList(sorted_entries_);
+}
+
+
// We split IDs on evens for embedder objects (see
// HeapObjectsMap::GenerateId) and odds for native objects.
const SnapshotObjectId HeapObjectsMap::kInternalRootObjectId = 1;
@@ -1311,96 +1301,166 @@ const SnapshotObjectId HeapObjectsMap::kFirstAvailableObjectId =
VisitorSynchronization::kNumberOfSyncTags * HeapObjectsMap::kObjectIdStep;
HeapObjectsMap::HeapObjectsMap()
- : initial_fill_mode_(true),
- next_id_(kFirstAvailableObjectId),
- entries_map_(AddressesMatch),
- entries_(new List<EntryInfo>()) { }
-
-
-HeapObjectsMap::~HeapObjectsMap() {
- delete entries_;
+ : next_id_(kFirstAvailableObjectId),
+ entries_map_(AddressesMatch) {
+ // This dummy element solves a problem with entries_map_.
+ // When we do lookup in HashMap we see no difference between two cases:
+ // it has an entry with NULL as the value or it has created
+ // a new entry on the fly with NULL as the default value.
+ // With such dummy element we have a guaranty that all entries_map_ entries
+ // will have the value field grater than 0.
+ // This fact is using in MoveObject method.
+ entries_.Add(EntryInfo(0, NULL, 0));
}
void HeapObjectsMap::SnapshotGenerationFinished() {
- initial_fill_mode_ = false;
RemoveDeadEntries();
}
-SnapshotObjectId HeapObjectsMap::FindObject(Address addr) {
- if (!initial_fill_mode_) {
- SnapshotObjectId existing = FindEntry(addr);
- if (existing != 0) return existing;
- }
- SnapshotObjectId id = next_id_;
- next_id_ += kObjectIdStep;
- AddEntry(addr, id);
- return id;
-}
-
-
void HeapObjectsMap::MoveObject(Address from, Address to) {
+ ASSERT(to != NULL);
+ ASSERT(from != NULL);
if (from == to) return;
- HashMap::Entry* entry = entries_map_.Lookup(from, AddressHash(from), false);
- if (entry != NULL) {
- void* value = entry->value;
- entries_map_.Remove(from, AddressHash(from));
- if (to != NULL) {
- entry = entries_map_.Lookup(to, AddressHash(to), true);
- // We can have an entry at the new location, it is OK, as GC can overwrite
- // dead objects with alive objects being moved.
- entry->value = value;
- }
+ void* from_value = entries_map_.Remove(from, AddressHash(from));
+ if (from_value == NULL) return;
+ int from_entry_info_index =
+ static_cast<int>(reinterpret_cast<intptr_t>(from_value));
+ entries_.at(from_entry_info_index).addr = to;
+ HashMap::Entry* to_entry = entries_map_.Lookup(to, AddressHash(to), true);
+ if (to_entry->value != NULL) {
+ int to_entry_info_index =
+ static_cast<int>(reinterpret_cast<intptr_t>(to_entry->value));
+ // Without this operation we will have two EntryInfo's with the same
+ // value in addr field. It is bad because later at RemoveDeadEntries
+ // one of this entry will be removed with the corresponding entries_map_
+ // entry.
+ entries_.at(to_entry_info_index).addr = NULL;
}
+ to_entry->value = reinterpret_cast<void*>(from_entry_info_index);
}
-void HeapObjectsMap::AddEntry(Address addr, SnapshotObjectId id) {
- HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), true);
- ASSERT(entry->value == NULL);
- entry->value = reinterpret_cast<void*>(entries_->length());
- entries_->Add(EntryInfo(id));
+SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) {
+ HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), false);
+ if (entry == NULL) return 0;
+ int entry_index = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
+ EntryInfo& entry_info = entries_.at(entry_index);
+ ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy());
+ return entry_info.id;
}
-SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) {
- HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), false);
- if (entry != NULL) {
+SnapshotObjectId HeapObjectsMap::FindOrAddEntry(Address addr,
+ unsigned int size) {
+ ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy());
+ HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), true);
+ if (entry->value != NULL) {
int entry_index =
static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
- EntryInfo& entry_info = entries_->at(entry_index);
+ EntryInfo& entry_info = entries_.at(entry_index);
entry_info.accessed = true;
+ entry_info.size = size;
return entry_info.id;
- } else {
- return 0;
}
+ entry->value = reinterpret_cast<void*>(entries_.length());
+ SnapshotObjectId id = next_id_;
+ next_id_ += kObjectIdStep;
+ entries_.Add(EntryInfo(id, addr, size));
+ ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy());
+ return id;
+}
+
+
+void HeapObjectsMap::StopHeapObjectsTracking() {
+ time_intervals_.Clear();
+}
+
+void HeapObjectsMap::UpdateHeapObjectsMap() {
+ HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask,
+ "HeapSnapshotsCollection::UpdateHeapObjectsMap");
+ HeapIterator iterator;
+ for (HeapObject* obj = iterator.next();
+ obj != NULL;
+ obj = iterator.next()) {
+ FindOrAddEntry(obj->address(), obj->Size());
+ }
+ RemoveDeadEntries();
+}
+
+
+void HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) {
+ UpdateHeapObjectsMap();
+ time_intervals_.Add(TimeInterval(next_id_));
+ int prefered_chunk_size = stream->GetChunkSize();
+ List<v8::HeapStatsUpdate> stats_buffer;
+ ASSERT(!entries_.is_empty());
+ EntryInfo* entry_info = &entries_.first();
+ EntryInfo* end_entry_info = &entries_.last() + 1;
+ for (int time_interval_index = 0;
+ time_interval_index < time_intervals_.length();
+ ++time_interval_index) {
+ TimeInterval& time_interval = time_intervals_[time_interval_index];
+ SnapshotObjectId time_interval_id = time_interval.id;
+ uint32_t entries_size = 0;
+ EntryInfo* start_entry_info = entry_info;
+ while (entry_info < end_entry_info && entry_info->id < time_interval_id) {
+ entries_size += entry_info->size;
+ ++entry_info;
+ }
+ uint32_t entries_count =
+ static_cast<uint32_t>(entry_info - start_entry_info);
+ if (time_interval.count != entries_count ||
+ time_interval.size != entries_size) {
+ stats_buffer.Add(v8::HeapStatsUpdate(
+ time_interval_index,
+ time_interval.count = entries_count,
+ time_interval.size = entries_size));
+ if (stats_buffer.length() >= prefered_chunk_size) {
+ OutputStream::WriteResult result = stream->WriteHeapStatsChunk(
+ &stats_buffer.first(), stats_buffer.length());
+ if (result == OutputStream::kAbort) return;
+ stats_buffer.Clear();
+ }
+ }
+ }
+ ASSERT(entry_info == end_entry_info);
+ if (!stats_buffer.is_empty()) {
+ OutputStream::WriteResult result = stream->WriteHeapStatsChunk(
+ &stats_buffer.first(), stats_buffer.length());
+ if (result == OutputStream::kAbort) return;
+ }
+ stream->EndOfStream();
}
void HeapObjectsMap::RemoveDeadEntries() {
- List<EntryInfo>* new_entries = new List<EntryInfo>();
- List<void*> dead_entries;
- for (HashMap::Entry* entry = entries_map_.Start();
- entry != NULL;
- entry = entries_map_.Next(entry)) {
- int entry_index =
- static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
- EntryInfo& entry_info = entries_->at(entry_index);
+ ASSERT(entries_.length() > 0 &&
+ entries_.at(0).id == 0 &&
+ entries_.at(0).addr == NULL);
+ int first_free_entry = 1;
+ for (int i = 1; i < entries_.length(); ++i) {
+ EntryInfo& entry_info = entries_.at(i);
if (entry_info.accessed) {
- entry->value = reinterpret_cast<void*>(new_entries->length());
- new_entries->Add(EntryInfo(entry_info.id, false));
+ if (first_free_entry != i) {
+ entries_.at(first_free_entry) = entry_info;
+ }
+ entries_.at(first_free_entry).accessed = false;
+ HashMap::Entry* entry = entries_map_.Lookup(
+ entry_info.addr, AddressHash(entry_info.addr), false);
+ ASSERT(entry);
+ entry->value = reinterpret_cast<void*>(first_free_entry);
+ ++first_free_entry;
} else {
- dead_entries.Add(entry->key);
+ if (entry_info.addr) {
+ entries_map_.Remove(entry_info.addr, AddressHash(entry_info.addr));
+ }
}
}
- for (int i = 0; i < dead_entries.length(); ++i) {
- void* raw_entry = dead_entries[i];
- entries_map_.Remove(
- raw_entry, AddressHash(reinterpret_cast<Address>(raw_entry)));
- }
- delete entries_;
- entries_ = new_entries;
+ entries_.Rewind(first_free_entry);
+ ASSERT(static_cast<uint32_t>(entries_.length()) - 1 ==
+ entries_map_.occupancy());
}
@@ -1487,7 +1547,7 @@ Handle<HeapObject> HeapSnapshotsCollection::FindHeapObjectById(
for (HeapObject* obj = iterator.next();
obj != NULL;
obj = iterator.next()) {
- if (ids_.FindObject(obj->address()) == id) {
+ if (ids_.FindEntry(obj->address()) == id) {
ASSERT(object == NULL);
object = obj;
// Can't break -- kFilterUnreachable requires full heap traversal.
@@ -1497,99 +1557,22 @@ Handle<HeapObject> HeapSnapshotsCollection::FindHeapObjectById(
}
-HeapEntry* const HeapEntriesMap::kHeapEntryPlaceholder =
- reinterpret_cast<HeapEntry*>(1);
-
HeapEntriesMap::HeapEntriesMap()
- : entries_(HeapThingsMatch),
- entries_count_(0),
- total_children_count_(0),
- total_retainers_count_(0) {
-}
-
-
-HeapEntriesMap::~HeapEntriesMap() {
- for (HashMap::Entry* p = entries_.Start(); p != NULL; p = entries_.Next(p)) {
- delete reinterpret_cast<EntryInfo*>(p->value);
- }
+ : entries_(HeapThingsMatch) {
}
-void HeapEntriesMap::AllocateHeapEntryForMapEntry(HashMap::Entry* map_entry) {
- EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(map_entry->value);
- entry_info->entry = entry_info->allocator->AllocateEntry(
- map_entry->key,
- entry_info->children_count,
- entry_info->retainers_count);
- ASSERT(entry_info->entry != NULL);
- ASSERT(entry_info->entry != kHeapEntryPlaceholder);
- entry_info->children_count = 0;
- entry_info->retainers_count = 0;
-}
-
-
-void HeapEntriesMap::AllocateEntries(HeapThing root_object) {
- HashMap::Entry* root_entry =
- entries_.Lookup(root_object, Hash(root_object), false);
- ASSERT(root_entry != NULL);
- // Make sure root entry is allocated first.
- AllocateHeapEntryForMapEntry(root_entry);
- void* root_entry_value = root_entry->value;
- // Remove the root object from map while iterating through other entries.
- entries_.Remove(root_object, Hash(root_object));
- root_entry = NULL;
-
- for (HashMap::Entry* p = entries_.Start();
- p != NULL;
- p = entries_.Next(p)) {
- AllocateHeapEntryForMapEntry(p);
- }
-
- // Insert root entry back.
- root_entry = entries_.Lookup(root_object, Hash(root_object), true);
- root_entry->value = root_entry_value;
-}
-
-
-HeapEntry* HeapEntriesMap::Map(HeapThing thing) {
+int HeapEntriesMap::Map(HeapThing thing) {
HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), false);
- if (cache_entry != NULL) {
- EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(cache_entry->value);
- return entry_info->entry;
- } else {
- return NULL;
- }
+ if (cache_entry == NULL) return HeapEntry::kNoEntry;
+ return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value));
}
-void HeapEntriesMap::Pair(
- HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry) {
+void HeapEntriesMap::Pair(HeapThing thing, int entry) {
HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), true);
ASSERT(cache_entry->value == NULL);
- cache_entry->value = new EntryInfo(entry, allocator);
- ++entries_count_;
-}
-
-
-void HeapEntriesMap::CountReference(HeapThing from, HeapThing to,
- int* prev_children_count,
- int* prev_retainers_count) {
- HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), false);
- HashMap::Entry* to_cache_entry = entries_.Lookup(to, Hash(to), false);
- ASSERT(from_cache_entry != NULL);
- ASSERT(to_cache_entry != NULL);
- EntryInfo* from_entry_info =
- reinterpret_cast<EntryInfo*>(from_cache_entry->value);
- EntryInfo* to_entry_info =
- reinterpret_cast<EntryInfo*>(to_cache_entry->value);
- if (prev_children_count)
- *prev_children_count = from_entry_info->children_count;
- if (prev_retainers_count)
- *prev_retainers_count = to_entry_info->retainers_count;
- ++from_entry_info->children_count;
- ++to_entry_info->retainers_count;
- ++total_children_count_;
- ++total_retainers_count_;
+ cache_entry->value = reinterpret_cast<void*>(static_cast<intptr_t>(entry));
}
@@ -1606,20 +1589,14 @@ void HeapObjectsSet::Clear() {
bool HeapObjectsSet::Contains(Object* obj) {
if (!obj->IsHeapObject()) return false;
HeapObject* object = HeapObject::cast(obj);
- HashMap::Entry* cache_entry =
- entries_.Lookup(object, HeapEntriesMap::Hash(object), false);
- return cache_entry != NULL;
+ return entries_.Lookup(object, HeapEntriesMap::Hash(object), false) != NULL;
}
void HeapObjectsSet::Insert(Object* obj) {
if (!obj->IsHeapObject()) return;
HeapObject* object = HeapObject::cast(obj);
- HashMap::Entry* cache_entry =
- entries_.Lookup(object, HeapEntriesMap::Hash(object), true);
- if (cache_entry->value == NULL) {
- cache_entry->value = HeapEntriesMap::kHeapEntryPlaceholder;
- }
+ entries_.Lookup(object, HeapEntriesMap::Hash(object), true);
}
@@ -1627,12 +1604,9 @@ const char* HeapObjectsSet::GetTag(Object* obj) {
HeapObject* object = HeapObject::cast(obj);
HashMap::Entry* cache_entry =
entries_.Lookup(object, HeapEntriesMap::Hash(object), false);
- if (cache_entry != NULL
- && cache_entry->value != HeapEntriesMap::kHeapEntryPlaceholder) {
- return reinterpret_cast<const char*>(cache_entry->value);
- } else {
- return NULL;
- }
+ return cache_entry != NULL
+ ? reinterpret_cast<const char*>(cache_entry->value)
+ : NULL;
}
@@ -1674,126 +1648,83 @@ V8HeapExplorer::~V8HeapExplorer() {
}
-HeapEntry* V8HeapExplorer::AllocateEntry(
- HeapThing ptr, int children_count, int retainers_count) {
- return AddEntry(
- reinterpret_cast<HeapObject*>(ptr), children_count, retainers_count);
+HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) {
+ return AddEntry(reinterpret_cast<HeapObject*>(ptr));
}
-HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
- int children_count,
- int retainers_count) {
+HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) {
if (object == kInternalRootObject) {
- ASSERT(retainers_count == 0);
- return snapshot_->AddRootEntry(children_count);
+ snapshot_->AddRootEntry();
+ return snapshot_->root();
} else if (object == kGcRootsObject) {
- return snapshot_->AddGcRootsEntry(children_count, retainers_count);
+ HeapEntry* entry = snapshot_->AddGcRootsEntry();
+ return entry;
} else if (object >= kFirstGcSubrootObject && object < kLastGcSubrootObject) {
- return snapshot_->AddGcSubrootEntry(
- GetGcSubrootOrder(object),
- children_count,
- retainers_count);
+ HeapEntry* entry = snapshot_->AddGcSubrootEntry(GetGcSubrootOrder(object));
+ return entry;
} else if (object->IsJSFunction()) {
JSFunction* func = JSFunction::cast(object);
SharedFunctionInfo* shared = func->shared();
const char* name = shared->bound() ? "native_bind" :
collection_->names()->GetName(String::cast(shared->name()));
- return AddEntry(object,
- HeapEntry::kClosure,
- name,
- children_count,
- retainers_count);
+ return AddEntry(object, HeapEntry::kClosure, name);
} else if (object->IsJSRegExp()) {
JSRegExp* re = JSRegExp::cast(object);
return AddEntry(object,
HeapEntry::kRegExp,
- collection_->names()->GetName(re->Pattern()),
- children_count,
- retainers_count);
+ collection_->names()->GetName(re->Pattern()));
} else if (object->IsJSObject()) {
- return AddEntry(object,
- HeapEntry::kObject,
- "",
- children_count,
- retainers_count);
+ const char* name = collection_->names()->GetName(
+ GetConstructorName(JSObject::cast(object)));
+ if (object->IsJSGlobalObject()) {
+ const char* tag = objects_tags_.GetTag(object);
+ if (tag != NULL) {
+ name = collection_->names()->GetFormatted("%s / %s", name, tag);
+ }
+ }
+ return AddEntry(object, HeapEntry::kObject, name);
} else if (object->IsString()) {
return AddEntry(object,
HeapEntry::kString,
- collection_->names()->GetName(String::cast(object)),
- children_count,
- retainers_count);
+ collection_->names()->GetName(String::cast(object)));
} else if (object->IsCode()) {
- return AddEntry(object,
- HeapEntry::kCode,
- "",
- children_count,
- retainers_count);
+ return AddEntry(object, HeapEntry::kCode, "");
} else if (object->IsSharedFunctionInfo()) {
- SharedFunctionInfo* shared = SharedFunctionInfo::cast(object);
+ String* name = String::cast(SharedFunctionInfo::cast(object)->name());
return AddEntry(object,
HeapEntry::kCode,
- collection_->names()->GetName(String::cast(shared->name())),
- children_count,
- retainers_count);
+ collection_->names()->GetName(name));
} else if (object->IsScript()) {
- Script* script = Script::cast(object);
+ Object* name = Script::cast(object)->name();
return AddEntry(object,
HeapEntry::kCode,
- script->name()->IsString() ?
- collection_->names()->GetName(
- String::cast(script->name()))
- : "",
- children_count,
- retainers_count);
+ name->IsString()
+ ? collection_->names()->GetName(String::cast(name))
+ : "");
} else if (object->IsGlobalContext()) {
- return AddEntry(object,
- HeapEntry::kHidden,
- "system / GlobalContext",
- children_count,
- retainers_count);
+ return AddEntry(object, HeapEntry::kHidden, "system / GlobalContext");
} else if (object->IsContext()) {
- return AddEntry(object,
- HeapEntry::kHidden,
- "system / Context",
- children_count,
- retainers_count);
+ return AddEntry(object, HeapEntry::kHidden, "system / Context");
} else if (object->IsFixedArray() ||
object->IsFixedDoubleArray() ||
object->IsByteArray() ||
object->IsExternalArray()) {
- const char* tag = objects_tags_.GetTag(object);
- return AddEntry(object,
- HeapEntry::kArray,
- tag != NULL ? tag : "",
- children_count,
- retainers_count);
+ return AddEntry(object, HeapEntry::kArray, "");
} else if (object->IsHeapNumber()) {
- return AddEntry(object,
- HeapEntry::kHeapNumber,
- "number",
- children_count,
- retainers_count);
+ return AddEntry(object, HeapEntry::kHeapNumber, "number");
}
- return AddEntry(object,
- HeapEntry::kHidden,
- GetSystemEntryName(object),
- children_count,
- retainers_count);
+ return AddEntry(object, HeapEntry::kHidden, GetSystemEntryName(object));
}
HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
HeapEntry::Type type,
- const char* name,
- int children_count,
- int retainers_count) {
- return snapshot_->AddEntry(type,
- name,
- collection_->GetObjectId(object->address()),
- object->Size(),
- children_count,
- retainers_count);
+ const char* name) {
+ int object_size = object->Size();
+ SnapshotObjectId object_id =
+ collection_->GetObjectId(object->address(), object_size);
+ return snapshot_->AddEntry(type, name, object_id, object_size);
}
@@ -1862,10 +1793,10 @@ class IndexedReferencesExtractor : public ObjectVisitor {
public:
IndexedReferencesExtractor(V8HeapExplorer* generator,
HeapObject* parent_obj,
- HeapEntry* parent_entry)
+ int parent)
: generator_(generator),
parent_obj_(parent_obj),
- parent_(parent_entry),
+ parent_(parent),
next_index_(1) {
}
void VisitPointers(Object** start, Object** end) {
@@ -1894,178 +1825,40 @@ class IndexedReferencesExtractor : public ObjectVisitor {
}
V8HeapExplorer* generator_;
HeapObject* parent_obj_;
- HeapEntry* parent_;
+ int parent_;
int next_index_;
};
void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
- HeapEntry* entry = GetEntry(obj);
- if (entry == NULL) return; // No interest in this object.
+ HeapEntry* heap_entry = GetEntry(obj);
+ if (heap_entry == NULL) return; // No interest in this object.
+ int entry = heap_entry->index();
bool extract_indexed_refs = true;
if (obj->IsJSGlobalProxy()) {
- // We need to reference JS global objects from snapshot's root.
- // We use JSGlobalProxy because this is what embedder (e.g. browser)
- // uses for the global object.
- JSGlobalProxy* proxy = JSGlobalProxy::cast(obj);
- SetRootShortcutReference(proxy->map()->prototype());
+ ExtractJSGlobalProxyReferences(JSGlobalProxy::cast(obj));
} else if (obj->IsJSObject()) {
- JSObject* js_obj = JSObject::cast(obj);
- ExtractClosureReferences(js_obj, entry);
- ExtractPropertyReferences(js_obj, entry);
- ExtractElementReferences(js_obj, entry);
- ExtractInternalReferences(js_obj, entry);
- SetPropertyReference(
- obj, entry, heap_->Proto_symbol(), js_obj->GetPrototype());
- if (obj->IsJSFunction()) {
- JSFunction* js_fun = JSFunction::cast(js_obj);
- Object* proto_or_map = js_fun->prototype_or_initial_map();
- if (!proto_or_map->IsTheHole()) {
- if (!proto_or_map->IsMap()) {
- SetPropertyReference(
- obj, entry,
- heap_->prototype_symbol(), proto_or_map,
- NULL,
- JSFunction::kPrototypeOrInitialMapOffset);
- } else {
- SetPropertyReference(
- obj, entry,
- heap_->prototype_symbol(), js_fun->prototype());
- }
- }
- SharedFunctionInfo* shared_info = js_fun->shared();
- // JSFunction has either bindings or literals and never both.
- bool bound = shared_info->bound();
- TagObject(js_fun->literals_or_bindings(),
- bound ? "(function bindings)" : "(function literals)");
- SetInternalReference(js_fun, entry,
- bound ? "bindings" : "literals",
- js_fun->literals_or_bindings(),
- JSFunction::kLiteralsOffset);
- SetInternalReference(js_fun, entry,
- "shared", shared_info,
- JSFunction::kSharedFunctionInfoOffset);
- TagObject(js_fun->unchecked_context(), "(context)");
- SetInternalReference(js_fun, entry,
- "context", js_fun->unchecked_context(),
- JSFunction::kContextOffset);
- for (int i = JSFunction::kNonWeakFieldsEndOffset;
- i < JSFunction::kSize;
- i += kPointerSize) {
- SetWeakReference(js_fun, entry, i, *HeapObject::RawField(js_fun, i), i);
- }
- }
- TagObject(js_obj->properties(), "(object properties)");
- SetInternalReference(obj, entry,
- "properties", js_obj->properties(),
- JSObject::kPropertiesOffset);
- TagObject(js_obj->elements(), "(object elements)");
- SetInternalReference(obj, entry,
- "elements", js_obj->elements(),
- JSObject::kElementsOffset);
+ ExtractJSObjectReferences(entry, JSObject::cast(obj));
} else if (obj->IsString()) {
- if (obj->IsConsString()) {
- ConsString* cs = ConsString::cast(obj);
- SetInternalReference(obj, entry, 1, cs->first());
- SetInternalReference(obj, entry, 2, cs->second());
- }
- if (obj->IsSlicedString()) {
- SlicedString* ss = SlicedString::cast(obj);
- SetInternalReference(obj, entry, "parent", ss->parent());
- }
+ ExtractStringReferences(entry, String::cast(obj));
extract_indexed_refs = false;
- } else if (obj->IsGlobalContext()) {
- Context* context = Context::cast(obj);
- TagObject(context->jsfunction_result_caches(),
- "(context func. result caches)");
- TagObject(context->normalized_map_cache(), "(context norm. map cache)");
- TagObject(context->runtime_context(), "(runtime context)");
- TagObject(context->data(), "(context data)");
- for (int i = Context::FIRST_WEAK_SLOT;
- i < Context::GLOBAL_CONTEXT_SLOTS;
- ++i) {
- SetWeakReference(obj, entry,
- i, context->get(i),
- FixedArray::OffsetOfElementAt(i));
- }
+ } else if (obj->IsContext()) {
+ ExtractContextReferences(entry, Context::cast(obj));
} else if (obj->IsMap()) {
- Map* map = Map::cast(obj);
- SetInternalReference(obj, entry,
- "prototype", map->prototype(), Map::kPrototypeOffset);
- SetInternalReference(obj, entry,
- "constructor", map->constructor(),
- Map::kConstructorOffset);
- if (!map->instance_descriptors()->IsEmpty()) {
- TagObject(map->instance_descriptors(), "(map descriptors)");
- SetInternalReference(obj, entry,
- "descriptors", map->instance_descriptors(),
- Map::kInstanceDescriptorsOrBitField3Offset);
- }
- if (map->prototype_transitions() != heap_->empty_fixed_array()) {
- TagObject(map->prototype_transitions(), "(prototype transitions)");
- SetInternalReference(obj,
- entry,
- "prototype_transitions",
- map->prototype_transitions(),
- Map::kPrototypeTransitionsOffset);
- }
- SetInternalReference(obj, entry,
- "code_cache", map->code_cache(),
- Map::kCodeCacheOffset);
+ ExtractMapReferences(entry, Map::cast(obj));
} else if (obj->IsSharedFunctionInfo()) {
- SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
- SetInternalReference(obj, entry,
- "name", shared->name(),
- SharedFunctionInfo::kNameOffset);
- SetInternalReference(obj, entry,
- "code", shared->unchecked_code(),
- SharedFunctionInfo::kCodeOffset);
- TagObject(shared->scope_info(), "(function scope info)");
- SetInternalReference(obj, entry,
- "scope_info", shared->scope_info(),
- SharedFunctionInfo::kScopeInfoOffset);
- SetInternalReference(obj, entry,
- "instance_class_name", shared->instance_class_name(),
- SharedFunctionInfo::kInstanceClassNameOffset);
- SetInternalReference(obj, entry,
- "script", shared->script(),
- SharedFunctionInfo::kScriptOffset);
- SetWeakReference(obj, entry,
- 1, shared->initial_map(),
- SharedFunctionInfo::kInitialMapOffset);
+ ExtractSharedFunctionInfoReferences(entry, SharedFunctionInfo::cast(obj));
} else if (obj->IsScript()) {
- Script* script = Script::cast(obj);
- SetInternalReference(obj, entry,
- "source", script->source(),
- Script::kSourceOffset);
- SetInternalReference(obj, entry,
- "name", script->name(),
- Script::kNameOffset);
- SetInternalReference(obj, entry,
- "data", script->data(),
- Script::kDataOffset);
- SetInternalReference(obj, entry,
- "context_data", script->context_data(),
- Script::kContextOffset);
- TagObject(script->line_ends(), "(script line ends)");
- SetInternalReference(obj, entry,
- "line_ends", script->line_ends(),
- Script::kLineEndsOffset);
+ ExtractScriptReferences(entry, Script::cast(obj));
} else if (obj->IsCodeCache()) {
- CodeCache* code_cache = CodeCache::cast(obj);
- TagObject(code_cache->default_cache(), "(default code cache)");
- SetInternalReference(obj, entry,
- "default_cache", code_cache->default_cache(),
- CodeCache::kDefaultCacheOffset);
- TagObject(code_cache->normal_type_cache(), "(code type cache)");
- SetInternalReference(obj, entry,
- "type_cache", code_cache->normal_type_cache(),
- CodeCache::kNormalTypeCacheOffset);
+ ExtractCodeCacheReferences(entry, CodeCache::cast(obj));
} else if (obj->IsCode()) {
- Code* code = Code::cast(obj);
- TagObject(code->unchecked_relocation_info(), "(code relocation info)");
- TagObject(code->unchecked_deoptimization_data(), "(code deopt data)");
+ ExtractCodeReferences(entry, Code::cast(obj));
+ } else if (obj->IsJSGlobalPropertyCell()) {
+ ExtractJSGlobalPropertyCellReferences(
+ entry, JSGlobalPropertyCell::cast(obj));
+ extract_indexed_refs = false;
}
if (extract_indexed_refs) {
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
@@ -2075,14 +1868,266 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
}
-void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj,
- HeapEntry* entry) {
+void V8HeapExplorer::ExtractJSGlobalProxyReferences(JSGlobalProxy* proxy) {
+ // We need to reference JS global objects from snapshot's root.
+ // We use JSGlobalProxy because this is what embedder (e.g. browser)
+ // uses for the global object.
+ Object* object = proxy->map()->prototype();
+ bool is_debug_object = false;
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ is_debug_object = object->IsGlobalObject() &&
+ Isolate::Current()->debug()->IsDebugGlobal(GlobalObject::cast(object));
+#endif
+ if (!is_debug_object) {
+ SetUserGlobalReference(object);
+ }
+}
+
+
+void V8HeapExplorer::ExtractJSObjectReferences(
+ int entry, JSObject* js_obj) {
+ HeapObject* obj = js_obj;
+ ExtractClosureReferences(js_obj, entry);
+ ExtractPropertyReferences(js_obj, entry);
+ ExtractElementReferences(js_obj, entry);
+ ExtractInternalReferences(js_obj, entry);
+ SetPropertyReference(
+ obj, entry, heap_->Proto_symbol(), js_obj->GetPrototype());
+ if (obj->IsJSFunction()) {
+ JSFunction* js_fun = JSFunction::cast(js_obj);
+ Object* proto_or_map = js_fun->prototype_or_initial_map();
+ if (!proto_or_map->IsTheHole()) {
+ if (!proto_or_map->IsMap()) {
+ SetPropertyReference(
+ obj, entry,
+ heap_->prototype_symbol(), proto_or_map,
+ NULL,
+ JSFunction::kPrototypeOrInitialMapOffset);
+ } else {
+ SetPropertyReference(
+ obj, entry,
+ heap_->prototype_symbol(), js_fun->prototype());
+ }
+ }
+ SharedFunctionInfo* shared_info = js_fun->shared();
+ // JSFunction has either bindings or literals and never both.
+ bool bound = shared_info->bound();
+ TagObject(js_fun->literals_or_bindings(),
+ bound ? "(function bindings)" : "(function literals)");
+ SetInternalReference(js_fun, entry,
+ bound ? "bindings" : "literals",
+ js_fun->literals_or_bindings(),
+ JSFunction::kLiteralsOffset);
+ TagObject(shared_info, "(shared function info)");
+ SetInternalReference(js_fun, entry,
+ "shared", shared_info,
+ JSFunction::kSharedFunctionInfoOffset);
+ TagObject(js_fun->unchecked_context(), "(context)");
+ SetInternalReference(js_fun, entry,
+ "context", js_fun->unchecked_context(),
+ JSFunction::kContextOffset);
+ for (int i = JSFunction::kNonWeakFieldsEndOffset;
+ i < JSFunction::kSize;
+ i += kPointerSize) {
+ SetWeakReference(js_fun, entry, i, *HeapObject::RawField(js_fun, i), i);
+ }
+ } else if (obj->IsGlobalObject()) {
+ GlobalObject* global_obj = GlobalObject::cast(obj);
+ SetInternalReference(global_obj, entry,
+ "builtins", global_obj->builtins(),
+ GlobalObject::kBuiltinsOffset);
+ SetInternalReference(global_obj, entry,
+ "global_context", global_obj->global_context(),
+ GlobalObject::kGlobalContextOffset);
+ SetInternalReference(global_obj, entry,
+ "global_receiver", global_obj->global_receiver(),
+ GlobalObject::kGlobalReceiverOffset);
+ }
+ TagObject(js_obj->properties(), "(object properties)");
+ SetInternalReference(obj, entry,
+ "properties", js_obj->properties(),
+ JSObject::kPropertiesOffset);
+ TagObject(js_obj->elements(), "(object elements)");
+ SetInternalReference(obj, entry,
+ "elements", js_obj->elements(),
+ JSObject::kElementsOffset);
+}
+
+
+void V8HeapExplorer::ExtractStringReferences(int entry, String* string) {
+ if (string->IsConsString()) {
+ ConsString* cs = ConsString::cast(string);
+ SetInternalReference(cs, entry, "first", cs->first());
+ SetInternalReference(cs, entry, "second", cs->second());
+ } else if (string->IsSlicedString()) {
+ SlicedString* ss = SlicedString::cast(string);
+ SetInternalReference(ss, entry, "parent", ss->parent());
+ }
+}
+
+
+void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
+#define EXTRACT_CONTEXT_FIELD(index, type, name) \
+ SetInternalReference(context, entry, #name, context->get(Context::index), \
+ FixedArray::OffsetOfElementAt(Context::index));
+ EXTRACT_CONTEXT_FIELD(CLOSURE_INDEX, JSFunction, closure);
+ EXTRACT_CONTEXT_FIELD(PREVIOUS_INDEX, Context, previous);
+ EXTRACT_CONTEXT_FIELD(EXTENSION_INDEX, Object, extension);
+ EXTRACT_CONTEXT_FIELD(GLOBAL_INDEX, GlobalObject, global);
+ if (context->IsGlobalContext()) {
+ TagObject(context->jsfunction_result_caches(),
+ "(context func. result caches)");
+ TagObject(context->normalized_map_cache(), "(context norm. map cache)");
+ TagObject(context->runtime_context(), "(runtime context)");
+ TagObject(context->data(), "(context data)");
+ GLOBAL_CONTEXT_FIELDS(EXTRACT_CONTEXT_FIELD);
+#undef EXTRACT_CONTEXT_FIELD
+ for (int i = Context::FIRST_WEAK_SLOT;
+ i < Context::GLOBAL_CONTEXT_SLOTS;
+ ++i) {
+ SetWeakReference(context, entry, i, context->get(i),
+ FixedArray::OffsetOfElementAt(i));
+ }
+ }
+}
+
+
+void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
+ SetInternalReference(map, entry,
+ "prototype", map->prototype(), Map::kPrototypeOffset);
+ SetInternalReference(map, entry,
+ "constructor", map->constructor(),
+ Map::kConstructorOffset);
+ if (!map->instance_descriptors()->IsEmpty()) {
+ TagObject(map->instance_descriptors(), "(map descriptors)");
+ SetInternalReference(map, entry,
+ "descriptors", map->instance_descriptors(),
+ Map::kInstanceDescriptorsOrBitField3Offset);
+ }
+ if (map->unchecked_prototype_transitions()->IsFixedArray()) {
+ TagObject(map->prototype_transitions(), "(prototype transitions)");
+ SetInternalReference(map, entry,
+ "prototype_transitions", map->prototype_transitions(),
+ Map::kPrototypeTransitionsOrBackPointerOffset);
+ } else {
+ SetInternalReference(map, entry,
+ "back_pointer", map->GetBackPointer(),
+ Map::kPrototypeTransitionsOrBackPointerOffset);
+ }
+ SetInternalReference(map, entry,
+ "code_cache", map->code_cache(),
+ Map::kCodeCacheOffset);
+}
+
+
+void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
+ int entry, SharedFunctionInfo* shared) {
+ HeapObject* obj = shared;
+ SetInternalReference(obj, entry,
+ "name", shared->name(),
+ SharedFunctionInfo::kNameOffset);
+ TagObject(shared->code(), "(code)");
+ SetInternalReference(obj, entry,
+ "code", shared->code(),
+ SharedFunctionInfo::kCodeOffset);
+ TagObject(shared->scope_info(), "(function scope info)");
+ SetInternalReference(obj, entry,
+ "scope_info", shared->scope_info(),
+ SharedFunctionInfo::kScopeInfoOffset);
+ SetInternalReference(obj, entry,
+ "instance_class_name", shared->instance_class_name(),
+ SharedFunctionInfo::kInstanceClassNameOffset);
+ SetInternalReference(obj, entry,
+ "script", shared->script(),
+ SharedFunctionInfo::kScriptOffset);
+ TagObject(shared->construct_stub(), "(code)");
+ SetInternalReference(obj, entry,
+ "construct_stub", shared->construct_stub(),
+ SharedFunctionInfo::kConstructStubOffset);
+ SetInternalReference(obj, entry,
+ "function_data", shared->function_data(),
+ SharedFunctionInfo::kFunctionDataOffset);
+ SetInternalReference(obj, entry,
+ "debug_info", shared->debug_info(),
+ SharedFunctionInfo::kDebugInfoOffset);
+ SetInternalReference(obj, entry,
+ "inferred_name", shared->inferred_name(),
+ SharedFunctionInfo::kInferredNameOffset);
+ SetInternalReference(obj, entry,
+ "this_property_assignments",
+ shared->this_property_assignments(),
+ SharedFunctionInfo::kThisPropertyAssignmentsOffset);
+ SetWeakReference(obj, entry,
+ 1, shared->initial_map(),
+ SharedFunctionInfo::kInitialMapOffset);
+}
+
+
+void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) {
+ HeapObject* obj = script;
+ SetInternalReference(obj, entry,
+ "source", script->source(),
+ Script::kSourceOffset);
+ SetInternalReference(obj, entry,
+ "name", script->name(),
+ Script::kNameOffset);
+ SetInternalReference(obj, entry,
+ "data", script->data(),
+ Script::kDataOffset);
+ SetInternalReference(obj, entry,
+ "context_data", script->context_data(),
+ Script::kContextOffset);
+ TagObject(script->line_ends(), "(script line ends)");
+ SetInternalReference(obj, entry,
+ "line_ends", script->line_ends(),
+ Script::kLineEndsOffset);
+}
+
+
+void V8HeapExplorer::ExtractCodeCacheReferences(
+ int entry, CodeCache* code_cache) {
+ TagObject(code_cache->default_cache(), "(default code cache)");
+ SetInternalReference(code_cache, entry,
+ "default_cache", code_cache->default_cache(),
+ CodeCache::kDefaultCacheOffset);
+ TagObject(code_cache->normal_type_cache(), "(code type cache)");
+ SetInternalReference(code_cache, entry,
+ "type_cache", code_cache->normal_type_cache(),
+ CodeCache::kNormalTypeCacheOffset);
+}
+
+
+void V8HeapExplorer::ExtractCodeReferences(int entry, Code* code) {
+ TagObject(code->relocation_info(), "(code relocation info)");
+ SetInternalReference(code, entry,
+ "relocation_info", code->relocation_info(),
+ Code::kRelocationInfoOffset);
+ SetInternalReference(code, entry,
+ "handler_table", code->handler_table(),
+ Code::kHandlerTableOffset);
+ TagObject(code->deoptimization_data(), "(code deopt data)");
+ SetInternalReference(code, entry,
+ "deoptimization_data", code->deoptimization_data(),
+ Code::kDeoptimizationDataOffset);
+ SetInternalReference(code, entry,
+ "type_feedback_info", code->type_feedback_info(),
+ Code::kTypeFeedbackInfoOffset);
+ SetInternalReference(code, entry,
+ "gc_metadata", code->gc_metadata(),
+ Code::kGCMetadataOffset);
+}
+
+
+void V8HeapExplorer::ExtractJSGlobalPropertyCellReferences(
+ int entry, JSGlobalPropertyCell* cell) {
+ SetInternalReference(cell, entry, "value", cell->value());
+}
+
+
+void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) {
if (!js_obj->IsJSFunction()) return;
JSFunction* func = JSFunction::cast(js_obj);
- Context* context = func->context();
- ScopeInfo* scope_info = context->closure()->shared()->scope_info();
-
if (func->shared()->bound()) {
FixedArray* bindings = func->function_bindings();
SetNativeBindReference(js_obj, entry, "bound_this",
@@ -2098,6 +2143,8 @@ void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj,
bindings->get(i));
}
} else {
+ Context* context = func->context()->declaration_context();
+ ScopeInfo* scope_info = context->closure()->shared()->scope_info();
// Add context allocated locals.
int context_locals = scope_info->ContextLocalCount();
for (int i = 0; i < context_locals; ++i) {
@@ -2109,19 +2156,17 @@ void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj,
// Add function variable.
if (scope_info->HasFunctionName()) {
String* name = scope_info->FunctionName();
- int idx = Context::MIN_CONTEXT_SLOTS + context_locals;
-#ifdef DEBUG
VariableMode mode;
- ASSERT(idx == scope_info->FunctionContextSlotIndex(name, &mode));
-#endif
- SetClosureReference(js_obj, entry, name, context->get(idx));
+ int idx = scope_info->FunctionContextSlotIndex(name, &mode);
+ if (idx >= 0) {
+ SetClosureReference(js_obj, entry, name, context->get(idx));
+ }
}
}
}
-void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj,
- HeapEntry* entry) {
+void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
if (js_obj->HasFastProperties()) {
DescriptorArray* descs = js_obj->map()->instance_descriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
@@ -2178,15 +2223,15 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj,
Object* k = dictionary->KeyAt(i);
if (dictionary->IsKey(k)) {
Object* target = dictionary->ValueAt(i);
- SetPropertyReference(
- js_obj, entry, String::cast(k), target);
// We assume that global objects can only have slow properties.
- if (target->IsJSGlobalPropertyCell()) {
- SetPropertyShortcutReference(js_obj,
- entry,
- String::cast(k),
- JSGlobalPropertyCell::cast(
- target)->value());
+ Object* value = target->IsJSGlobalPropertyCell()
+ ? JSGlobalPropertyCell::cast(target)->value()
+ : target;
+ if (String::cast(k)->length() > 0) {
+ SetPropertyReference(js_obj, entry, String::cast(k), value);
+ } else {
+ TagObject(value, "(hidden properties)");
+ SetInternalReference(js_obj, entry, "hidden_properties", value);
}
}
}
@@ -2194,8 +2239,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj,
}
-void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj,
- HeapEntry* entry) {
+void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int entry) {
if (js_obj->HasFastElements()) {
FixedArray* elements = FixedArray::cast(js_obj->elements());
int length = js_obj->IsJSArray() ?
@@ -2221,8 +2265,7 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj,
}
-void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj,
- HeapEntry* entry) {
+void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, int entry) {
int length = js_obj->GetInternalFieldCount();
for (int i = 0; i < length; ++i) {
Object* o = js_obj->GetInternalField(i);
@@ -2348,6 +2391,7 @@ bool V8HeapExplorer::IterateAndExtractReferences(
filler_ = NULL;
return false;
}
+
SetRootGcRootsReference();
RootsReferencesExtractor extractor;
heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG);
@@ -2355,148 +2399,127 @@ bool V8HeapExplorer::IterateAndExtractReferences(
heap_->IterateRoots(&extractor, VISIT_ALL);
extractor.FillReferences(this);
filler_ = NULL;
- return progress_->ProgressReport(false);
-}
-
-
-bool V8HeapExplorer::IterateAndSetObjectNames(SnapshotFillerInterface* filler) {
- HeapIterator iterator(HeapIterator::kFilterUnreachable);
- filler_ = filler;
- for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
- SetObjectName(obj);
- }
- return true;
+ return progress_->ProgressReport(true);
}
-void V8HeapExplorer::SetObjectName(HeapObject* object) {
- if (!object->IsJSObject() || object->IsJSRegExp() || object->IsJSFunction()) {
- return;
- }
- const char* name = collection_->names()->GetName(
- GetConstructorName(JSObject::cast(object)));
- if (object->IsJSGlobalObject()) {
- const char* tag = objects_tags_.GetTag(object);
- if (tag != NULL) {
- name = collection_->names()->GetFormatted("%s / %s", name, tag);
- }
- }
- GetEntry(object)->set_name(name);
+bool V8HeapExplorer::IsEssentialObject(Object* object) {
+ // We have to use raw_unchecked_* versions because checked versions
+ // would fail during iteration over object properties.
+ return object->IsHeapObject()
+ && !object->IsOddball()
+ && object != heap_->raw_unchecked_empty_byte_array()
+ && object != heap_->raw_unchecked_empty_fixed_array()
+ && object != heap_->raw_unchecked_empty_descriptor_array()
+ && object != heap_->raw_unchecked_fixed_array_map()
+ && object != heap_->raw_unchecked_global_property_cell_map()
+ && object != heap_->raw_unchecked_shared_function_info_map()
+ && object != heap_->raw_unchecked_free_space_map()
+ && object != heap_->raw_unchecked_one_pointer_filler_map()
+ && object != heap_->raw_unchecked_two_pointer_filler_map();
}
void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj,
- HeapEntry* parent_entry,
+ int parent_entry,
String* reference_name,
Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetNamedReference(HeapGraphEdge::kContextVariable,
- parent_obj,
parent_entry,
collection_->names()->GetName(reference_name),
- child_obj,
child_entry);
}
}
void V8HeapExplorer::SetNativeBindReference(HeapObject* parent_obj,
- HeapEntry* parent_entry,
+ int parent_entry,
const char* reference_name,
Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetNamedReference(HeapGraphEdge::kShortcut,
- parent_obj,
parent_entry,
reference_name,
- child_obj,
child_entry);
}
}
void V8HeapExplorer::SetElementReference(HeapObject* parent_obj,
- HeapEntry* parent_entry,
+ int parent_entry,
int index,
Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetIndexedReference(HeapGraphEdge::kElement,
- parent_obj,
parent_entry,
index,
- child_obj,
child_entry);
}
}
void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
- HeapEntry* parent_entry,
+ int parent_entry,
const char* reference_name,
Object* child_obj,
int field_offset) {
HeapEntry* child_entry = GetEntry(child_obj);
- if (child_entry != NULL) {
+ if (child_entry == NULL) return;
+ if (IsEssentialObject(child_obj)) {
filler_->SetNamedReference(HeapGraphEdge::kInternal,
- parent_obj,
parent_entry,
reference_name,
- child_obj,
child_entry);
- IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
+ IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
- HeapEntry* parent_entry,
+ int parent_entry,
int index,
Object* child_obj,
int field_offset) {
HeapEntry* child_entry = GetEntry(child_obj);
- if (child_entry != NULL) {
+ if (child_entry == NULL) return;
+ if (IsEssentialObject(child_obj)) {
filler_->SetNamedReference(HeapGraphEdge::kInternal,
- parent_obj,
parent_entry,
collection_->names()->GetName(index),
- child_obj,
child_entry);
- IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
+ IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj,
- HeapEntry* parent_entry,
+ int parent_entry,
int index,
Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
- if (child_entry != NULL) {
+ if (child_entry != NULL && IsEssentialObject(child_obj)) {
filler_->SetIndexedReference(HeapGraphEdge::kHidden,
- parent_obj,
parent_entry,
index,
- child_obj,
child_entry);
}
}
void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
- HeapEntry* parent_entry,
+ int parent_entry,
int index,
Object* child_obj,
int field_offset) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetIndexedReference(HeapGraphEdge::kWeak,
- parent_obj,
parent_entry,
index,
- child_obj,
child_entry);
IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
@@ -2504,7 +2527,7 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
- HeapEntry* parent_entry,
+ int parent_entry,
String* reference_name,
Object* child_obj,
const char* name_format_string,
@@ -2521,10 +2544,8 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
collection_->names()->GetName(reference_name);
filler_->SetNamedReference(type,
- parent_obj,
parent_entry,
name,
- child_obj,
child_entry);
IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
@@ -2532,16 +2553,14 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
void V8HeapExplorer::SetPropertyShortcutReference(HeapObject* parent_obj,
- HeapEntry* parent_entry,
+ int parent_entry,
String* reference_name,
Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetNamedReference(HeapGraphEdge::kShortcut,
- parent_obj,
parent_entry,
collection_->names()->GetName(reference_name),
- child_obj,
child_entry);
}
}
@@ -2550,26 +2569,26 @@ void V8HeapExplorer::SetPropertyShortcutReference(HeapObject* parent_obj,
void V8HeapExplorer::SetRootGcRootsReference() {
filler_->SetIndexedAutoIndexReference(
HeapGraphEdge::kElement,
- kInternalRootObject, snapshot_->root(),
- kGcRootsObject, snapshot_->gc_roots());
+ snapshot_->root()->index(),
+ snapshot_->gc_roots());
}
-void V8HeapExplorer::SetRootShortcutReference(Object* child_obj) {
+void V8HeapExplorer::SetUserGlobalReference(Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
ASSERT(child_entry != NULL);
filler_->SetNamedAutoIndexReference(
HeapGraphEdge::kShortcut,
- kInternalRootObject, snapshot_->root(),
- child_obj, child_entry);
+ snapshot_->root()->index(),
+ child_entry);
}
void V8HeapExplorer::SetGcRootsReference(VisitorSynchronization::SyncTag tag) {
filler_->SetIndexedAutoIndexReference(
HeapGraphEdge::kElement,
- kGcRootsObject, snapshot_->gc_roots(),
- GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag));
+ snapshot_->gc_roots()->index(),
+ snapshot_->gc_subroot(tag));
}
@@ -2577,21 +2596,48 @@ void V8HeapExplorer::SetGcSubrootReference(
VisitorSynchronization::SyncTag tag, bool is_weak, Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
- filler_->SetIndexedAutoIndexReference(
- is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kElement,
- GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag),
- child_obj, child_entry);
+ const char* name = GetStrongGcSubrootName(child_obj);
+ if (name != NULL) {
+ filler_->SetNamedReference(
+ HeapGraphEdge::kInternal,
+ snapshot_->gc_subroot(tag)->index(),
+ name,
+ child_entry);
+ } else {
+ filler_->SetIndexedAutoIndexReference(
+ is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kElement,
+ snapshot_->gc_subroot(tag)->index(),
+ child_entry);
+ }
}
}
+const char* V8HeapExplorer::GetStrongGcSubrootName(Object* object) {
+ if (strong_gc_subroot_names_.is_empty()) {
+#define NAME_ENTRY(name) strong_gc_subroot_names_.SetTag(heap_->name(), #name);
+#define ROOT_NAME(type, name, camel_name) NAME_ENTRY(name)
+ STRONG_ROOT_LIST(ROOT_NAME)
+#undef ROOT_NAME
+#define STRUCT_MAP_NAME(NAME, Name, name) NAME_ENTRY(name##_map)
+ STRUCT_LIST(STRUCT_MAP_NAME)
+#undef STRUCT_MAP_NAME
+#define SYMBOL_NAME(name, str) NAME_ENTRY(name)
+ SYMBOL_LIST(SYMBOL_NAME)
+#undef SYMBOL_NAME
+#undef NAME_ENTRY
+ CHECK(!strong_gc_subroot_names_.is_empty());
+ }
+ return strong_gc_subroot_names_.GetTag(object);
+}
+
+
void V8HeapExplorer::TagObject(Object* obj, const char* tag) {
- if (obj->IsHeapObject() &&
- !obj->IsOddball() &&
- obj != heap_->raw_unchecked_empty_byte_array() &&
- obj != heap_->raw_unchecked_empty_fixed_array() &&
- obj != heap_->raw_unchecked_empty_descriptor_array()) {
- objects_tags_.SetTag(obj, tag);
+ if (IsEssentialObject(obj)) {
+ HeapEntry* entry = GetEntry(obj);
+ if (entry->name()[0] == '\0') {
+ entry->set_name(tag);
+ }
}
}
@@ -2637,7 +2683,7 @@ void V8HeapExplorer::TagGlobalObjects() {
Handle<JSGlobalObject> global_obj = enumerator.at(i);
Object* obj_document;
if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) &&
- obj_document->IsJSObject()) {
+ obj_document->IsJSObject()) {
JSObject* document = JSObject::cast(obj_document);
Object* obj_url;
if (document->GetProperty(*url_string)->ToObject(&obj_url) &&
@@ -2681,8 +2727,7 @@ class BasicHeapEntriesAllocator : public HeapEntriesAllocator {
collection_(snapshot_->collection()),
entries_type_(entries_type) {
}
- virtual HeapEntry* AllocateEntry(
- HeapThing ptr, int children_count, int retainers_count);
+ virtual HeapEntry* AllocateEntry(HeapThing ptr);
private:
HeapSnapshot* snapshot_;
HeapSnapshotsCollection* collection_;
@@ -2690,23 +2735,19 @@ class BasicHeapEntriesAllocator : public HeapEntriesAllocator {
};
-HeapEntry* BasicHeapEntriesAllocator::AllocateEntry(
- HeapThing ptr, int children_count, int retainers_count) {
+HeapEntry* BasicHeapEntriesAllocator::AllocateEntry(HeapThing ptr) {
v8::RetainedObjectInfo* info = reinterpret_cast<v8::RetainedObjectInfo*>(ptr);
intptr_t elements = info->GetElementCount();
intptr_t size = info->GetSizeInBytes();
+ const char* name = elements != -1
+ ? collection_->names()->GetFormatted(
+ "%s / %" V8_PTR_PREFIX "d entries", info->GetLabel(), elements)
+ : collection_->names()->GetCopy(info->GetLabel());
return snapshot_->AddEntry(
entries_type_,
- elements != -1 ?
- collection_->names()->GetFormatted(
- "%s / %" V8_PTR_PREFIX "d entries",
- info->GetLabel(),
- info->GetElementCount()) :
- collection_->names()->GetCopy(info->GetLabel()),
+ name,
HeapObjectsMap::GenerateId(info),
- size != -1 ? static_cast<int>(size) : 0,
- children_count,
- retainers_count);
+ size != -1 ? static_cast<int>(size) : 0);
}
@@ -2787,9 +2828,9 @@ void NativeObjectsExplorer::FillImplicitReferences() {
for (int i = 0; i < groups->length(); ++i) {
ImplicitRefGroup* group = groups->at(i);
HeapObject* parent = *group->parent_;
- HeapEntry* parent_entry =
- filler_->FindOrAddEntry(parent, native_entries_allocator_);
- ASSERT(parent_entry != NULL);
+ int parent_entry =
+ filler_->FindOrAddEntry(parent, native_entries_allocator_)->index();
+ ASSERT(parent_entry != HeapEntry::kNoEntry);
Object*** children = group->children_;
for (size_t j = 0; j < group->length_; ++j) {
Object* child = *children[j];
@@ -2797,9 +2838,9 @@ void NativeObjectsExplorer::FillImplicitReferences() {
filler_->FindOrAddEntry(child, native_entries_allocator_);
filler_->SetNamedReference(
HeapGraphEdge::kInternal,
- parent, parent_entry,
+ parent_entry,
"native",
- child, child_entry);
+ child_entry);
}
}
}
@@ -2877,8 +2918,9 @@ NativeGroupRetainedObjectInfo* NativeObjectsExplorer::FindOrAddGroupInfo(
HEAP->HashSeed());
HashMap::Entry* entry = native_groups_.Lookup(const_cast<char*>(label_copy),
hash, true);
- if (entry->value == NULL)
+ if (entry->value == NULL) {
entry->value = new NativeGroupRetainedObjectInfo(label);
+ }
return static_cast<NativeGroupRetainedObjectInfo*>(entry->value);
}
@@ -2894,8 +2936,8 @@ void NativeObjectsExplorer::SetNativeRootReference(
filler_->FindOrAddEntry(group_info, synthetic_entries_allocator_);
filler_->SetNamedAutoIndexReference(
HeapGraphEdge::kInternal,
- group_info, group_entry,
- info, child_entry);
+ group_entry->index(),
+ child_entry);
}
@@ -2907,12 +2949,12 @@ void NativeObjectsExplorer::SetWrapperNativeReferences(
filler_->FindOrAddEntry(info, native_entries_allocator_);
ASSERT(info_entry != NULL);
filler_->SetNamedReference(HeapGraphEdge::kInternal,
- wrapper, wrapper_entry,
+ wrapper_entry->index(),
"native",
- info, info_entry);
+ info_entry);
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
- info, info_entry,
- wrapper, wrapper_entry);
+ info_entry->index(),
+ wrapper_entry);
}
@@ -2927,8 +2969,8 @@ void NativeObjectsExplorer::SetRootNativeRootsReference() {
ASSERT(group_entry != NULL);
filler_->SetIndexedAutoIndexReference(
HeapGraphEdge::kElement,
- V8HeapExplorer::kInternalRootObject, snapshot_->root(),
- group_info, group_entry);
+ snapshot_->root()->index(),
+ group_entry);
}
}
@@ -2943,56 +2985,6 @@ void NativeObjectsExplorer::VisitSubtreeWrapper(Object** p, uint16_t class_id) {
}
-class SnapshotCounter : public SnapshotFillerInterface {
- public:
- explicit SnapshotCounter(HeapEntriesMap* entries) : entries_(entries) { }
- HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
- entries_->Pair(ptr, allocator, HeapEntriesMap::kHeapEntryPlaceholder);
- return HeapEntriesMap::kHeapEntryPlaceholder;
- }
- HeapEntry* FindEntry(HeapThing ptr) {
- return entries_->Map(ptr);
- }
- HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
- HeapEntry* entry = FindEntry(ptr);
- return entry != NULL ? entry : AddEntry(ptr, allocator);
- }
- void SetIndexedReference(HeapGraphEdge::Type,
- HeapThing parent_ptr,
- HeapEntry*,
- int,
- HeapThing child_ptr,
- HeapEntry*) {
- entries_->CountReference(parent_ptr, child_ptr);
- }
- void SetIndexedAutoIndexReference(HeapGraphEdge::Type,
- HeapThing parent_ptr,
- HeapEntry*,
- HeapThing child_ptr,
- HeapEntry*) {
- entries_->CountReference(parent_ptr, child_ptr);
- }
- void SetNamedReference(HeapGraphEdge::Type,
- HeapThing parent_ptr,
- HeapEntry*,
- const char*,
- HeapThing child_ptr,
- HeapEntry*) {
- entries_->CountReference(parent_ptr, child_ptr);
- }
- void SetNamedAutoIndexReference(HeapGraphEdge::Type,
- HeapThing parent_ptr,
- HeapEntry*,
- HeapThing child_ptr,
- HeapEntry*) {
- entries_->CountReference(parent_ptr, child_ptr);
- }
-
- private:
- HeapEntriesMap* entries_;
-};
-
-
class SnapshotFiller : public SnapshotFillerInterface {
public:
explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries)
@@ -3000,64 +2992,48 @@ class SnapshotFiller : public SnapshotFillerInterface {
collection_(snapshot->collection()),
entries_(entries) { }
HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
- UNREACHABLE();
- return NULL;
+ HeapEntry* entry = allocator->AllocateEntry(ptr);
+ entries_->Pair(ptr, entry->index());
+ return entry;
}
HeapEntry* FindEntry(HeapThing ptr) {
- return entries_->Map(ptr);
+ int index = entries_->Map(ptr);
+ return index != HeapEntry::kNoEntry ? &snapshot_->entries()[index] : NULL;
}
HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
HeapEntry* entry = FindEntry(ptr);
return entry != NULL ? entry : AddEntry(ptr, allocator);
}
void SetIndexedReference(HeapGraphEdge::Type type,
- HeapThing parent_ptr,
- HeapEntry* parent_entry,
+ int parent,
int index,
- HeapThing child_ptr,
HeapEntry* child_entry) {
- int child_index, retainer_index;
- entries_->CountReference(
- parent_ptr, child_ptr, &child_index, &retainer_index);
- parent_entry->SetIndexedReference(
- type, child_index, index, child_entry, retainer_index);
+ HeapEntry* parent_entry = &snapshot_->entries()[parent];
+ parent_entry->SetIndexedReference(type, index, child_entry);
}
void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
- HeapThing parent_ptr,
- HeapEntry* parent_entry,
- HeapThing child_ptr,
+ int parent,
HeapEntry* child_entry) {
- int child_index, retainer_index;
- entries_->CountReference(
- parent_ptr, child_ptr, &child_index, &retainer_index);
- parent_entry->SetIndexedReference(
- type, child_index, child_index + 1, child_entry, retainer_index);
+ HeapEntry* parent_entry = &snapshot_->entries()[parent];
+ int index = parent_entry->children_count() + 1;
+ parent_entry->SetIndexedReference(type, index, child_entry);
}
void SetNamedReference(HeapGraphEdge::Type type,
- HeapThing parent_ptr,
- HeapEntry* parent_entry,
+ int parent,
const char* reference_name,
- HeapThing child_ptr,
HeapEntry* child_entry) {
- int child_index, retainer_index;
- entries_->CountReference(
- parent_ptr, child_ptr, &child_index, &retainer_index);
- parent_entry->SetNamedReference(
- type, child_index, reference_name, child_entry, retainer_index);
+ HeapEntry* parent_entry = &snapshot_->entries()[parent];
+ parent_entry->SetNamedReference(type, reference_name, child_entry);
}
void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
- HeapThing parent_ptr,
- HeapEntry* parent_entry,
- HeapThing child_ptr,
+ int parent,
HeapEntry* child_entry) {
- int child_index, retainer_index;
- entries_->CountReference(
- parent_ptr, child_ptr, &child_index, &retainer_index);
- parent_entry->SetNamedReference(type,
- child_index,
- collection_->names()->GetName(child_index + 1),
- child_entry,
- retainer_index);
+ HeapEntry* parent_entry = &snapshot_->entries()[parent];
+ int index = parent_entry->children_count() + 1;
+ parent_entry->SetNamedReference(
+ type,
+ collection_->names()->GetName(index),
+ child_entry);
}
private:
@@ -3107,30 +3083,15 @@ bool HeapSnapshotGenerator::GenerateSnapshot() {
debug_heap->Verify();
#endif
- SetProgressTotal(2); // 2 passes.
-
-#ifdef DEBUG
- debug_heap->Verify();
-#endif
-
- // Pass 1. Iterate heap contents to count entries and references.
- if (!CountEntriesAndReferences()) return false;
+ SetProgressTotal(1); // 1 pass.
#ifdef DEBUG
debug_heap->Verify();
#endif
- // Allocate memory for entries and references.
- snapshot_->AllocateEntries(entries_.entries_count(),
- entries_.total_children_count(),
- entries_.total_retainers_count());
-
- // Allocate heap objects to entries hash map.
- entries_.AllocateEntries(V8HeapExplorer::kInternalRootObject);
-
- // Pass 2. Fill references.
if (!FillReferences()) return false;
+ snapshot_->FillChildrenAndRetainers();
snapshot_->RememberLastJSObjectId();
if (!SetEntriesDominators()) return false;
@@ -3162,49 +3123,77 @@ bool HeapSnapshotGenerator::ProgressReport(bool force) {
void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) {
if (control_ == NULL) return;
HeapIterator iterator(HeapIterator::kFilterUnreachable);
- progress_total_ = (
+ progress_total_ = iterations_count * (
v8_heap_explorer_.EstimateObjectsCount(&iterator) +
- dom_explorer_.EstimateObjectsCount()) * iterations_count;
+ dom_explorer_.EstimateObjectsCount());
progress_counter_ = 0;
}
-bool HeapSnapshotGenerator::CountEntriesAndReferences() {
- SnapshotCounter counter(&entries_);
- v8_heap_explorer_.AddRootEntries(&counter);
- return v8_heap_explorer_.IterateAndExtractReferences(&counter)
- && dom_explorer_.IterateAndExtractReferences(&counter);
-}
-
-
bool HeapSnapshotGenerator::FillReferences() {
SnapshotFiller filler(snapshot_, &entries_);
- // IterateAndExtractReferences cannot set object names because
- // it makes call to JSObject::LocalLookupRealNamedProperty which
- // in turn may relocate objects in property maps thus changing the heap
- // layout and affecting retainer counts. This is not acceptable because
- // number of retainers must not change between count and fill passes.
- // To avoid this there's a separate postpass that set object names.
+ v8_heap_explorer_.AddRootEntries(&filler);
return v8_heap_explorer_.IterateAndExtractReferences(&filler)
- && dom_explorer_.IterateAndExtractReferences(&filler)
- && v8_heap_explorer_.IterateAndSetObjectNames(&filler);
+ && dom_explorer_.IterateAndExtractReferences(&filler);
}
-void HeapSnapshotGenerator::FillReversePostorderIndexes(
+bool HeapSnapshotGenerator::IsUserGlobalReference(const HeapGraphEdge* edge) {
+ ASSERT(edge->from() == snapshot_->root());
+ return edge->type() == HeapGraphEdge::kShortcut;
+}
+
+
+void HeapSnapshotGenerator::MarkUserReachableObjects() {
+ List<HeapEntry*> worklist;
+
+ Vector<HeapGraphEdge*> children = snapshot_->root()->children();
+ for (int i = 0; i < children.length(); ++i) {
+ if (IsUserGlobalReference(children[i])) {
+ worklist.Add(children[i]->to());
+ }
+ }
+
+ while (!worklist.is_empty()) {
+ HeapEntry* entry = worklist.RemoveLast();
+ if (entry->user_reachable()) continue;
+ entry->set_user_reachable();
+ Vector<HeapGraphEdge*> children = entry->children();
+ for (int i = 0; i < children.length(); ++i) {
+ HeapEntry* child = children[i]->to();
+ if (!child->user_reachable()) {
+ worklist.Add(child);
+ }
+ }
+ }
+}
+
+
+static bool IsRetainingEdge(HeapGraphEdge* edge) {
+ if (edge->type() == HeapGraphEdge::kShortcut) return false;
+ // The edge is not retaining if it goes from system domain
+ // (i.e. an object not reachable from window) to the user domain
+ // (i.e. a reachable object).
+ return edge->from()->user_reachable()
+ || !edge->to()->user_reachable();
+}
+
+
+void HeapSnapshotGenerator::FillPostorderIndexes(
Vector<HeapEntry*>* entries) {
snapshot_->ClearPaint();
int current_entry = 0;
List<HeapEntry*> nodes_to_visit;
- nodes_to_visit.Add(snapshot_->root());
+ HeapEntry* root = snapshot_->root();
+ nodes_to_visit.Add(root);
snapshot_->root()->paint();
while (!nodes_to_visit.is_empty()) {
HeapEntry* entry = nodes_to_visit.last();
- Vector<HeapGraphEdge> children = entry->children();
+ Vector<HeapGraphEdge*> children = entry->children();
bool has_new_edges = false;
for (int i = 0; i < children.length(); ++i) {
- if (children[i].type() == HeapGraphEdge::kShortcut) continue;
- HeapEntry* child = children[i].to();
+ if (entry != root && !IsRetainingEdge(children[i])) continue;
+ HeapEntry* child = children[i]->to();
if (!child->painted()) {
nodes_to_visit.Add(child);
child->paint();
@@ -3212,7 +3201,7 @@ void HeapSnapshotGenerator::FillReversePostorderIndexes(
}
}
if (!has_new_edges) {
- entry->set_ordered_index(current_entry);
+ entry->set_postorder_index(current_entry);
(*entries)[current_entry++] = entry;
nodes_to_visit.RemoveLast();
}
@@ -3238,9 +3227,9 @@ bool HeapSnapshotGenerator::BuildDominatorTree(
const Vector<HeapEntry*>& entries,
Vector<int>* dominators) {
if (entries.length() == 0) return true;
+ HeapEntry* root = snapshot_->root();
const int entries_length = entries.length(), root_index = entries_length - 1;
- static const int kNoDominator = -1;
- for (int i = 0; i < root_index; ++i) (*dominators)[i] = kNoDominator;
+ for (int i = 0; i < root_index; ++i) (*dominators)[i] = HeapEntry::kNoEntry;
(*dominators)[root_index] = root_index;
// The affected array is used to mark entries which dominators
@@ -3248,28 +3237,28 @@ bool HeapSnapshotGenerator::BuildDominatorTree(
ScopedVector<bool> affected(entries_length);
for (int i = 0; i < affected.length(); ++i) affected[i] = false;
// Mark the root direct children as affected.
- Vector<HeapGraphEdge> children = entries[root_index]->children();
+ Vector<HeapGraphEdge*> children = entries[root_index]->children();
for (int i = 0; i < children.length(); ++i) {
- affected[children[i].to()->ordered_index()] = true;
+ affected[children[i]->to()->postorder_index()] = true;
}
bool changed = true;
while (changed) {
changed = false;
- if (!ProgressReport(true)) return false;
+ if (!ProgressReport(false)) return false;
for (int i = root_index - 1; i >= 0; --i) {
if (!affected[i]) continue;
affected[i] = false;
// If dominator of the entry has already been set to root,
// then it can't propagate any further.
if ((*dominators)[i] == root_index) continue;
- int new_idom_index = kNoDominator;
+ int new_idom_index = HeapEntry::kNoEntry;
Vector<HeapGraphEdge*> rets = entries[i]->retainers();
for (int j = 0; j < rets.length(); ++j) {
- if (rets[j]->type() == HeapGraphEdge::kShortcut) continue;
- int ret_index = rets[j]->From()->ordered_index();
- if (dominators->at(ret_index) != kNoDominator) {
- new_idom_index = new_idom_index == kNoDominator
+ if (rets[j]->from() != root && !IsRetainingEdge(rets[j])) continue;
+ int ret_index = rets[j]->from()->postorder_index();
+ if (dominators->at(ret_index) != HeapEntry::kNoEntry) {
+ new_idom_index = new_idom_index == HeapEntry::kNoEntry
? ret_index
: Intersect(ret_index, new_idom_index, *dominators);
// If idom has already reached the root, it doesn't make sense
@@ -3277,13 +3266,13 @@ bool HeapSnapshotGenerator::BuildDominatorTree(
if (new_idom_index == root_index) break;
}
}
- if (new_idom_index != kNoDominator
+ if (new_idom_index != HeapEntry::kNoEntry
&& dominators->at(i) != new_idom_index) {
(*dominators)[i] = new_idom_index;
changed = true;
- Vector<HeapGraphEdge> children = entries[i]->children();
+ Vector<HeapGraphEdge*> children = entries[i]->children();
for (int j = 0; j < children.length(); ++j) {
- affected[children[j].to()->ordered_index()] = true;
+ affected[children[j]->to()->postorder_index()] = true;
}
}
}
@@ -3293,13 +3282,14 @@ bool HeapSnapshotGenerator::BuildDominatorTree(
bool HeapSnapshotGenerator::SetEntriesDominators() {
- // This array is used for maintaining reverse postorder of nodes.
- ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length());
- FillReversePostorderIndexes(&ordered_entries);
+ MarkUserReachableObjects();
+ // This array is used for maintaining postorder of nodes.
+ ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries().length());
+ FillPostorderIndexes(&ordered_entries);
ScopedVector<int> dominators(ordered_entries.length());
if (!BuildDominatorTree(ordered_entries, &dominators)) return false;
for (int i = 0; i < ordered_entries.length(); ++i) {
- ASSERT(dominators[i] >= 0);
+ ASSERT(dominators[i] != HeapEntry::kNoEntry);
ordered_entries[i]->set_dominator(ordered_entries[dominators[i]]);
}
return true;
@@ -3310,17 +3300,18 @@ bool HeapSnapshotGenerator::CalculateRetainedSizes() {
// As for the dominators tree we only know parent nodes, not
// children, to sum up total sizes we "bubble" node's self size
// adding it to all of its parents.
- List<HeapEntry*>& entries = *snapshot_->entries();
+ List<HeapEntry>& entries = snapshot_->entries();
for (int i = 0; i < entries.length(); ++i) {
- HeapEntry* entry = entries[i];
+ HeapEntry* entry = &entries[i];
entry->set_retained_size(entry->self_size());
}
for (int i = 0; i < entries.length(); ++i) {
- HeapEntry* entry = entries[i];
- int entry_size = entry->self_size();
- for (HeapEntry* dominator = entry->dominator();
- dominator != entry;
- entry = dominator, dominator = entry->dominator()) {
+ int entry_size = entries[i].self_size();
+ HeapEntry* current = &entries[i];
+ for (HeapEntry* dominator = current->dominator();
+ dominator != current;
+ current = dominator, dominator = current->dominator()) {
+ ASSERT(current->dominator() != NULL);
dominator->add_retained_size(entry_size);
}
}
@@ -3424,19 +3415,23 @@ class OutputStreamWriter {
};
+// type, name|index, to_node.
+const int HeapSnapshotJSONSerializer::kEdgeFieldsCount = 3;
+// type, name, id, self_size, retained_size, dominator, children_index.
+const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 7;
+
void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
ASSERT(writer_ == NULL);
writer_ = new OutputStreamWriter(stream);
HeapSnapshot* original_snapshot = NULL;
- if (snapshot_->raw_entries_size() >=
+ if (snapshot_->RawSnapshotSize() >=
SnapshotSizeConstants<kPointerSize>::kMaxSerializableSnapshotRawSize) {
// The snapshot is too big. Serialize a fake snapshot.
original_snapshot = snapshot_;
snapshot_ = CreateFakeSnapshot();
}
- // Since nodes graph is cyclic, we need the first pass to enumerate
- // them. Strings can be serialized in one pass.
+
SerializeImpl();
delete writer_;
@@ -3454,30 +3449,35 @@ HeapSnapshot* HeapSnapshotJSONSerializer::CreateFakeSnapshot() {
HeapSnapshot::kFull,
snapshot_->title(),
snapshot_->uid());
- result->AllocateEntries(2, 1, 0);
- HeapEntry* root = result->AddRootEntry(1);
+ result->AddRootEntry();
const char* text = snapshot_->collection()->names()->GetFormatted(
"The snapshot is too big. "
"Maximum snapshot size is %" V8_PTR_PREFIX "u MB. "
"Actual snapshot size is %" V8_PTR_PREFIX "u MB.",
SnapshotSizeConstants<kPointerSize>::kMaxSerializableSnapshotRawSize / MB,
- (snapshot_->raw_entries_size() + MB - 1) / MB);
- HeapEntry* message = result->AddEntry(
- HeapEntry::kString, text, 0, 4, 0, 0);
- root->SetUnidirElementReference(0, 1, message);
+ (snapshot_->RawSnapshotSize() + MB - 1) / MB);
+ HeapEntry* message = result->AddEntry(HeapEntry::kString, text, 0, 4);
+ result->root()->SetIndexedReference(HeapGraphEdge::kElement, 1, message);
+ result->FillChildrenAndRetainers();
result->SetDominatorsToSelf();
return result;
}
void HeapSnapshotJSONSerializer::SerializeImpl() {
+ List<HeapEntry>& nodes = snapshot_->entries();
+ ASSERT(0 == snapshot_->root()->index());
writer_->AddCharacter('{');
writer_->AddString("\"snapshot\":{");
SerializeSnapshot();
if (writer_->aborted()) return;
writer_->AddString("},\n");
writer_->AddString("\"nodes\":[");
- SerializeNodes();
+ SerializeNodes(nodes);
+ if (writer_->aborted()) return;
+ writer_->AddString("],\n");
+ writer_->AddString("\"edges\":[");
+ SerializeEdges(nodes);
if (writer_->aborted()) return;
writer_->AddString("],\n");
writer_->AddString("\"strings\":[");
@@ -3499,16 +3499,9 @@ int HeapSnapshotJSONSerializer::GetStringId(const char* s) {
}
-// This function won't work correctly for MIN_INT but this is not
-// a problem in case of heap snapshots serialization.
-static int itoa(int value, const Vector<char>& buffer, int buffer_pos) {
- if (value < 0) {
- buffer[buffer_pos++] = '-';
- value = -value;
- }
-
+static int utoa(unsigned value, const Vector<char>& buffer, int buffer_pos) {
int number_of_digits = 0;
- int t = value;
+ unsigned t = value;
do {
++number_of_digits;
} while (t /= 10);
@@ -3524,7 +3517,8 @@ static int itoa(int value, const Vector<char>& buffer, int buffer_pos) {
}
-void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) {
+void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
+ bool first_edge) {
// The buffer needs space for 3 ints, 3 commas and \0
static const int kBufferSize =
MaxDecimalDigitsIn<sizeof(int)>::kSigned * 3 + 3 + 1; // NOLINT
@@ -3534,127 +3528,70 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) {
|| edge->type() == HeapGraphEdge::kWeak
? edge->index() : GetStringId(edge->name());
int buffer_pos = 0;
+ if (!first_edge) {
+ buffer[buffer_pos++] = ',';
+ }
+ buffer_pos = utoa(edge->type(), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
- buffer_pos = itoa(edge->type(), buffer, buffer_pos);
- buffer[buffer_pos++] = ',';
- buffer_pos = itoa(edge_name_or_index, buffer, buffer_pos);
+ buffer_pos = utoa(edge_name_or_index, buffer, buffer_pos);
buffer[buffer_pos++] = ',';
- buffer_pos = itoa(edge->to()->entry_index(), buffer, buffer_pos);
+ buffer_pos = utoa(entry_index(edge->to()), buffer, buffer_pos);
buffer[buffer_pos++] = '\0';
writer_->AddString(buffer.start());
}
-void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) {
+void HeapSnapshotJSONSerializer::SerializeEdges(const List<HeapEntry>& nodes) {
+ bool first_edge = true;
+ for (int i = 0; i < nodes.length(); ++i) {
+ HeapEntry* entry = &nodes[i];
+ Vector<HeapGraphEdge*> children = entry->children();
+ for (int j = 0; j < children.length(); ++j) {
+ SerializeEdge(children[j], first_edge);
+ first_edge = false;
+ if (writer_->aborted()) return;
+ }
+ }
+}
+
+
+void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry,
+ int edges_index) {
// The buffer needs space for 6 ints, 1 uint32_t, 7 commas, \n and \0
static const int kBufferSize =
6 * MaxDecimalDigitsIn<sizeof(int)>::kSigned // NOLINT
+ MaxDecimalDigitsIn<sizeof(uint32_t)>::kUnsigned // NOLINT
+ 7 + 1 + 1;
EmbeddedVector<char, kBufferSize> buffer;
- Vector<HeapGraphEdge> children = entry->children();
int buffer_pos = 0;
- buffer[buffer_pos++] = '\n';
- buffer[buffer_pos++] = ',';
- buffer_pos = itoa(entry->type(), buffer, buffer_pos);
+ if (entry_index(entry) != 0) {
+ buffer[buffer_pos++] = ',';
+ }
+ buffer_pos = utoa(entry->type(), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
- buffer_pos = itoa(GetStringId(entry->name()), buffer, buffer_pos);
+ buffer_pos = utoa(GetStringId(entry->name()), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
- buffer_pos = itoa(entry->id(), buffer, buffer_pos);
+ buffer_pos = utoa(entry->id(), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
- buffer_pos = itoa(entry->self_size(), buffer, buffer_pos);
+ buffer_pos = utoa(entry->self_size(), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
- buffer_pos = itoa(entry->retained_size(), buffer, buffer_pos);
+ buffer_pos = utoa(entry->retained_size(), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
- buffer_pos = itoa(entry->dominator()->entry_index(), buffer, buffer_pos);
+ buffer_pos = utoa(entry_index(entry->dominator()), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
- buffer_pos = itoa(children.length(), buffer, buffer_pos);
+ buffer_pos = utoa(edges_index, buffer, buffer_pos);
+ buffer[buffer_pos++] = '\n';
buffer[buffer_pos++] = '\0';
writer_->AddString(buffer.start());
- for (int i = 0; i < children.length(); ++i) {
- SerializeEdge(&children[i]);
- if (writer_->aborted()) return;
- }
}
-void HeapSnapshotJSONSerializer::SerializeNodes() {
- // The first (zero) item of nodes array is an object describing node
- // serialization layout. We use a set of macros to improve
- // readability.
-#define JSON_A(s) "[" s "]"
-#define JSON_O(s) "{" s "}"
-#define JSON_S(s) "\"" s "\""
- writer_->AddString(JSON_O(
- JSON_S("fields") ":" JSON_A(
- JSON_S("type")
- "," JSON_S("name")
- "," JSON_S("id")
- "," JSON_S("self_size")
- "," JSON_S("retained_size")
- "," JSON_S("dominator")
- "," JSON_S("children_count")
- "," JSON_S("children"))
- "," JSON_S("types") ":" JSON_A(
- JSON_A(
- JSON_S("hidden")
- "," JSON_S("array")
- "," JSON_S("string")
- "," JSON_S("object")
- "," JSON_S("code")
- "," JSON_S("closure")
- "," JSON_S("regexp")
- "," JSON_S("number")
- "," JSON_S("native")
- "," JSON_S("synthetic"))
- "," JSON_S("string")
- "," JSON_S("number")
- "," JSON_S("number")
- "," JSON_S("number")
- "," JSON_S("number")
- "," JSON_S("number")
- "," JSON_O(
- JSON_S("fields") ":" JSON_A(
- JSON_S("type")
- "," JSON_S("name_or_index")
- "," JSON_S("to_node"))
- "," JSON_S("types") ":" JSON_A(
- JSON_A(
- JSON_S("context")
- "," JSON_S("element")
- "," JSON_S("property")
- "," JSON_S("internal")
- "," JSON_S("hidden")
- "," JSON_S("shortcut")
- "," JSON_S("weak"))
- "," JSON_S("string_or_number")
- "," JSON_S("node"))))));
-#undef JSON_S
-#undef JSON_O
-#undef JSON_A
-
- const int node_fields_count = 7;
- // type,name,id,self_size,retained_size,dominator,children_count.
- const int edge_fields_count = 3; // type,name|index,to_node.
-
- List<HeapEntry*>& nodes = *(snapshot_->entries());
- // Root must be the first.
- ASSERT(nodes.first() == snapshot_->root());
- // Rewrite node indexes, so they refer to actual array positions. Do this
- // only once.
- if (nodes[0]->entry_index() == -1) {
- // Nodes start from array index 1.
- int index = 1;
- for (int i = 0; i < nodes.length(); ++i) {
- HeapEntry* node = nodes[i];
- node->set_entry_index(index);
- index += node_fields_count +
- node->children().length() * edge_fields_count;
- }
- }
-
+void HeapSnapshotJSONSerializer::SerializeNodes(const List<HeapEntry>& nodes) {
+ int edges_index = 0;
for (int i = 0; i < nodes.length(); ++i) {
- SerializeNode(nodes[i]);
+ HeapEntry* entry = &nodes[i];
+ SerializeNode(entry, edges_index);
+ edges_index += entry->children().length() * kEdgeFieldsCount;
if (writer_->aborted()) return;
}
}
@@ -3666,6 +3603,61 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
writer_->AddString("\"");
writer_->AddString(",\"uid\":");
writer_->AddNumber(snapshot_->uid());
+ writer_->AddString(",\"meta\":");
+ // The object describing node serialization layout.
+ // We use a set of macros to improve readability.
+#define JSON_A(s) "[" s "]"
+#define JSON_O(s) "{" s "}"
+#define JSON_S(s) "\"" s "\""
+ writer_->AddString(JSON_O(
+ JSON_S("node_fields") ":" JSON_A(
+ JSON_S("type") ","
+ JSON_S("name") ","
+ JSON_S("id") ","
+ JSON_S("self_size") ","
+ JSON_S("retained_size") ","
+ JSON_S("dominator") ","
+ JSON_S("edges_index")) ","
+ JSON_S("node_types") ":" JSON_A(
+ JSON_A(
+ JSON_S("hidden") ","
+ JSON_S("array") ","
+ JSON_S("string") ","
+ JSON_S("object") ","
+ JSON_S("code") ","
+ JSON_S("closure") ","
+ JSON_S("regexp") ","
+ JSON_S("number") ","
+ JSON_S("native") ","
+ JSON_S("synthetic")) ","
+ JSON_S("string") ","
+ JSON_S("number") ","
+ JSON_S("number") ","
+ JSON_S("number") ","
+ JSON_S("number") ","
+ JSON_S("number")) ","
+ JSON_S("edge_fields") ":" JSON_A(
+ JSON_S("type") ","
+ JSON_S("name_or_index") ","
+ JSON_S("to_node")) ","
+ JSON_S("edge_types") ":" JSON_A(
+ JSON_A(
+ JSON_S("context") ","
+ JSON_S("element") ","
+ JSON_S("property") ","
+ JSON_S("internal") ","
+ JSON_S("hidden") ","
+ JSON_S("shortcut") ","
+ JSON_S("weak")) ","
+ JSON_S("string_or_number") ","
+ JSON_S("node"))));
+#undef JSON_S
+#undef JSON_O
+#undef JSON_A
+ writer_->AddString(",\"node_count\":");
+ writer_->AddNumber(snapshot_->entries().length());
+ writer_->AddString(",\"edge_count\":");
+ writer_->AddNumber(snapshot_->edges().length());
}
diff --git a/src/3rdparty/v8/src/profile-generator.h b/src/3rdparty/v8/src/profile-generator.h
index 1fa647e..92896c2 100644
--- a/src/3rdparty/v8/src/profile-generator.h
+++ b/src/3rdparty/v8/src/profile-generator.h
@@ -446,6 +446,7 @@ class ProfileGenerator {
class HeapEntry;
+class HeapSnapshot;
class HeapGraphEdge BASE_EMBEDDED {
public:
@@ -460,60 +461,45 @@ class HeapGraphEdge BASE_EMBEDDED {
};
HeapGraphEdge() { }
- void Init(int child_index, Type type, const char* name, HeapEntry* to);
- void Init(int child_index, Type type, int index, HeapEntry* to);
- void Init(int child_index, int index, HeapEntry* to);
+ HeapGraphEdge(Type type, const char* name, int from, int to);
+ HeapGraphEdge(Type type, int index, int from, int to);
+ void ReplaceToIndexWithEntry(HeapSnapshot* snapshot);
- Type type() { return static_cast<Type>(type_); }
- int index() {
+ Type type() const { return static_cast<Type>(type_); }
+ int index() const {
ASSERT(type_ == kElement || type_ == kHidden || type_ == kWeak);
return index_;
}
- const char* name() {
+ const char* name() const {
ASSERT(type_ == kContextVariable
- || type_ == kProperty
- || type_ == kInternal
- || type_ == kShortcut);
+ || type_ == kProperty
+ || type_ == kInternal
+ || type_ == kShortcut);
return name_;
}
- HeapEntry* to() { return to_; }
-
- HeapEntry* From();
+ INLINE(HeapEntry* from() const);
+ HeapEntry* to() const { return to_entry_; }
private:
- int child_index_ : 29;
+ INLINE(HeapSnapshot* snapshot() const);
+
unsigned type_ : 3;
+ int from_index_ : 29;
+ union {
+ // During entries population |to_index_| is used for storing the index,
+ // afterwards it is replaced with a pointer to the entry.
+ int to_index_;
+ HeapEntry* to_entry_;
+ };
union {
int index_;
const char* name_;
};
- HeapEntry* to_;
-
- DISALLOW_COPY_AND_ASSIGN(HeapGraphEdge);
};
-class HeapSnapshot;
-
// HeapEntry instances represent an entity from the heap (or a special
-// virtual node, e.g. root). To make heap snapshots more compact,
-// HeapEntries has a special memory layout (no Vectors or Lists used):
-//
-// +-----------------+
-// HeapEntry
-// +-----------------+
-// HeapGraphEdge |
-// ... } children_count
-// HeapGraphEdge |
-// +-----------------+
-// HeapGraphEdge* |
-// ... } retainers_count
-// HeapGraphEdge* |
-// +-----------------+
-//
-// In a HeapSnapshot, all entries are hand-allocated in a continuous array
-// of raw bytes.
-//
+// virtual node, e.g. root).
class HeapEntry BASE_EMBEDDED {
public:
enum Type {
@@ -528,15 +514,14 @@ class HeapEntry BASE_EMBEDDED {
kNative = v8::HeapGraphNode::kNative,
kSynthetic = v8::HeapGraphNode::kSynthetic
};
+ static const int kNoEntry;
HeapEntry() { }
- void Init(HeapSnapshot* snapshot,
+ HeapEntry(HeapSnapshot* snapshot,
Type type,
const char* name,
SnapshotObjectId id,
- int self_size,
- int children_count,
- int retainers_count);
+ int self_size);
HeapSnapshot* snapshot() { return snapshot_; }
Type type() { return static_cast<Type>(type_); }
@@ -546,75 +531,65 @@ class HeapEntry BASE_EMBEDDED {
int self_size() { return self_size_; }
int retained_size() { return retained_size_; }
void add_retained_size(int size) { retained_size_ += size; }
- void set_retained_size(int value) { retained_size_ = value; }
- int ordered_index() { return ordered_index_; }
- void set_ordered_index(int value) { ordered_index_ = value; }
- int entry_index() { return entry_index_; }
- void set_entry_index(int value) { entry_index_ = value; }
-
- Vector<HeapGraphEdge> children() {
- return Vector<HeapGraphEdge>(children_arr(), children_count_); }
+ void set_retained_size(int size) { retained_size_ = size; }
+ INLINE(int index() const);
+ int postorder_index() { return postorder_index_; }
+ void set_postorder_index(int value) { postorder_index_ = value; }
+ int children_count() const { return children_count_; }
+ INLINE(int set_children_index(int index));
+ INLINE(int set_retainers_index(int index));
+ void add_child(HeapGraphEdge* edge) {
+ children_arr()[children_count_++] = edge;
+ }
+ void add_retainer(HeapGraphEdge* edge) {
+ retainers_arr()[retainers_count_++] = edge;
+ }
+ Vector<HeapGraphEdge*> children() {
+ return Vector<HeapGraphEdge*>(children_arr(), children_count_); }
Vector<HeapGraphEdge*> retainers() {
return Vector<HeapGraphEdge*>(retainers_arr(), retainers_count_); }
- HeapEntry* dominator() { return dominator_; }
+ INLINE(HeapEntry* dominator() const);
void set_dominator(HeapEntry* entry) {
ASSERT(entry != NULL);
- dominator_ = entry;
+ dominator_ = entry->index();
}
void clear_paint() { painted_ = false; }
bool painted() { return painted_; }
void paint() { painted_ = true; }
+ bool user_reachable() { return user_reachable_; }
+ void set_user_reachable() { user_reachable_ = true; }
- void SetIndexedReference(HeapGraphEdge::Type type,
- int child_index,
- int index,
- HeapEntry* entry,
- int retainer_index);
- void SetNamedReference(HeapGraphEdge::Type type,
- int child_index,
- const char* name,
- HeapEntry* entry,
- int retainer_index);
- void SetUnidirElementReference(int child_index, int index, HeapEntry* entry);
-
- size_t EntrySize() {
- return EntriesSize(1, children_count_, retainers_count_);
- }
+ void SetIndexedReference(
+ HeapGraphEdge::Type type, int index, HeapEntry* entry);
+ void SetNamedReference(
+ HeapGraphEdge::Type type, const char* name, HeapEntry* entry);
void Print(
const char* prefix, const char* edge_name, int max_depth, int indent);
Handle<HeapObject> GetHeapObject();
- static size_t EntriesSize(int entries_count,
- int children_count,
- int retainers_count);
-
private:
- HeapGraphEdge* children_arr() {
- return reinterpret_cast<HeapGraphEdge*>(this + 1);
- }
- HeapGraphEdge** retainers_arr() {
- return reinterpret_cast<HeapGraphEdge**>(children_arr() + children_count_);
- }
+ INLINE(HeapGraphEdge** children_arr());
+ INLINE(HeapGraphEdge** retainers_arr());
const char* TypeAsString();
unsigned painted_: 1;
+ unsigned user_reachable_: 1;
+ int dominator_: 30;
unsigned type_: 4;
- int children_count_: 27;
- int retainers_count_;
+ int retainers_count_: 28;
+ int retainers_index_;
+ int children_count_;
+ int children_index_;
int self_size_;
union {
- int ordered_index_; // Used during dominator tree building.
- int retained_size_; // At that moment, there is no retained size yet.
+ int postorder_index_; // Used during dominator tree building.
+ int retained_size_; // At that moment, there is no retained size yet.
};
- int entry_index_;
SnapshotObjectId id_;
- HeapEntry* dominator_;
HeapSnapshot* snapshot_;
const char* name_;
-
- DISALLOW_COPY_AND_ASSIGN(HeapEntry);
};
@@ -635,61 +610,59 @@ class HeapSnapshot {
Type type,
const char* title,
unsigned uid);
- ~HeapSnapshot();
void Delete();
HeapSnapshotsCollection* collection() { return collection_; }
Type type() { return type_; }
const char* title() { return title_; }
unsigned uid() { return uid_; }
- HeapEntry* root() { return root_entry_; }
- HeapEntry* gc_roots() { return gc_roots_entry_; }
- HeapEntry* natives_root() { return natives_root_entry_; }
- HeapEntry* gc_subroot(int index) { return gc_subroot_entries_[index]; }
- List<HeapEntry*>* entries() { return &entries_; }
- size_t raw_entries_size() { return raw_entries_size_; }
+ size_t RawSnapshotSize() const;
+ HeapEntry* root() { return &entries_[root_index_]; }
+ HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; }
+ HeapEntry* natives_root() { return &entries_[natives_root_index_]; }
+ HeapEntry* gc_subroot(int index) {
+ return &entries_[gc_subroot_indexes_[index]];
+ }
+ List<HeapEntry>& entries() { return entries_; }
+ List<HeapGraphEdge>& edges() { return edges_; }
+ List<HeapGraphEdge*>& children() { return children_; }
+ List<HeapGraphEdge*>& retainers() { return retainers_; }
void RememberLastJSObjectId();
SnapshotObjectId max_snapshot_js_object_id() const {
return max_snapshot_js_object_id_;
}
- void AllocateEntries(
- int entries_count, int children_count, int retainers_count);
HeapEntry* AddEntry(HeapEntry::Type type,
const char* name,
SnapshotObjectId id,
- int size,
- int children_count,
- int retainers_count);
- HeapEntry* AddRootEntry(int children_count);
- HeapEntry* AddGcRootsEntry(int children_count, int retainers_count);
- HeapEntry* AddGcSubrootEntry(int tag,
- int children_count,
- int retainers_count);
- HeapEntry* AddNativesRootEntry(int children_count, int retainers_count);
+ int size);
+ HeapEntry* AddRootEntry();
+ HeapEntry* AddGcRootsEntry();
+ HeapEntry* AddGcSubrootEntry(int tag);
+ HeapEntry* AddNativesRootEntry();
void ClearPaint();
HeapEntry* GetEntryById(SnapshotObjectId id);
List<HeapEntry*>* GetSortedEntriesList();
void SetDominatorsToSelf();
+ void FillChildrenAndRetainers();
void Print(int max_depth);
void PrintEntriesSize();
private:
- HeapEntry* GetNextEntryToInit();
-
HeapSnapshotsCollection* collection_;
Type type_;
const char* title_;
unsigned uid_;
- HeapEntry* root_entry_;
- HeapEntry* gc_roots_entry_;
- HeapEntry* natives_root_entry_;
- HeapEntry* gc_subroot_entries_[VisitorSynchronization::kNumberOfSyncTags];
- char* raw_entries_;
- List<HeapEntry*> entries_;
+ int root_index_;
+ int gc_roots_index_;
+ int natives_root_index_;
+ int gc_subroot_indexes_[VisitorSynchronization::kNumberOfSyncTags];
+ List<HeapEntry> entries_;
+ List<HeapGraphEdge> edges_;
+ List<HeapGraphEdge*> children_;
+ List<HeapGraphEdge*> retainers_;
List<HeapEntry*> sorted_entries_;
- size_t raw_entries_size_;
SnapshotObjectId max_snapshot_js_object_id_;
friend class HeapSnapshotTester;
@@ -701,15 +674,18 @@ class HeapSnapshot {
class HeapObjectsMap {
public:
HeapObjectsMap();
- ~HeapObjectsMap();
void SnapshotGenerationFinished();
- SnapshotObjectId FindObject(Address addr);
+ SnapshotObjectId FindEntry(Address addr);
+ SnapshotObjectId FindOrAddEntry(Address addr, unsigned int size);
void MoveObject(Address from, Address to);
SnapshotObjectId last_assigned_id() const {
return next_id_ - kObjectIdStep;
}
+ void StopHeapObjectsTracking();
+ void PushHeapObjectsStats(OutputStream* stream);
+
static SnapshotObjectId GenerateId(v8::RetainedObjectInfo* info);
static inline SnapshotObjectId GetNthGcSubrootId(int delta);
@@ -722,16 +698,23 @@ class HeapObjectsMap {
private:
struct EntryInfo {
- explicit EntryInfo(SnapshotObjectId id) : id(id), accessed(true) { }
- EntryInfo(SnapshotObjectId id, bool accessed)
- : id(id),
- accessed(accessed) { }
+ EntryInfo(SnapshotObjectId id, Address addr, unsigned int size)
+ : id(id), addr(addr), size(size), accessed(true) { }
+ EntryInfo(SnapshotObjectId id, Address addr, unsigned int size, bool accessed)
+ : id(id), addr(addr), size(size), accessed(accessed) { }
SnapshotObjectId id;
+ Address addr;
+ 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;
+ };
- void AddEntry(Address addr, SnapshotObjectId id);
- SnapshotObjectId FindEntry(Address addr);
+ void UpdateHeapObjectsMap();
void RemoveDeadEntries();
static bool AddressesMatch(void* key1, void* key2) {
@@ -744,10 +727,10 @@ class HeapObjectsMap {
v8::internal::kZeroHashSeed);
}
- bool initial_fill_mode_;
SnapshotObjectId next_id_;
HashMap entries_map_;
- List<EntryInfo>* entries_;
+ List<EntryInfo> entries_;
+ List<TimeInterval> time_intervals_;
DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap);
};
@@ -759,6 +742,11 @@ class HeapSnapshotsCollection {
~HeapSnapshotsCollection();
bool is_tracking_objects() { return is_tracking_objects_; }
+ void PushHeapObjectsStats(OutputStream* stream) {
+ return ids_.PushHeapObjectsStats(stream);
+ }
+ void StartHeapObjectsTracking() { is_tracking_objects_ = true; }
+ void StopHeapObjectsTracking() { ids_.StopHeapObjectsTracking(); }
HeapSnapshot* NewSnapshot(
HeapSnapshot::Type type, const char* name, unsigned uid);
@@ -770,7 +758,12 @@ class HeapSnapshotsCollection {
StringsStorage* names() { return &names_; }
TokenEnumerator* token_enumerator() { return token_enumerator_; }
- SnapshotObjectId GetObjectId(Address addr) { return ids_.FindObject(addr); }
+ SnapshotObjectId FindObjectId(Address object_addr) {
+ return ids_.FindEntry(object_addr);
+ }
+ SnapshotObjectId GetObjectId(Address object_addr, int object_size) {
+ return ids_.FindOrAddEntry(object_addr, object_size);
+ }
Handle<HeapObject> FindHeapObjectById(SnapshotObjectId id);
void ObjectMoveEvent(Address from, Address to) { ids_.MoveObject(from, to); }
SnapshotObjectId last_assigned_id() const {
@@ -804,8 +797,7 @@ typedef void* HeapThing;
class HeapEntriesAllocator {
public:
virtual ~HeapEntriesAllocator() { }
- virtual HeapEntry* AllocateEntry(
- HeapThing ptr, int children_count, int retainers_count) = 0;
+ virtual HeapEntry* AllocateEntry(HeapThing ptr) = 0;
};
@@ -814,37 +806,11 @@ class HeapEntriesAllocator {
class HeapEntriesMap {
public:
HeapEntriesMap();
- ~HeapEntriesMap();
- void AllocateEntries(HeapThing root_object);
- HeapEntry* Map(HeapThing thing);
- void Pair(HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry);
- void CountReference(HeapThing from, HeapThing to,
- int* prev_children_count = NULL,
- int* prev_retainers_count = NULL);
-
- int entries_count() { return entries_count_; }
- int total_children_count() { return total_children_count_; }
- int total_retainers_count() { return total_retainers_count_; }
-
- static HeapEntry* const kHeapEntryPlaceholder;
+ int Map(HeapThing thing);
+ void Pair(HeapThing thing, int entry);
private:
- struct EntryInfo {
- EntryInfo(HeapEntry* entry, HeapEntriesAllocator* allocator)
- : entry(entry),
- allocator(allocator),
- children_count(0),
- retainers_count(0) {
- }
- HeapEntry* entry;
- HeapEntriesAllocator* allocator;
- int children_count;
- int retainers_count;
- };
-
- static inline void AllocateHeapEntryForMapEntry(HashMap::Entry* map_entry);
-
static uint32_t Hash(HeapThing thing) {
return ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)),
@@ -855,9 +821,6 @@ class HeapEntriesMap {
}
HashMap entries_;
- int entries_count_;
- int total_children_count_;
- int total_retainers_count_;
friend class HeapObjectsSet;
@@ -873,6 +836,7 @@ class HeapObjectsSet {
void Insert(Object* obj);
const char* GetTag(Object* obj);
void SetTag(Object* obj, const char* tag);
+ bool is_empty() const { return entries_.occupancy() == 0; }
private:
HashMap entries_;
@@ -891,26 +855,18 @@ class SnapshotFillerInterface {
virtual HeapEntry* FindOrAddEntry(HeapThing ptr,
HeapEntriesAllocator* allocator) = 0;
virtual void SetIndexedReference(HeapGraphEdge::Type type,
- HeapThing parent_ptr,
- HeapEntry* parent_entry,
+ int parent_entry,
int index,
- HeapThing child_ptr,
HeapEntry* child_entry) = 0;
virtual void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
- HeapThing parent_ptr,
- HeapEntry* parent_entry,
- HeapThing child_ptr,
+ int parent_entry,
HeapEntry* child_entry) = 0;
virtual void SetNamedReference(HeapGraphEdge::Type type,
- HeapThing parent_ptr,
- HeapEntry* parent_entry,
+ int parent_entry,
const char* reference_name,
- HeapThing child_ptr,
HeapEntry* child_entry) = 0;
virtual void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
- HeapThing parent_ptr,
- HeapEntry* parent_entry,
- HeapThing child_ptr,
+ int parent_entry,
HeapEntry* child_entry) = 0;
};
@@ -929,12 +885,10 @@ class V8HeapExplorer : public HeapEntriesAllocator {
V8HeapExplorer(HeapSnapshot* snapshot,
SnapshottingProgressReportingInterface* progress);
virtual ~V8HeapExplorer();
- virtual HeapEntry* AllocateEntry(
- HeapThing ptr, int children_count, int retainers_count);
+ virtual HeapEntry* AllocateEntry(HeapThing ptr);
void AddRootEntries(SnapshotFillerInterface* filler);
int EstimateObjectsCount(HeapIterator* iterator);
bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
- bool IterateAndSetObjectNames(SnapshotFillerInterface* filler);
void TagGlobalObjects();
static String* GetConstructorName(JSObject* object);
@@ -942,66 +896,77 @@ class V8HeapExplorer : public HeapEntriesAllocator {
static HeapObject* const kInternalRootObject;
private:
- HeapEntry* AddEntry(
- HeapObject* object, int children_count, int retainers_count);
+ HeapEntry* AddEntry(HeapObject* object);
HeapEntry* AddEntry(HeapObject* object,
HeapEntry::Type type,
- const char* name,
- int children_count,
- int retainers_count);
+ const char* name);
const char* GetSystemEntryName(HeapObject* object);
+
void ExtractReferences(HeapObject* obj);
- void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry);
- void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);
- void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry);
- void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry);
+ void ExtractJSGlobalProxyReferences(JSGlobalProxy* proxy);
+ void ExtractJSObjectReferences(int entry, JSObject* js_obj);
+ void ExtractStringReferences(int entry, String* obj);
+ void ExtractContextReferences(int entry, Context* context);
+ void ExtractMapReferences(int entry, Map* map);
+ void ExtractSharedFunctionInfoReferences(int entry,
+ SharedFunctionInfo* shared);
+ void ExtractScriptReferences(int entry, Script* script);
+ void ExtractCodeCacheReferences(int entry, CodeCache* code_cache);
+ void ExtractCodeReferences(int entry, Code* code);
+ void ExtractJSGlobalPropertyCellReferences(int entry,
+ JSGlobalPropertyCell* cell);
+ void ExtractClosureReferences(JSObject* js_obj, int entry);
+ void ExtractPropertyReferences(JSObject* js_obj, int entry);
+ void ExtractElementReferences(JSObject* js_obj, int entry);
+ void ExtractInternalReferences(JSObject* js_obj, int entry);
+ bool IsEssentialObject(Object* object);
void SetClosureReference(HeapObject* parent_obj,
- HeapEntry* parent,
+ int parent,
String* reference_name,
Object* child);
void SetNativeBindReference(HeapObject* parent_obj,
- HeapEntry* parent,
+ int parent,
const char* reference_name,
Object* child);
void SetElementReference(HeapObject* parent_obj,
- HeapEntry* parent,
+ int parent,
int index,
Object* child);
void SetInternalReference(HeapObject* parent_obj,
- HeapEntry* parent,
+ int parent,
const char* reference_name,
Object* child,
int field_offset = -1);
void SetInternalReference(HeapObject* parent_obj,
- HeapEntry* parent,
+ int parent,
int index,
Object* child,
int field_offset = -1);
void SetHiddenReference(HeapObject* parent_obj,
- HeapEntry* parent,
+ int parent,
int index,
Object* child);
void SetWeakReference(HeapObject* parent_obj,
- HeapEntry* parent_entry,
+ int parent,
int index,
Object* child_obj,
int field_offset);
void SetPropertyReference(HeapObject* parent_obj,
- HeapEntry* parent,
+ int parent,
String* reference_name,
Object* child,
const char* name_format_string = NULL,
int field_offset = -1);
void SetPropertyShortcutReference(HeapObject* parent_obj,
- HeapEntry* parent,
+ int parent,
String* reference_name,
Object* child);
- void SetRootShortcutReference(Object* child);
+ void SetUserGlobalReference(Object* user_global);
void SetRootGcRootsReference();
void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
void SetGcSubrootReference(
VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
- void SetObjectName(HeapObject* object);
+ const char* GetStrongGcSubrootName(Object* object);
void TagObject(Object* obj, const char* tag);
HeapEntry* GetEntry(Object* obj);
@@ -1015,6 +980,7 @@ class V8HeapExplorer : public HeapEntriesAllocator {
SnapshottingProgressReportingInterface* progress_;
SnapshotFillerInterface* filler_;
HeapObjectsSet objects_tags_;
+ HeapObjectsSet strong_gc_subroot_names_;
static HeapObject* const kGcRootsObject;
static HeapObject* const kFirstGcSubrootObject;
@@ -1098,9 +1064,10 @@ class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
bool BuildDominatorTree(const Vector<HeapEntry*>& entries,
Vector<int>* dominators);
bool CalculateRetainedSizes();
- bool CountEntriesAndReferences();
bool FillReferences();
- void FillReversePostorderIndexes(Vector<HeapEntry*>* entries);
+ void FillPostorderIndexes(Vector<HeapEntry*>* entries);
+ bool IsUserGlobalReference(const HeapGraphEdge* edge);
+ void MarkUserReachableObjects();
void ProgressStep();
bool ProgressReport(bool force = false);
bool SetEntriesDominators();
@@ -1145,16 +1112,19 @@ class HeapSnapshotJSONSerializer {
HeapSnapshot* CreateFakeSnapshot();
int GetStringId(const char* s);
- void SerializeEdge(HeapGraphEdge* edge);
+ int entry_index(HeapEntry* e) { return e->index() * kNodeFieldsCount; }
+ void SerializeEdge(HeapGraphEdge* edge, bool first_edge);
+ void SerializeEdges(const List<HeapEntry>& nodes);
void SerializeImpl();
- void SerializeNode(HeapEntry* entry);
- void SerializeNodes();
+ void SerializeNode(HeapEntry* entry, int edges_index);
+ void SerializeNodes(const List<HeapEntry>& nodes);
void SerializeSnapshot();
void SerializeString(const unsigned char* s);
void SerializeStrings();
void SortHashMap(HashMap* map, List<HashMap::Entry*>* sorted_entries);
- static const int kMaxSerializableSnapshotRawSize;
+ static const int kEdgeFieldsCount;
+ static const int kNodeFieldsCount;
HeapSnapshot* snapshot_;
HashMap strings_;
diff --git a/src/3rdparty/v8/src/property.h b/src/3rdparty/v8/src/property.h
index 04f78b2..ba5e3c8 100644
--- a/src/3rdparty/v8/src/property.h
+++ b/src/3rdparty/v8/src/property.h
@@ -214,13 +214,6 @@ class LookupResult BASE_EMBEDDED {
number_ = number;
}
- void DescriptorResult(JSObject* holder, Smi* details, int number) {
- lookup_type_ = DESCRIPTOR_TYPE;
- holder_ = holder;
- details_ = PropertyDetails(details);
- number_ = number;
- }
-
void ConstantResult(JSObject* holder) {
lookup_type_ = CONSTANT_TYPE;
holder_ = holder;
diff --git a/src/3rdparty/v8/src/regexp.js b/src/3rdparty/v8/src/regexp.js
index bc9508d..a574f62 100644
--- a/src/3rdparty/v8/src/regexp.js
+++ b/src/3rdparty/v8/src/regexp.js
@@ -278,11 +278,7 @@ function TrimRegExp(regexp) {
function RegExpToString() {
- // If this.source is an empty string, output /(?:)/.
- // http://bugzilla.mozilla.org/show_bug.cgi?id=225550
- // ecma_2/RegExp/properties-001.js.
- var src = this.source ? this.source : '(?:)';
- var result = '/' + src + '/';
+ var result = '/' + this.source + '/';
if (this.global) result += 'g';
if (this.ignoreCase) result += 'i';
if (this.multiline) result += 'm';
@@ -296,7 +292,7 @@ function RegExpToString() {
// of the last successful match.
function RegExpGetLastMatch() {
if (lastMatchInfoOverride !== null) {
- return lastMatchInfoOverride[0];
+ return OVERRIDE_MATCH(lastMatchInfoOverride);
}
var regExpSubject = LAST_SUBJECT(lastMatchInfo);
return SubString(regExpSubject,
@@ -334,8 +330,8 @@ function RegExpGetLeftContext() {
subject = LAST_SUBJECT(lastMatchInfo);
} else {
var override = lastMatchInfoOverride;
- start_index = override[override.length - 2];
- subject = override[override.length - 1];
+ start_index = OVERRIDE_POS(override);
+ subject = OVERRIDE_SUBJECT(override);
}
return SubString(subject, 0, start_index);
}
@@ -349,8 +345,9 @@ function RegExpGetRightContext() {
subject = LAST_SUBJECT(lastMatchInfo);
} else {
var override = lastMatchInfoOverride;
- subject = override[override.length - 1];
- start_index = override[override.length - 2] + subject.length;
+ subject = OVERRIDE_SUBJECT(override);
+ var match = OVERRIDE_MATCH(override);
+ start_index = OVERRIDE_POS(override) + match.length;
}
return SubString(subject, start_index, subject.length);
}
@@ -362,7 +359,9 @@ function RegExpGetRightContext() {
function RegExpMakeCaptureGetter(n) {
return function() {
if (lastMatchInfoOverride) {
- if (n < lastMatchInfoOverride.length - 2) return lastMatchInfoOverride[n];
+ if (n < lastMatchInfoOverride.length - 2) {
+ return OVERRIDE_CAPTURE(lastMatchInfoOverride, n);
+ }
return '';
}
var index = n * 2;
diff --git a/src/3rdparty/v8/src/runtime.cc b/src/3rdparty/v8/src/runtime.cc
index 2794fac..a42f90c 100644
--- a/src/3rdparty/v8/src/runtime.cc
+++ b/src/3rdparty/v8/src/runtime.cc
@@ -1272,112 +1272,96 @@ static Failure* ThrowRedeclarationError(Isolate* isolate,
RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ASSERT(args.length() == 3);
HandleScope scope(isolate);
+ Handle<GlobalObject> global = Handle<GlobalObject>(
+ isolate->context()->global());
Handle<Context> context = args.at<Context>(0);
CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
CONVERT_SMI_ARG_CHECKED(flags, 2);
- Handle<JSObject> js_global = Handle<JSObject>(isolate->context()->global());
- Handle<JSObject> qml_global = Handle<JSObject>(isolate->context()->qml_global());
-
// Traverse the name/value pairs and set the properties.
int length = pairs->length();
- for (int i = 0; i < length; i += 3) {
+ for (int i = 0; i < length; i += 2) {
HandleScope scope(isolate);
Handle<String> name(String::cast(pairs->get(i)));
Handle<Object> value(pairs->get(i + 1), isolate);
- Handle<Smi> is_qml_global(Smi::cast(pairs->get(i + 2)));
-
- Handle<JSObject> global = is_qml_global->value()?qml_global:js_global;
// We have to declare a global const property. To capture we only
// assign to it when evaluating the assignment for "const x =
// <expr>" the initial value is the hole.
- bool is_const_property = value->IsTheHole();
- bool is_function_declaration = false;
- if (value->IsUndefined() || is_const_property) {
+ bool is_var = value->IsUndefined();
+ bool is_const = value->IsTheHole();
+ bool is_function = value->IsSharedFunctionInfo();
+ bool is_module = value->IsJSModule();
+ ASSERT(is_var + is_const + is_function + is_module == 1);
+
+ if (is_var || is_const) {
// Lookup the property in the global object, and don't set the
// value of the variable if the property is already there.
+ // Do the lookup locally only, see ES5 errata.
LookupResult lookup(isolate);
- global->Lookup(*name, &lookup, true);
+ if (FLAG_es52_globals)
+ global->LocalLookup(*name, &lookup);
+ else
+ global->Lookup(*name, &lookup);
if (lookup.IsProperty()) {
// We found an existing property. Unless it was an interceptor
// that claims the property is absent, skip this declaration.
- if (lookup.type() != INTERCEPTOR) {
- continue;
- }
+ if (lookup.type() != INTERCEPTOR) continue;
PropertyAttributes attributes = global->GetPropertyAttribute(*name);
- if (attributes != ABSENT) {
- continue;
- }
+ if (attributes != ABSENT) continue;
// Fall-through and introduce the absent property by using
// SetProperty.
}
- } else {
- is_function_declaration = true;
+ } else if (is_function) {
// Copy the function and update its context. Use it as value.
Handle<SharedFunctionInfo> shared =
Handle<SharedFunctionInfo>::cast(value);
Handle<JSFunction> function =
- isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
- context,
- TENURED);
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(
+ shared, context, TENURED);
value = function;
}
LookupResult lookup(isolate);
- global->LocalLookup(*name, &lookup, true);
+ global->LocalLookup(*name, &lookup);
- // Compute the property attributes. According to ECMA-262, section
- // 13, page 71, the property must be read-only and
- // non-deletable. However, neither SpiderMonkey nor KJS creates the
- // property as read-only, so we don't either.
+ // Compute the property attributes. According to ECMA-262,
+ // the property must be non-configurable except in eval.
int attr = NONE;
- if (!DeclareGlobalsEvalFlag::decode(flags)) {
+ bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
+ if (!is_eval || is_module) {
attr |= DONT_DELETE;
}
bool is_native = DeclareGlobalsNativeFlag::decode(flags);
- if (is_const_property || (is_native && is_function_declaration)) {
+ if (is_const || is_module || (is_native && is_function)) {
attr |= READ_ONLY;
}
LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
- // Safari does not allow the invocation of callback setters for
- // function declarations. To mimic this behavior, we do not allow
- // the invocation of setters for function values. This makes a
- // difference for global functions with the same names as event
- // handlers such as "function onload() {}". Firefox does call the
- // onload setter in those case and Safari does not. We follow
- // Safari for compatibility.
- if (is_function_declaration) {
- if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
- // Do not overwrite READ_ONLY properties.
- if (lookup.GetAttributes() & READ_ONLY) {
- if (language_mode != CLASSIC_MODE) {
- Handle<Object> args[] = { name };
- return isolate->Throw(*isolate->factory()->NewTypeError(
- "strict_cannot_assign", HandleVector(args, ARRAY_SIZE(args))));
- }
- continue;
+ if (!lookup.IsProperty() || is_function || is_module) {
+ // If the local property exists, check that we can reconfigure it
+ // as required for function declarations.
+ if (lookup.IsProperty() && lookup.IsDontDelete()) {
+ if (lookup.IsReadOnly() || lookup.IsDontEnum() ||
+ lookup.type() == CALLBACKS) {
+ return ThrowRedeclarationError(
+ isolate, is_function ? "function" : "module", name);
}
- // Do not change DONT_DELETE to false from true.
- attr |= lookup.GetAttributes() & DONT_DELETE;
+ // If the existing property is not configurable, keep its attributes.
+ attr = lookup.GetAttributes();
}
- PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
-
- RETURN_IF_EMPTY_HANDLE(
- isolate,
- JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
- attributes));
+ // Define or redefine own property.
+ RETURN_IF_EMPTY_HANDLE(isolate,
+ JSObject::SetLocalPropertyIgnoreAttributes(
+ global, name, value, static_cast<PropertyAttributes>(attr)));
} else {
- RETURN_IF_EMPTY_HANDLE(
- isolate,
- JSReceiver::SetProperty(global, name, value,
- static_cast<PropertyAttributes>(attr),
- language_mode == CLASSIC_MODE
- ? kNonStrictMode : kStrictMode,
- true));
+ // Do a [[Put]] on the existing (own) property.
+ RETURN_IF_EMPTY_HANDLE(isolate,
+ JSObject::SetProperty(
+ global, name, value, static_cast<PropertyAttributes>(attr),
+ language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode));
}
}
@@ -1410,6 +1394,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
if (attributes != ABSENT) {
// The name was declared before; check for conflicting re-declarations.
+ // Note: this is actually inconsistent with what happens for globals (where
+ // we silently ignore such declarations).
if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
// Functions are not read-only.
ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
@@ -1472,9 +1458,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
return ThrowRedeclarationError(isolate, "const", name);
}
}
- RETURN_IF_EMPTY_HANDLE(
- isolate,
- JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
+ if (object->IsJSGlobalObject()) {
+ // Define own property on the global object.
+ RETURN_IF_EMPTY_HANDLE(isolate,
+ JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode));
+ } else {
+ RETURN_IF_EMPTY_HANDLE(isolate,
+ JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
+ }
}
return isolate->heap()->undefined_value();
@@ -1485,25 +1476,20 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
NoHandleAllocation nha;
// args[0] == name
// args[1] == language_mode
- // args[2] == qml_mode
- // args[3] == value (optional)
+ // args[2] == value (optional)
// Determine if we need to assign to the variable if it already
// exists (based on the number of arguments).
- RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
- bool assign = args.length() == 4;
+ RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
+ bool assign = args.length() == 3;
CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
+ GlobalObject* global = isolate->context()->global();
RUNTIME_ASSERT(args[1]->IsSmi());
CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
? kNonStrictMode : kStrictMode;
- RUNTIME_ASSERT(args[2]->IsSmi());
- int qml_mode = Smi::cast(args[2])->value();
-
- JSObject* global = qml_mode?isolate->context()->qml_global():isolate->context()->global();
-
// According to ECMA-262, section 12.2, page 62, the property must
// not be deletable.
PropertyAttributes attributes = DONT_DELETE;
@@ -1520,7 +1506,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
while (object->IsJSObject() &&
JSObject::cast(object)->map()->is_hidden_prototype()) {
JSObject* raw_holder = JSObject::cast(object);
- raw_holder->LocalLookup(*name, &lookup, true);
+ raw_holder->LocalLookup(*name, &lookup);
if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
HandleScope handle_scope(isolate);
Handle<JSObject> holder(raw_holder);
@@ -1531,7 +1517,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
// Found an interceptor that's not read only.
if (assign) {
return raw_holder->SetProperty(
- &lookup, *name, args[3], attributes, strict_mode_flag);
+ &lookup, *name, args[2], attributes, strict_mode_flag);
} else {
return isolate->heap()->undefined_value();
}
@@ -1541,10 +1527,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
}
// Reload global in case the loop above performed a GC.
- global = qml_mode?isolate->context()->qml_global():isolate->context()->global();
+ global = isolate->context()->global();
if (assign) {
- return global->SetProperty(
- *name, args[3], attributes, strict_mode_flag, true);
+ return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
}
return isolate->heap()->undefined_value();
}
@@ -1554,15 +1539,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
// All constants are declared with an initial value. The name
// of the constant is the first argument and the initial value
// is the second.
- RUNTIME_ASSERT(args.length() == 3);
+ RUNTIME_ASSERT(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
Handle<Object> value = args.at<Object>(1);
- RUNTIME_ASSERT(args[2]->IsSmi());
- int qml_mode = Smi::cast(args[2])->value();
-
// Get the current global object from top.
- JSObject* global = qml_mode?isolate->context()->qml_global():isolate->context()->global();
+ GlobalObject* global = isolate->context()->global();
// According to ECMA-262, section 12.2, page 62, the property must
// not be deletable. Since it's a const, it must be READ_ONLY too.
@@ -1586,7 +1568,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
// Restore global object from context (in case of GC) and continue
// with setting the value.
HandleScope handle_scope(isolate);
- Handle<JSObject> global(qml_mode?isolate->context()->qml_global():isolate->context()->global());
+ Handle<GlobalObject> global(isolate->context()->global());
// BUG 1213575: Handle the case where we have to set a read-only
// property through an interceptor and only do it if it's
@@ -1801,6 +1783,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
ASSERT(args.length() == 5);
CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
CONVERT_ARG_CHECKED(String, source, 1);
+ // If source is the empty string we set it to "(?:)" instead as
+ // suggested by ECMA-262, 5th, section 15.10.4.1.
+ if (source->length() == 0) source = isolate->heap()->query_colon_symbol();
Object* global = args[2];
if (!global->IsTrue()) global = isolate->heap()->false_value();
@@ -2115,7 +2100,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
DescriptorArray* instance_desc = function->map()->instance_descriptors();
int index = instance_desc->Search(name);
ASSERT(index != DescriptorArray::kNotFound);
- PropertyDetails details(instance_desc->GetDetails(index));
+ PropertyDetails details = instance_desc->GetDetails(index);
CallbacksDescriptor new_desc(name,
instance_desc->GetValue(index),
static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
@@ -2900,12 +2885,79 @@ void FindStringIndicesDispatch(Isolate* isolate,
}
+// Two smis before and after the match, for very long strings.
+const int kMaxBuilderEntriesPerRegExpMatch = 5;
+
+
+static void SetLastMatchInfoNoCaptures(Handle<String> subject,
+ Handle<JSArray> last_match_info,
+ int match_start,
+ int match_end) {
+ // Fill last_match_info with a single capture.
+ last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
+ AssertNoAllocation no_gc;
+ FixedArray* elements = FixedArray::cast(last_match_info->elements());
+ RegExpImpl::SetLastCaptureCount(elements, 2);
+ RegExpImpl::SetLastInput(elements, *subject);
+ RegExpImpl::SetLastSubject(elements, *subject);
+ RegExpImpl::SetCapture(elements, 0, match_start);
+ RegExpImpl::SetCapture(elements, 1, match_end);
+}
+
+
+template <typename SubjectChar, typename PatternChar>
+static bool SearchStringMultiple(Isolate* isolate,
+ Vector<const SubjectChar> subject,
+ Vector<const PatternChar> pattern,
+ String* pattern_string,
+ FixedArrayBuilder* builder,
+ int* match_pos) {
+ int pos = *match_pos;
+ int subject_length = subject.length();
+ int pattern_length = pattern.length();
+ int max_search_start = subject_length - pattern_length;
+ StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
+ while (pos <= max_search_start) {
+ if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
+ *match_pos = pos;
+ return false;
+ }
+ // Position of end of previous match.
+ int match_end = pos + pattern_length;
+ int new_pos = search.Search(subject, match_end);
+ if (new_pos >= 0) {
+ // A match.
+ if (new_pos > match_end) {
+ ReplacementStringBuilder::AddSubjectSlice(builder,
+ match_end,
+ new_pos);
+ }
+ pos = new_pos;
+ builder->Add(pattern_string);
+ } else {
+ break;
+ }
+ }
+
+ if (pos < max_search_start) {
+ ReplacementStringBuilder::AddSubjectSlice(builder,
+ pos + pattern_length,
+ subject_length);
+ }
+ *match_pos = pos;
+ return true;
+}
+
+
+
+
template<typename ResultSeqString>
-MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
+MUST_USE_RESULT static MaybeObject* StringReplaceAtomRegExpWithString(
Isolate* isolate,
Handle<String> subject,
Handle<JSRegExp> pattern_regexp,
- Handle<String> replacement) {
+ Handle<String> replacement,
+ Handle<JSArray> last_match_info) {
ASSERT(subject->IsFlat());
ASSERT(replacement->IsFlat());
@@ -2964,6 +3016,12 @@ MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
subject_pos,
subject_len);
}
+
+ SetLastMatchInfoNoCaptures(subject,
+ last_match_info,
+ indices.at(matches - 1),
+ indices.at(matches - 1) + pattern_len);
+
return *result;
}
@@ -3012,11 +3070,19 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
compiled_replacement.simple_hint()) {
if (subject_handle->HasOnlyAsciiChars() &&
replacement_handle->HasOnlyAsciiChars()) {
- return StringReplaceStringWithString<SeqAsciiString>(
- isolate, subject_handle, regexp_handle, replacement_handle);
+ return StringReplaceAtomRegExpWithString<SeqAsciiString>(
+ isolate,
+ subject_handle,
+ regexp_handle,
+ replacement_handle,
+ last_match_info_handle);
} else {
- return StringReplaceStringWithString<SeqTwoByteString>(
- isolate, subject_handle, regexp_handle, replacement_handle);
+ return StringReplaceAtomRegExpWithString<SeqTwoByteString>(
+ isolate,
+ subject_handle,
+ regexp_handle,
+ replacement_handle,
+ last_match_info_handle);
}
}
@@ -3105,21 +3171,29 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
Handle<String> subject_handle(subject);
Handle<JSRegExp> regexp_handle(regexp);
+ Handle<JSArray> last_match_info_handle(last_match_info);
// Shortcut for simple non-regexp global replacements
if (regexp_handle->GetFlags().is_global() &&
regexp_handle->TypeTag() == JSRegExp::ATOM) {
Handle<String> empty_string_handle(HEAP->empty_string());
if (subject_handle->HasOnlyAsciiChars()) {
- return StringReplaceStringWithString<SeqAsciiString>(
- isolate, subject_handle, regexp_handle, empty_string_handle);
+ return StringReplaceAtomRegExpWithString<SeqAsciiString>(
+ isolate,
+ subject_handle,
+ regexp_handle,
+ empty_string_handle,
+ last_match_info_handle);
} else {
- return StringReplaceStringWithString<SeqTwoByteString>(
- isolate, subject_handle, regexp_handle, empty_string_handle);
+ return StringReplaceAtomRegExpWithString<SeqTwoByteString>(
+ isolate,
+ subject_handle,
+ regexp_handle,
+ empty_string_handle,
+ last_match_info_handle);
}
}
- Handle<JSArray> last_match_info_handle(last_match_info);
Handle<Object> match = RegExpImpl::Exec(regexp_handle,
subject_handle,
0,
@@ -3139,6 +3213,10 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
end = RegExpImpl::GetCapture(match_info_array, 1);
}
+ bool global = regexp_handle->GetFlags().is_global();
+
+ if (start == end && !global) return *subject_handle;
+
int length = subject_handle->length();
int new_length = length - (end - start);
if (new_length == 0) {
@@ -3154,7 +3232,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
}
// If the regexp isn't global, only match once.
- if (!regexp_handle->GetFlags().is_global()) {
+ if (!global) {
if (start > 0) {
String::WriteToFlat(*subject_handle,
answer->GetChars(),
@@ -3653,70 +3731,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
}
-// Two smis before and after the match, for very long strings.
-const int kMaxBuilderEntriesPerRegExpMatch = 5;
-
-
-static void SetLastMatchInfoNoCaptures(Handle<String> subject,
- Handle<JSArray> last_match_info,
- int match_start,
- int match_end) {
- // Fill last_match_info with a single capture.
- last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
- AssertNoAllocation no_gc;
- FixedArray* elements = FixedArray::cast(last_match_info->elements());
- RegExpImpl::SetLastCaptureCount(elements, 2);
- RegExpImpl::SetLastInput(elements, *subject);
- RegExpImpl::SetLastSubject(elements, *subject);
- RegExpImpl::SetCapture(elements, 0, match_start);
- RegExpImpl::SetCapture(elements, 1, match_end);
-}
-
-
-template <typename SubjectChar, typename PatternChar>
-static bool SearchStringMultiple(Isolate* isolate,
- Vector<const SubjectChar> subject,
- Vector<const PatternChar> pattern,
- String* pattern_string,
- FixedArrayBuilder* builder,
- int* match_pos) {
- int pos = *match_pos;
- int subject_length = subject.length();
- int pattern_length = pattern.length();
- int max_search_start = subject_length - pattern_length;
- StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
- while (pos <= max_search_start) {
- if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
- *match_pos = pos;
- return false;
- }
- // Position of end of previous match.
- int match_end = pos + pattern_length;
- int new_pos = search.Search(subject, match_end);
- if (new_pos >= 0) {
- // A match.
- if (new_pos > match_end) {
- ReplacementStringBuilder::AddSubjectSlice(builder,
- match_end,
- new_pos);
- }
- pos = new_pos;
- builder->Add(pattern_string);
- } else {
- break;
- }
- }
-
- if (pos < max_search_start) {
- ReplacementStringBuilder::AddSubjectSlice(builder,
- pos + pattern_length,
- subject_length);
- }
- *match_pos = pos;
- return true;
-}
-
-
static bool SearchStringMultiple(Isolate* isolate,
Handle<String> subject,
Handle<String> pattern,
@@ -3856,6 +3870,8 @@ static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
}
+// Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
+// separate last match info. See comment on that function.
static RegExpImpl::IrregexpResult SearchRegExpMultiple(
Isolate* isolate,
Handle<String> subject,
@@ -3884,10 +3900,6 @@ static RegExpImpl::IrregexpResult SearchRegExpMultiple(
// End of previous match. Differs from pos if match was empty.
int match_end = 0;
if (result == RegExpImpl::RE_SUCCESS) {
- // Need to keep a copy of the previous match for creating last_match_info
- // at the end, so we have two vectors that we swap between.
- OffsetsVector registers2(required_registers, isolate);
- Vector<int> prev_register_vector(registers2.vector(), registers2.length());
bool first = true;
do {
int match_start = register_vector[0];
@@ -3940,11 +3952,6 @@ static RegExpImpl::IrregexpResult SearchRegExpMultiple(
elements->set(capture_count + 2, *subject);
builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
}
- // Swap register vectors, so the last successful match is in
- // prev_register_vector.
- Vector<int32_t> tmp = prev_register_vector;
- prev_register_vector = register_vector;
- register_vector = tmp;
if (match_end > match_start) {
pos = match_end;
@@ -3976,12 +3983,12 @@ static RegExpImpl::IrregexpResult SearchRegExpMultiple(
last_match_array->EnsureSize(last_match_array_size);
AssertNoAllocation no_gc;
FixedArray* elements = FixedArray::cast(last_match_array->elements());
+ // We have to set this even though the rest of the last match array is
+ // ignored.
RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
+ // These are also read without consulting the override.
RegExpImpl::SetLastSubject(elements, *subject);
RegExpImpl::SetLastInput(elements, *subject);
- for (int i = 0; i < last_match_capture_count; i++) {
- RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
- }
return RegExpImpl::RE_SUCCESS;
}
}
@@ -3990,6 +3997,9 @@ static RegExpImpl::IrregexpResult SearchRegExpMultiple(
}
+// This is only called for StringReplaceGlobalRegExpWithFunction. This sets
+// lastMatchInfoOverride to maintain the last match info, so we don't need to
+// set any other last match array info.
RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
ASSERT(args.length() == 4);
HandleScope handles(isolate);
@@ -4717,6 +4727,36 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
}
+// Check whether debugger and is about to step into the callback that is passed
+// to a built-in function such as Array.forEach.
+RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugCallbackSupportsStepping) {
+ if (!isolate->IsDebuggerActive()) 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.
+ if (!callback->IsJSFunction() || JSFunction::cast(callback)->IsBuiltin()) {
+ return isolate->heap()->false_value();
+ }
+ return isolate->heap()->true_value();
+}
+
+
+// Set one shot breakpoints for the callback function that is passed to a
+// built-in function such as Array.forEach to enable stepping into the callback.
+RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrepareStepInIfStepping) {
+ Debug* debug = isolate->debug();
+ if (!debug->IsStepping()) return NULL;
+ CONVERT_ARG_CHECKED(Object, callback, 0);
+ HandleScope scope(isolate);
+ Handle<SharedFunctionInfo> shared_info(JSFunction::cast(callback)->shared());
+ // When leaving the callback, step out has been activated, but not performed
+ // if we do not leave the builtin. To be able to step into the callback
+ // again, we need to clear the step out at this point.
+ debug->ClearStepOut();
+ debug->FloodWithOneShot(shared_info);
+ return NULL;
+}
+
+
// Set a local property, even if it is READ_ONLY. If the property does not
// exist, it will be added with attributes NONE.
RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
@@ -7135,29 +7175,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_UserObjectEquals) {
- NoHandleAllocation ha;
- ASSERT(args.length() == 2);
-
- CONVERT_ARG_CHECKED(JSObject, lhs, 1);
- CONVERT_ARG_CHECKED(JSObject, rhs, 0);
-
- bool result;
-
- v8::UserObjectComparisonCallback callback = isolate->UserObjectComparisonCallback();
- if (callback) {
- HandleScope scope(isolate);
- Handle<JSObject> lhs_handle(lhs);
- Handle<JSObject> rhs_handle(rhs);
- result = callback(v8::Utils::ToLocal(lhs_handle), v8::Utils::ToLocal(rhs_handle));
- } else {
- result = (lhs == rhs);
- }
-
- return Smi::FromInt(result?0:1);
-}
-
-
RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
NoHandleAllocation ha;
ASSERT(args.length() == 3);
@@ -8163,6 +8180,14 @@ static void MaterializeArgumentsObjectInFrame(Isolate* isolate,
ASSERT(*arguments != isolate->heap()->undefined_value());
}
frame->SetExpression(i, *arguments);
+ if (FLAG_trace_deopt) {
+ PrintF("Materializing arguments object for frame %p - %p: %p ",
+ reinterpret_cast<void*>(frame->sp()),
+ reinterpret_cast<void*>(frame->fp()),
+ reinterpret_cast<void*>(*arguments));
+ arguments->ShortPrint();
+ PrintF("\n");
+ }
}
}
}
@@ -8252,6 +8277,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearFunctionTypeFeedback) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+ Code* unoptimized = function->shared()->code();
+ if (unoptimized->kind() == Code::FUNCTION) {
+ unoptimized->ClearInlineCaches();
+ unoptimized->ClearTypeFeedbackCells(isolate->heap());
+ }
+ return isolate->heap()->undefined_value();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
#if defined(USE_SIMULATOR)
return isolate->heap()->true_value();
@@ -8291,10 +8329,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
if (!V8::UseCrankshaft()) {
return Smi::FromInt(4); // 4 == "never".
}
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
if (FLAG_always_opt) {
- return Smi::FromInt(3); // 3 == "always".
+ // We may have always opt, but that is more best-effort than a real
+ // promise, so we still say "no" if it is not optimized.
+ return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always".
+ : Smi::FromInt(2); // 2 == "no".
}
- CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
: Smi::FromInt(2); // 2 == "no".
}
@@ -8435,6 +8476,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) {
+ RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
+ return isolate->heap()->nan_value();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
HandleScope scope(isolate);
ASSERT(args.length() >= 2);
@@ -8527,10 +8574,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
- SharedFunctionInfo* shared = function->shared();
- // TODO: The QML mode should be checked in the ContextLength function.
- int length = shared->scope_info()->ContextLength(shared->qml_mode());
-
+ int length = function->shared()->scope_info()->ContextLength();
Object* result;
{ MaybeObject* maybe_result =
isolate->heap()->AllocateFunctionContext(length, function);
@@ -8637,6 +8681,25 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 2);
+ CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 0);
+ CONVERT_ARG_HANDLE_CHECKED(JSModule, instance, 1);
+
+ Context* context;
+ MaybeObject* maybe_context =
+ isolate->heap()->AllocateModuleContext(isolate->context(),
+ scope_info);
+ if (!maybe_context->To(&context)) return maybe_context;
+ // Also initialize the context slot of the instance object.
+ instance->set_context(context);
+ isolate->set_context(context);
+
+ return context;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
HandleScope scope(isolate);
ASSERT(args.length() == 2);
@@ -9190,7 +9253,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
// Compile source string in the global context.
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
- source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition, false);
+ source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> fun =
isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
@@ -9204,8 +9267,7 @@ static ObjectPair CompileGlobalEval(Isolate* isolate,
Handle<String> source,
Handle<Object> receiver,
LanguageMode language_mode,
- int scope_position,
- bool qml_mode) {
+ int scope_position) {
Handle<Context> context = Handle<Context>(isolate->context());
Handle<Context> global_context = Handle<Context>(context->global_context());
@@ -9225,8 +9287,7 @@ static ObjectPair CompileGlobalEval(Isolate* isolate,
Handle<Context>(isolate->context()),
context->IsGlobalContext(),
language_mode,
- scope_position,
- qml_mode);
+ scope_position);
if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
Handle<JSFunction> compiled =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
@@ -9236,7 +9297,7 @@ static ObjectPair CompileGlobalEval(Isolate* isolate,
RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
- ASSERT(args.length() == 6);
+ ASSERT(args.length() == 5);
HandleScope scope(isolate);
Handle<Object> callee = args.at<Object>(0);
@@ -9257,8 +9318,7 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
args.at<String>(1),
args.at<Object>(2),
language_mode,
- args.smi_at(4),
- Smi::cast(args[5])->value());
+ args.smi_at(4));
}
@@ -9966,36 +10026,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
- HandleScope handle_scope(isolate);
-
- ASSERT_EQ(3, args.length());
-
- CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
- Handle<Object> key1 = args.at<Object>(1);
- Handle<Object> key2 = args.at<Object>(2);
-
- uint32_t index1, index2;
- if (!key1->ToArrayIndex(&index1)
- || !key2->ToArrayIndex(&index2)) {
- return isolate->ThrowIllegalOperation();
- }
-
- Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
- Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
- RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
- Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
- RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
-
- RETURN_IF_EMPTY_HANDLE(
- isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
- RETURN_IF_EMPTY_HANDLE(
- isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
-
- return isolate->heap()->undefined_value();
-}
-
-
// Returns an array that tells you where in the [0, length) interval an array
// might have elements. Can either return keys (positive integers) or
// intervals (pair of a negative integer (-start-1) followed by a
@@ -10971,10 +11001,10 @@ static Handle<JSObject> MaterializeModuleScope(
}
-// Iterate over the actual scopes visible from a stack frame. The iteration
-// proceeds from the innermost visible nested scope outwards. All scopes are
-// backed by an actual context except the local scope, which is inserted
-// "artificially" in the context chain.
+// Iterate over the actual scopes visible from a stack frame or from a closure.
+// The iteration proceeds from the innermost visible nested scope outwards.
+// All scopes are backed by an actual context except the local scope,
+// which is inserted "artificially" in the context chain.
class ScopeIterator {
public:
enum ScopeType {
@@ -11075,6 +11105,18 @@ class ScopeIterator {
}
}
+ ScopeIterator(Isolate* isolate,
+ Handle<JSFunction> function)
+ : isolate_(isolate),
+ frame_(NULL),
+ inlined_jsframe_index_(0),
+ function_(function),
+ context_(function->context()) {
+ if (function->IsBuiltin()) {
+ context_ = Handle<Context>();
+ }
+ }
+
// More scopes?
bool Done() { return context_.is_null(); }
@@ -11295,6 +11337,22 @@ static const int kScopeDetailsTypeIndex = 0;
static const int kScopeDetailsObjectIndex = 1;
static const int kScopeDetailsSize = 2;
+
+static MaybeObject* MaterializeScopeDetails(Isolate* isolate,
+ ScopeIterator* it) {
+ // Calculate the size of the result.
+ int details_size = kScopeDetailsSize;
+ Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
+
+ // Fill in scope details.
+ details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
+ Handle<JSObject> scope_object = it->ScopeObject();
+ RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
+ details->set(kScopeDetailsObjectIndex, *scope_object);
+
+ return *isolate->factory()->NewJSArrayWithElements(details);
+}
+
// Return an array with scope details
// args[0]: number: break id
// args[1]: number: frame index
@@ -11332,18 +11390,46 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
if (it.Done()) {
return isolate->heap()->undefined_value();
}
+ return MaterializeScopeDetails(isolate, &it);
+}
- // Calculate the size of the result.
- int details_size = kScopeDetailsSize;
- Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
- // Fill in scope details.
- details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
- Handle<JSObject> scope_object = it.ScopeObject();
- RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
- details->set(kScopeDetailsObjectIndex, *scope_object);
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 1);
- return *isolate->factory()->NewJSArrayWithElements(details);
+ // Check arguments.
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
+
+ // Count the visible scopes.
+ int n = 0;
+ for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
+ n++;
+ }
+
+ return Smi::FromInt(n);
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 2);
+
+ // Check arguments.
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
+ CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
+
+ // Find the requested scope.
+ int n = 0;
+ ScopeIterator it(isolate, fun);
+ for (; !it.Done() && n < index; it.Next()) {
+ n++;
+ }
+ if (it.Done()) {
+ return isolate->heap()->undefined_value();
+ }
+
+ return MaterializeScopeDetails(isolate, &it);
}
@@ -11475,12 +11561,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
}
-// Return the value of breakpoint_relocation flag
-RUNTIME_FUNCTION(MaybeObject*, Runtime_AllowBreakPointRelocation) {
- return Smi::FromInt(FLAG_breakpoint_relocation);
-}
-
-
// Set a break point in a function
// args[0]: function
// args[1]: number: break source position (within the function source)
@@ -11875,7 +11955,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
Handle<ScopeInfo> scope_info(function->shared()->scope_info());
- bool qml_mode = function->shared()->qml_mode();
// Traverse the saved contexts chain to find the active context for the
// selected frame.
@@ -11947,8 +12026,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
context,
context->IsGlobalContext(),
CLASSIC_MODE,
- RelocInfo::kNoPosition,
- qml_mode);
+ RelocInfo::kNoPosition);
if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> compiled_function =
isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
@@ -11958,8 +12036,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
Handle<Object> receiver(frame->receiver(), isolate);
Handle<Object> evaluation_function =
Execution::Call(compiled_function, receiver, 0, NULL,
- &has_pending_exception, false,
- Handle<Object>(function->context()->qml_global()));
+ &has_pending_exception);
if (has_pending_exception) return Failure::Exception();
Handle<Object> arguments = GetArgumentsObject(isolate,
@@ -12042,8 +12119,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
context,
is_global,
CLASSIC_MODE,
- RelocInfo::kNoPosition,
- false);
+ RelocInfo::kNoPosition);
if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> compiled_function =
Handle<JSFunction>(
diff --git a/src/3rdparty/v8/src/runtime.h b/src/3rdparty/v8/src/runtime.h
index 22cb12d..83991bb 100644
--- a/src/3rdparty/v8/src/runtime.h
+++ b/src/3rdparty/v8/src/runtime.h
@@ -77,6 +77,7 @@ namespace internal {
\
/* Utilities */ \
F(CheckIsBootstrapping, 0, 1) \
+ F(GetRootNaN, 0, 1) \
F(Call, -1 /* >= 2 */, 1) \
F(Apply, 5, 1) \
F(GetFunctionDelegate, 1, 1) \
@@ -88,6 +89,7 @@ namespace internal {
F(NotifyDeoptimized, 1, 1) \
F(NotifyOSR, 0, 1) \
F(DeoptimizeFunction, 1, 1) \
+ F(ClearFunctionTypeFeedback, 1, 1) \
F(RunningInSimulator, 0, 1) \
F(OptimizeFunctionOnNextCall, -1, 1) \
F(GetOptimizationStatus, 1, 1) \
@@ -97,6 +99,8 @@ namespace internal {
F(AllocateInNewSpace, 1, 1) \
F(SetNativeFlag, 1, 1) \
F(StoreArrayLiteralElement, 5, 1) \
+ F(DebugCallbackSupportsStepping, 1, 1) \
+ F(DebugPrepareStepInIfStepping, 1, 1) \
\
/* Array join support */ \
F(PushIfAbsent, 2, 1) \
@@ -156,7 +160,6 @@ namespace internal {
/* Comparisons */ \
F(NumberEquals, 2, 1) \
F(StringEquals, 2, 1) \
- F(UserObjectEquals, 2, 1) \
\
F(NumberCompare, 3, 1) \
F(SmiLexicographicCompare, 2, 1) \
@@ -257,7 +260,7 @@ namespace internal {
\
/* Eval */ \
F(GlobalReceiver, 1, 1) \
- F(ResolvePossiblyDirectEval, 6, 2) \
+ F(ResolvePossiblyDirectEval, 5, 2) \
\
F(SetProperty, -1 /* 4 or 5 */, 1) \
F(DefineOrRedefineDataProperty, 4, 1) \
@@ -269,7 +272,6 @@ namespace internal {
F(GetArrayKeys, 2, 1) \
F(MoveArrayContents, 2, 1) \
F(EstimateNumberOfElements, 1, 1) \
- F(SwapElements, 3, 1) \
\
/* Getters and Setters */ \
F(LookupAccessor, 3, 1) \
@@ -324,6 +326,7 @@ namespace internal {
F(PushWithContext, 2, 1) \
F(PushCatchContext, 3, 1) \
F(PushBlockContext, 2, 1) \
+ F(PushModuleContext, 2, 1) \
F(DeleteContextSlot, 2, 1) \
F(LoadContextSlot, 2, 2) \
F(LoadContextSlotNoReferenceError, 2, 2) \
@@ -332,8 +335,8 @@ namespace internal {
/* Declarations and initialization */ \
F(DeclareGlobals, 3, 1) \
F(DeclareContextSlot, 4, 1) \
- F(InitializeVarGlobal, -1 /* 3 or 4 */, 1) \
- F(InitializeConstGlobal, 3, 1) \
+ F(InitializeVarGlobal, -1 /* 2 or 3 */, 1) \
+ F(InitializeConstGlobal, 2, 1) \
F(InitializeConstContextSlot, 3, 1) \
F(OptimizeObjectForAddingMultipleProperties, 2, 1) \
\
@@ -401,12 +404,13 @@ namespace internal {
F(GetFrameDetails, 2, 1) \
F(GetScopeCount, 2, 1) \
F(GetScopeDetails, 4, 1) \
+ F(GetFunctionScopeCount, 1, 1) \
+ F(GetFunctionScopeDetails, 2, 1) \
F(DebugPrintScopes, 0, 1) \
F(GetThreadCount, 1, 1) \
F(GetThreadDetails, 2, 1) \
F(SetDisableBreak, 1, 1) \
F(GetBreakLocations, 1, 1) \
- F(AllowBreakPointRelocation, 0, 1) \
F(SetFunctionBreakPoint, 3, 1) \
F(SetScriptBreakPoint, 3, 1) \
F(ClearBreakPoint, 1, 1) \
@@ -531,8 +535,7 @@ namespace internal {
F(RegExpExec, 4, 1) \
F(RegExpConstructResult, 3, 1) \
F(GetFromCache, 2, 1) \
- F(NumberToString, 1, 1) \
- F(SwapElements, 3, 1)
+ F(NumberToString, 1, 1)
//---------------------------------------------------------------------------
diff --git a/src/3rdparty/v8/src/runtime.js b/src/3rdparty/v8/src/runtime.js
index 53d9a39..6b48734 100644
--- a/src/3rdparty/v8/src/runtime.js
+++ b/src/3rdparty/v8/src/runtime.js
@@ -47,7 +47,7 @@ var $String = global.String;
var $Number = global.Number;
var $Function = global.Function;
var $Boolean = global.Boolean;
-var $NaN = 0/0;
+var $NaN = %GetRootNaN();
var builtins = this;
// ECMA-262 Section 11.9.3.
diff --git a/src/3rdparty/v8/src/scanner.cc b/src/3rdparty/v8/src/scanner.cc
index 7901b5d..f24af2e 100755
--- a/src/3rdparty/v8/src/scanner.cc
+++ b/src/3rdparty/v8/src/scanner.cc
@@ -611,7 +611,7 @@ void Scanner::SeekForward(int pos) {
}
-void Scanner::ScanEscape() {
+bool Scanner::ScanEscape() {
uc32 c = c0_;
Advance();
@@ -621,7 +621,7 @@ void Scanner::ScanEscape() {
if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance();
// Allow LF+CR newlines in multiline string literals.
if (IsLineFeed(c) && IsCarriageReturn(c0_)) Advance();
- return;
+ return true;
}
switch (c) {
@@ -635,13 +635,13 @@ void Scanner::ScanEscape() {
case 't' : c = '\t'; break;
case 'u' : {
c = ScanHexNumber(4);
- if (c < 0) c = 'u';
+ if (c < 0) return false;
break;
}
case 'v' : c = '\v'; break;
case 'x' : {
c = ScanHexNumber(2);
- if (c < 0) c = 'x';
+ if (c < 0) return false;
break;
}
case '0' : // fall through
@@ -654,10 +654,11 @@ void Scanner::ScanEscape() {
case '7' : c = ScanOctalEscape(c, 2); break;
}
- // According to ECMA-262, 3rd, 7.8.4 (p 18ff) these
- // should be illegal, but they are commonly handled
- // as non-escaped characters by JS VMs.
+ // According to ECMA-262, section 7.8.4, characters not covered by the
+ // above cases should be illegal, but they are commonly handled as
+ // non-escaped characters by JS VMs.
AddLiteralChar(c);
+ return true;
}
@@ -696,8 +697,7 @@ Token::Value Scanner::ScanString() {
uc32 c = c0_;
Advance();
if (c == '\\') {
- if (c0_ < 0) return Token::ILLEGAL;
- ScanEscape();
+ if (c0_ < 0 || !ScanEscape()) return Token::ILLEGAL;
} else {
AddLiteralChar(c);
}
diff --git a/src/3rdparty/v8/src/scanner.h b/src/3rdparty/v8/src/scanner.h
index 045e7d2..4de413b 100644
--- a/src/3rdparty/v8/src/scanner.h
+++ b/src/3rdparty/v8/src/scanner.h
@@ -520,13 +520,16 @@ class Scanner {
Token::Value ScanIdentifierOrKeyword();
Token::Value ScanIdentifierSuffix(LiteralScope* literal);
- void ScanEscape();
Token::Value ScanString();
- // Decodes a unicode escape-sequence which is part of an identifier.
+ // Scans an escape-sequence which is part of a string and adds the
+ // decoded character to the current literal. Returns true if a pattern
+ // is scanned.
+ bool ScanEscape();
+ // Decodes a Unicode escape-sequence which is part of an identifier.
// If the escape sequence cannot be decoded the result is kBadChar.
uc32 ScanIdentifierUnicodeEscape();
- // Recognizes a uniocde escape-sequence and adds its characters,
+ // Scans a Unicode escape-sequence and adds its characters,
// uninterpreted, to the current literal. Used for parsing RegExp
// flags.
bool ScanLiteralUnicodeEscape();
diff --git a/src/3rdparty/v8/src/scopeinfo.cc b/src/3rdparty/v8/src/scopeinfo.cc
index 3150045..f50af30 100644
--- a/src/3rdparty/v8/src/scopeinfo.cc
+++ b/src/3rdparty/v8/src/scopeinfo.cc
@@ -53,7 +53,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Scope* scope) {
FunctionVariableInfo function_name_info;
VariableMode function_variable_mode;
if (scope->is_function_scope() && scope->function() != NULL) {
- Variable* var = scope->function()->var();
+ Variable* var = scope->function()->proxy()->var();
if (!var->is_used()) {
function_name_info = UNUSED;
} else if (var->IsContextSlot()) {
@@ -80,7 +80,6 @@ Handle<ScopeInfo> ScopeInfo::Create(Scope* scope) {
int flags = TypeField::encode(scope->type()) |
CallsEvalField::encode(scope->calls_eval()) |
LanguageModeField::encode(scope->language_mode()) |
- QmlModeField::encode(scope->is_qml_mode()) |
FunctionVariableField::encode(function_name_info) |
FunctionVariableMode::encode(function_variable_mode);
scope_info->SetFlags(flags);
@@ -130,8 +129,8 @@ Handle<ScopeInfo> ScopeInfo::Create(Scope* scope) {
// If present, add the function variable name and its index.
ASSERT(index == scope_info->FunctionNameEntryIndex());
if (has_function_name) {
- int var_index = scope->function()->var()->index();
- scope_info->set(index++, *scope->function()->name());
+ int var_index = scope->function()->proxy()->var()->index();
+ scope_info->set(index++, *scope->function()->proxy()->name());
scope_info->set(index++, Smi::FromInt(var_index));
ASSERT(function_name_info != STACK ||
(var_index == scope_info->StackLocalCount() &&
@@ -143,7 +142,9 @@ Handle<ScopeInfo> ScopeInfo::Create(Scope* scope) {
ASSERT(index == scope_info->length());
ASSERT(scope->num_parameters() == scope_info->ParameterCount());
ASSERT(scope->num_stack_slots() == scope_info->StackSlotCount());
- ASSERT(scope->num_heap_slots() == scope_info->ContextLength());
+ ASSERT(scope->num_heap_slots() == scope_info->ContextLength() ||
+ (scope->num_heap_slots() == kVariablePartIndex &&
+ scope_info->ContextLength() == 0));
return scope_info;
}
@@ -169,11 +170,6 @@ LanguageMode ScopeInfo::language_mode() {
}
-bool ScopeInfo::IsQmlMode() {
- return length() > 0 && QmlModeField::decode(Flags());
-}
-
-
int ScopeInfo::LocalCount() {
return StackLocalCount() + ContextLocalCount();
}
@@ -189,7 +185,7 @@ int ScopeInfo::StackSlotCount() {
}
-int ScopeInfo::ContextLength(bool qml_function) {
+int ScopeInfo::ContextLength() {
if (length() > 0) {
int context_locals = ContextLocalCount();
bool function_name_context_slot =
@@ -198,9 +194,7 @@ int ScopeInfo::ContextLength(bool qml_function) {
function_name_context_slot ||
Type() == WITH_SCOPE ||
(Type() == FUNCTION_SCOPE && CallsEval());
-
- // TODO: The QML mode should be checked in the has_context expression.
- if (has_context || qml_function) {
+ if (has_context) {
return Context::MIN_CONTEXT_SLOTS + context_locals +
(function_name_context_slot ? 1 : 0);
}
diff --git a/src/3rdparty/v8/src/scopes.cc b/src/3rdparty/v8/src/scopes.cc
index 1f18e51..2c61a75 100644
--- a/src/3rdparty/v8/src/scopes.cc
+++ b/src/3rdparty/v8/src/scopes.cc
@@ -36,8 +36,6 @@
#include "allocation-inl.h"
-#include "debug.h"
-
namespace v8 {
namespace internal {
@@ -186,8 +184,6 @@ void Scope::SetDefaults(ScopeType type,
// Inherit the strict mode from the parent scope.
language_mode_ = (outer_scope != NULL)
? outer_scope->language_mode_ : CLASSIC_MODE;
- qml_mode_flag_ = (outer_scope != NULL)
- ? outer_scope->qml_mode_flag_ : kNonQmlMode;
outer_scope_calls_non_strict_eval_ = false;
inner_scope_calls_eval_ = false;
force_eager_compilation_ = false;
@@ -392,14 +388,17 @@ Variable* Scope::LocalLookup(Handle<String> name) {
// Check context slot lookup.
VariableMode mode;
+ Variable::Location location = Variable::CONTEXT;
InitializationFlag init_flag;
int index = scope_info_->ContextSlotIndex(*name, &mode, &init_flag);
if (index < 0) {
// Check parameters.
- mode = VAR;
- init_flag = kCreatedInitialized;
index = scope_info_->ParameterIndex(*name);
if (index < 0) return NULL;
+
+ mode = DYNAMIC;
+ location = Variable::LOOKUP;
+ init_flag = kCreatedInitialized;
}
Variable* var =
@@ -409,21 +408,27 @@ Variable* Scope::LocalLookup(Handle<String> name) {
true,
Variable::NORMAL,
init_flag);
- var->AllocateTo(Variable::CONTEXT, index);
+ var->AllocateTo(location, index);
return var;
}
Variable* Scope::LookupFunctionVar(Handle<String> name,
AstNodeFactory<AstNullVisitor>* factory) {
- if (function_ != NULL && function_->name().is_identical_to(name)) {
- return function_->var();
+ if (function_ != NULL && function_->proxy()->name().is_identical_to(name)) {
+ return function_->proxy()->var();
} else if (!scope_info_.is_null()) {
// If we are backed by a scope info, try to lookup the variable there.
VariableMode mode;
int index = scope_info_->FunctionContextSlotIndex(*name, &mode);
if (index < 0) return NULL;
- Variable* var = DeclareFunctionVar(name, mode, factory);
+ Variable* var = new Variable(
+ this, name, mode, true /* is valid LHS */,
+ Variable::NORMAL, kCreatedInitialized);
+ VariableProxy* proxy = factory->NewVariableProxy(var);
+ VariableDeclaration* declaration =
+ factory->NewVariableDeclaration(proxy, mode, this);
+ DeclareFunctionVar(declaration);
var->AllocateTo(Variable::CONTEXT, index);
return var;
} else {
@@ -653,6 +658,26 @@ bool Scope::HasTrivialOuterContext() const {
}
+bool Scope::AllowsLazyRecompilation() const {
+ return !force_eager_compilation_ &&
+ !TrivialDeclarationScopesBeforeWithScope();
+}
+
+
+bool Scope::TrivialDeclarationScopesBeforeWithScope() const {
+ Scope* outer = outer_scope_;
+ if (outer == NULL) return false;
+ outer = outer->DeclarationScope();
+ while (outer != NULL) {
+ if (outer->is_with_scope()) return true;
+ if (outer->is_declaration_scope() && outer->num_heap_slots() > 0)
+ return false;
+ outer = outer->outer_scope_;
+ }
+ return false;
+}
+
+
int Scope::ContextChainLength(Scope* scope) {
int n = 0;
for (Scope* s = this; s != scope; s = s->outer_scope_) {
@@ -795,7 +820,7 @@ void Scope::Print(int n) {
// Function name, if any (named function literals, only).
if (function_ != NULL) {
Indent(n1, "// (local) function name: ");
- PrintName(function_->name());
+ PrintName(function_->proxy()->name());
PrintF("\n");
}
@@ -828,7 +853,7 @@ void Scope::Print(int n) {
// Print locals.
Indent(n1, "// function var\n");
if (function_ != NULL) {
- PrintVar(n1, function_->var());
+ PrintVar(n1, function_->proxy()->var());
}
Indent(n1, "// temporary vars\n");
@@ -953,30 +978,14 @@ bool Scope::ResolveVariable(CompilationInfo* info,
break;
case BOUND_EVAL_SHADOWED:
- // We found a variable variable binding that might be shadowed
- // by 'eval' introduced variable bindings.
+ // We either found a variable binding that might be shadowed by eval or
+ // gave up on it (e.g. by encountering a local with the same in the outer
+ // scope which was not promoted to a context, this can happen if we use
+ // debugger to evaluate arbitrary expressions at a break point).
if (var->is_global()) {
var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
-
- if (is_qml_mode()) {
- Handle<GlobalObject> global = isolate_->global();
-
-#ifdef ENABLE_DEBUGGER_SUPPORT
- if (isolate_->debug()->IsLoaded() && isolate_->debug()->InDebugger()) {
- // Get the context before the debugger was entered.
- SaveContext *save = isolate_->save_context();
- while (save != NULL && *save->context() == *isolate_->debug()->debug_context())
- save = save->prev();
-
- global = Handle<GlobalObject>(save->context()->global());
- }
-#endif
-
- if (is_qml_mode() && !global->HasProperty(*(proxy->name()))) {
- var->set_is_qml_global(true);
- }
- }
-
+ } else if (var->is_dynamic()) {
+ var = NonLocal(proxy->name(), DYNAMIC);
} else {
Variable* invalidated = var;
var = NonLocal(proxy->name(), DYNAMIC_LOCAL);
@@ -987,52 +996,12 @@ bool Scope::ResolveVariable(CompilationInfo* info,
case UNBOUND:
// No binding has been found. Declare a variable in global scope.
var = info->global_scope()->DeclareGlobal(proxy->name());
-
- if (is_qml_mode()) {
- Handle<GlobalObject> global = isolate_->global();
-
-#ifdef ENABLE_DEBUGGER_SUPPORT
- if (isolate_->debug()->IsLoaded() && isolate_->debug()->InDebugger()) {
- // Get the context before the debugger was entered.
- SaveContext *save = isolate_->save_context();
- while (save != NULL && *save->context() == *isolate_->debug()->debug_context())
- save = save->prev();
-
- global = Handle<GlobalObject>(save->context()->global());
- }
-#endif
-
- if (!global->HasProperty(*(proxy->name()))) {
- var->set_is_qml_global(true);
- }
- }
-
break;
case UNBOUND_EVAL_SHADOWED:
// No binding has been found. But some scope makes a
// non-strict 'eval' call.
var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
-
- if (is_qml_mode()) {
- Handle<GlobalObject> global = isolate_->global();
-
-#ifdef ENABLE_DEBUGGER_SUPPORT
- if (isolate_->debug()->IsLoaded() && isolate_->debug()->InDebugger()) {
- // Get the context before the debugger was entered.
- SaveContext *save = isolate_->save_context();
- while (save != NULL && *save->context() == *isolate_->debug()->debug_context())
- save = save->prev();
-
- global = Handle<GlobalObject>(save->context()->global());
- }
-#endif
-
- if (is_qml_mode() && !global->HasProperty(*(proxy->name()))) {
- var->set_is_qml_global(true);
- }
- }
-
break;
case DYNAMIC_LOOKUP:
@@ -1150,7 +1119,7 @@ bool Scope::MustAllocateInContext(Variable* var) {
// Exceptions: temporary variables are never allocated in a context;
// catch-bound variables are always allocated in a context.
if (var->mode() == TEMPORARY) return false;
- if (is_catch_scope() || is_block_scope()) return true;
+ if (is_catch_scope() || is_block_scope() || is_module_scope()) return true;
return var->has_forced_context_allocation() ||
scope_calls_eval_ ||
inner_scope_calls_eval_ ||
@@ -1268,7 +1237,7 @@ void Scope::AllocateNonParameterLocals() {
// because of the current ScopeInfo implementation (see
// ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
if (function_ != NULL) {
- AllocateNonParameterLocal(function_->var());
+ AllocateNonParameterLocal(function_->proxy()->var());
}
}
@@ -1294,7 +1263,8 @@ void Scope::AllocateVariablesRecursively() {
// Force allocation of a context for this scope if necessary. For a 'with'
// scope and for a function scope that makes an 'eval' call we need a context,
// even if no local variables were statically allocated in the scope.
- bool must_have_context = is_with_scope() ||
+ // Likewise for modules.
+ bool must_have_context = is_with_scope() || is_module_scope() ||
(is_function_scope() && calls_eval());
// If we didn't allocate any locals in the local context, then we only
@@ -1310,14 +1280,14 @@ void Scope::AllocateVariablesRecursively() {
int Scope::StackLocalCount() const {
return num_stack_slots() -
- (function_ != NULL && function_->var()->IsStackLocal() ? 1 : 0);
+ (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0);
}
int Scope::ContextLocalCount() const {
if (num_heap_slots() == 0) return 0;
return num_heap_slots() - Context::MIN_CONTEXT_SLOTS -
- (function_ != NULL && function_->var()->IsContextSlot() ? 1 : 0);
+ (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0);
}
} } // namespace v8::internal
diff --git a/src/3rdparty/v8/src/scopes.h b/src/3rdparty/v8/src/scopes.h
index 2a3b4d3..be6705b 100644
--- a/src/3rdparty/v8/src/scopes.h
+++ b/src/3rdparty/v8/src/scopes.h
@@ -126,15 +126,9 @@ class Scope: public ZoneObject {
// Declare the function variable for a function literal. This variable
// is in an intermediate scope between this function scope and the the
// outer scope. Only possible for function scopes; at most one variable.
- template<class Visitor>
- Variable* DeclareFunctionVar(Handle<String> name,
- VariableMode mode,
- AstNodeFactory<Visitor>* factory) {
- ASSERT(is_function_scope() && function_ == NULL);
- Variable* function_var = new Variable(
- this, name, mode, true, Variable::NORMAL, kCreatedInitialized);
- function_ = factory->NewVariableProxy(function_var);
- return function_var;
+ void DeclareFunctionVar(VariableDeclaration* declaration) {
+ ASSERT(is_function_scope());
+ function_ = declaration;
}
// Declare a parameter in this scope. When there are duplicated
@@ -230,11 +224,6 @@ class Scope: public ZoneObject {
language_mode_ = language_mode;
}
- // Enable qml mode for this scope
- void EnableQmlModeFlag() {
- qml_mode_flag_ = kQmlMode;
- }
-
// Position in the source where this scope begins and ends.
//
// * For the scope of a with statement
@@ -289,7 +278,6 @@ class Scope: public ZoneObject {
bool is_strict_or_extended_eval_scope() const {
return is_eval_scope() && !is_classic_mode();
}
- bool is_qml_mode() const { return qml_mode_flag() == kQmlMode; }
// Information about which scopes calls eval.
bool calls_eval() const { return scope_calls_eval_; }
@@ -314,16 +302,12 @@ class Scope: public ZoneObject {
// The language mode of this scope.
LanguageMode language_mode() const { return language_mode_; }
- // The strict mode of this scope.
- QmlModeFlag qml_mode_flag() const { return qml_mode_flag_; }
-
// The variable corresponding the 'this' value.
Variable* receiver() { return receiver_; }
// The variable holding the function literal for named function
- // literals, or NULL.
- // Only valid for function scopes.
- VariableProxy* function() const {
+ // literals, or NULL. Only valid for function scopes.
+ VariableDeclaration* function() const {
ASSERT(is_function_scope());
return function_;
}
@@ -378,13 +362,16 @@ class Scope: public ZoneObject {
bool AllowsLazyCompilation() const;
// True if we can lazily recompile functions with this scope.
- bool allows_lazy_recompilation() const {
- return !force_eager_compilation_;
- }
+ bool AllowsLazyRecompilation() const;
// True if the outer context of this scope is always the global context.
bool HasTrivialOuterContext() const;
+ // True if this scope is inside a with scope and all declaration scopes
+ // between them have empty contexts. Such declaration scopes become
+ // invisible during scope info deserialization.
+ bool TrivialDeclarationScopesBeforeWithScope() const;
+
// The number of contexts between this and scope; zero if this == scope.
int ContextChainLength(Scope* scope);
@@ -455,7 +442,7 @@ class Scope: public ZoneObject {
// Convenience variable.
Variable* receiver_;
// Function variable, if any; function scopes only.
- VariableProxy* function_;
+ VariableDeclaration* function_;
// Convenience variable; function scopes only.
Variable* arguments_;
// Interface; module scopes only.
@@ -475,8 +462,6 @@ class Scope: public ZoneObject {
bool scope_calls_eval_;
// The language mode of this scope.
LanguageMode language_mode_;
- // This scope is a qml mode scope.
- QmlModeFlag qml_mode_flag_;
// Source positions.
int start_position_;
int end_position_;
diff --git a/src/3rdparty/v8/src/serialize.cc b/src/3rdparty/v8/src/serialize.cc
index 01d5f1c..cf8e5e1 100644
--- a/src/3rdparty/v8/src/serialize.cc
+++ b/src/3rdparty/v8/src/serialize.cc
@@ -244,7 +244,7 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
"Isolate::" #hacker_name "_address",
FOR_EACH_ISOLATE_ADDRESS_NAME(BUILD_NAME_LITERAL)
NULL
-#undef C
+#undef BUILD_NAME_LITERAL
};
for (uint16_t i = 0; i < Isolate::kIsolateAddressCount; ++i) {
diff --git a/src/3rdparty/v8/src/spaces-inl.h b/src/3rdparty/v8/src/spaces-inl.h
index 55bf222..ed78fc7 100644
--- a/src/3rdparty/v8/src/spaces-inl.h
+++ b/src/3rdparty/v8/src/spaces-inl.h
@@ -295,11 +295,27 @@ MaybeObject* PagedSpace::AllocateRaw(int size_in_bytes) {
MaybeObject* NewSpace::AllocateRaw(int size_in_bytes) {
Address old_top = allocation_info_.top;
+#ifdef DEBUG
+ // If we are stressing compaction we waste some memory in new space
+ // in order to get more frequent GCs.
+ if (FLAG_stress_compaction && !HEAP->linear_allocation()) {
+ if (allocation_info_.limit - old_top >= size_in_bytes * 4) {
+ int filler_size = size_in_bytes * 4;
+ for (int i = 0; i < filler_size; i += kPointerSize) {
+ *(reinterpret_cast<Object**>(old_top + i)) =
+ HEAP->one_pointer_filler_map();
+ }
+ old_top += filler_size;
+ allocation_info_.top += filler_size;
+ }
+ }
+#endif
+
if (allocation_info_.limit - old_top < size_in_bytes) {
return SlowAllocateRaw(size_in_bytes);
}
- Object* obj = HeapObject::FromAddress(allocation_info_.top);
+ Object* obj = HeapObject::FromAddress(old_top);
allocation_info_.top += size_in_bytes;
ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
diff --git a/src/3rdparty/v8/src/spaces.cc b/src/3rdparty/v8/src/spaces.cc
index 6144464..a0c8f2c 100644
--- a/src/3rdparty/v8/src/spaces.cc
+++ b/src/3rdparty/v8/src/spaces.cc
@@ -362,15 +362,22 @@ Address MemoryAllocator::AllocateAlignedMemory(size_t size,
if (base == NULL) return NULL;
if (executable == EXECUTABLE) {
- CommitCodePage(&reservation, base, size);
+ if (!CommitCodePage(&reservation, base, size)) {
+ base = NULL;
+ }
} else {
- if (!reservation.Commit(base,
- size,
- executable == EXECUTABLE)) {
- return NULL;
+ if (!reservation.Commit(base, size, false)) {
+ base = NULL;
}
}
+ if (base == NULL) {
+ // Failed to commit the body. Release the mapping and any partially
+ // commited regions inside it.
+ reservation.Release();
+ return NULL;
+ }
+
controller->TakeControl(&reservation);
return base;
}
@@ -2288,8 +2295,6 @@ bool PagedSpace::AdvanceSweeper(intptr_t bytes_to_sweep) {
first_unswept_page_ = p;
}
- heap()->LowerOldGenLimits(freed_bytes);
-
heap()->FreeQueuedChunks();
return IsSweepingComplete();
diff --git a/src/3rdparty/v8/src/spaces.h b/src/3rdparty/v8/src/spaces.h
index 90f62f3..b0ecc5d 100644
--- a/src/3rdparty/v8/src/spaces.h
+++ b/src/3rdparty/v8/src/spaces.h
@@ -1042,7 +1042,9 @@ class MemoryAllocator {
return CodePageAreaEndOffset() - CodePageAreaStartOffset();
}
- static bool CommitCodePage(VirtualMemory* vm, Address start, size_t size);
+ MUST_USE_RESULT static bool CommitCodePage(VirtualMemory* vm,
+ Address start,
+ size_t size);
private:
Isolate* isolate_;
@@ -1520,6 +1522,10 @@ class PagedSpace : public Space {
return size_in_bytes - wasted;
}
+ void ResetFreeList() {
+ free_list_.Reset();
+ }
+
// Set space allocation info.
void SetTop(Address top, Address limit) {
ASSERT(top == limit ||
@@ -2371,11 +2377,6 @@ class FixedSpace : public PagedSpace {
// Prepares for a mark-compact GC.
virtual void PrepareForMarkCompact();
- protected:
- void ResetFreeList() {
- free_list_.Reset();
- }
-
private:
// The size of objects in this space.
int object_size_in_bytes_;
diff --git a/src/3rdparty/v8/src/string.js b/src/3rdparty/v8/src/string.js
index a464f7f..6115930 100644
--- a/src/3rdparty/v8/src/string.js
+++ b/src/3rdparty/v8/src/string.js
@@ -237,10 +237,28 @@ function StringReplace(search, replace) {
replace);
}
} else {
- return %StringReplaceRegExpWithString(subject,
- search,
- TO_STRING_INLINE(replace),
- lastMatchInfo);
+ if (lastMatchInfoOverride == null) {
+ return %StringReplaceRegExpWithString(subject,
+ search,
+ TO_STRING_INLINE(replace),
+ lastMatchInfo);
+ } 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 answer = %StringReplaceRegExpWithString(subject,
+ search,
+ TO_STRING_INLINE(replace),
+ lastMatchInfo);
+ if (%_IsSmi(lastMatchInfo[LAST_SUBJECT_INDEX])) {
+ lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject;
+ } else {
+ lastMatchInfoOverride = null;
+ }
+ return answer;
+ }
}
}
@@ -259,47 +277,34 @@ function StringReplace(search, replace) {
if (start < 0) return subject;
var end = start + search.length;
- var builder = new ReplaceResultBuilder(subject);
- // prefix
- builder.addSpecialSlice(0, start);
+ var result = SubString(subject, 0, start);
// Compute the string to replace with.
if (IS_SPEC_FUNCTION(replace)) {
var receiver = %GetDefaultReceiver(replace);
- builder.add(%_CallFunction(receiver,
- search,
- start,
- subject,
- replace));
+ result += %_CallFunction(receiver, search, start, subject, replace);
} else {
reusableMatchInfo[CAPTURE0] = start;
reusableMatchInfo[CAPTURE1] = end;
replace = TO_STRING_INLINE(replace);
- ExpandReplacement(replace, subject, reusableMatchInfo, builder);
+ result = ExpandReplacement(replace, subject, reusableMatchInfo, result);
}
- // suffix
- builder.addSpecialSlice(end, subject.length);
-
- return builder.generate();
+ return result + SubString(subject, end, subject.length);
}
// Expand the $-expressions in the string and return a new string with
// the result.
-function ExpandReplacement(string, subject, matchInfo, builder) {
+function ExpandReplacement(string, subject, matchInfo, result) {
var length = string.length;
- var builder_elements = builder.elements;
var next = %StringIndexOf(string, '$', 0);
if (next < 0) {
- if (length > 0) builder_elements.push(string);
- return;
+ if (length > 0) result += string;
+ return result;
}
- // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102.
- var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; // Includes the match.
-
- if (next > 0) builder_elements.push(SubString(string, 0, next));
+ if (next > 0) result += SubString(string, 0, next);
while (true) {
var expansion = '$';
@@ -308,51 +313,21 @@ function ExpandReplacement(string, subject, matchInfo, builder) {
var peek = %_StringCharCodeAt(string, position);
if (peek == 36) { // $$
++position;
- builder_elements.push('$');
+ result += '$';
} else if (peek == 38) { // $& - match
++position;
- builder.addSpecialSlice(matchInfo[CAPTURE0],
- matchInfo[CAPTURE1]);
+ result += SubString(subject, matchInfo[CAPTURE0], matchInfo[CAPTURE1]);
} else if (peek == 96) { // $` - prefix
++position;
- builder.addSpecialSlice(0, matchInfo[CAPTURE0]);
+ result += SubString(subject, 0, matchInfo[CAPTURE0]);
} else if (peek == 39) { // $' - suffix
++position;
- builder.addSpecialSlice(matchInfo[CAPTURE1], subject.length);
- } else if (peek >= 48 && peek <= 57) { // $n, 0 <= n <= 9
- ++position;
- var n = peek - 48;
- if (position < length) {
- peek = %_StringCharCodeAt(string, position);
- // $nn, 01 <= nn <= 99
- if (n != 0 && peek == 48 || peek >= 49 && peek <= 57) {
- var nn = n * 10 + (peek - 48);
- if (nn < m) {
- // If the two digit capture reference is within range of
- // the captures, we use it instead of the single digit
- // one. Otherwise, we fall back to using the single
- // digit reference. This matches the behavior of
- // SpiderMonkey.
- ++position;
- n = nn;
- }
- }
- }
- if (0 < n && n < m) {
- addCaptureString(builder, matchInfo, n);
- } else {
- // Because of the captures range check in the parsing of two
- // digit capture references, we can only enter here when a
- // single digit capture reference is outside the range of
- // captures.
- builder_elements.push('$');
- --position;
- }
+ result += SubString(subject, matchInfo[CAPTURE1], subject.length);
} else {
- builder_elements.push('$');
+ result += '$';
}
} else {
- builder_elements.push('$');
+ result += '$';
}
// Go the the next $ in the string.
@@ -362,16 +337,17 @@ function ExpandReplacement(string, subject, matchInfo, builder) {
// haven't reached the end, we need to append the suffix.
if (next < 0) {
if (position < length) {
- builder_elements.push(SubString(string, position, length));
+ result += SubString(string, position, length);
}
- return;
+ return result;
}
// Append substring between the previous and the next $ character.
if (next > position) {
- builder_elements.push(SubString(string, position, next));
+ result += SubString(string, position, next);
}
}
+ return result;
}
@@ -388,18 +364,6 @@ function CaptureString(string, lastCaptureInfo, index) {
}
-// Add the string of a given regular expression capture to the
-// ReplaceResultBuilder
-function addCaptureString(builder, matchInfo, index) {
- // Scale the index.
- var scaled = index << 1;
- // Compute start and end.
- var start = matchInfo[CAPTURE(scaled)];
- if (start < 0) return;
- var end = matchInfo[CAPTURE(scaled + 1)];
- builder.addSpecialSlice(start, end);
-}
-
// TODO(lrn): This array will survive indefinitely if replace is never
// called again. However, it will be empty, since the contents are cleared
// in the finally block.
@@ -429,14 +393,22 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
return subject;
}
var len = res.length;
- var i = 0;
if (NUMBER_OF_CAPTURES(lastMatchInfo) == 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.
+ // The builder will consist of some integers that indicate slices of the
+ // input string and some replacements that were returned from the replace
+ // function.
var match_start = 0;
var override = new InternalArray(null, 0, subject);
var receiver = %GetDefaultReceiver(replace);
- while (i < len) {
+ for (var i = 0; i < len; i++) {
var elem = res[i];
if (%_IsSmi(elem)) {
+ // Integers represent slices of the original string. Use these to
+ // get the offsets we need for the override array (so things like
+ // RegExp.leftContext work during the callback function.
if (elem > 0) {
match_start = (elem >> 11) + (elem & 0x7ff);
} else {
@@ -448,23 +420,25 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
lastMatchInfoOverride = override;
var func_result =
%_CallFunction(receiver, elem, match_start, subject, replace);
+ // Overwrite the i'th element in the results with the string we got
+ // back from the callback function.
res[i] = TO_STRING_INLINE(func_result);
match_start += elem.length;
}
- i++;
}
} else {
var receiver = %GetDefaultReceiver(replace);
- while (i < len) {
+ for (var i = 0; i < len; i++) {
var elem = res[i];
if (!%_IsSmi(elem)) {
// elem must be an Array.
// Use the apply argument as backing for global RegExp properties.
lastMatchInfoOverride = 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.
res[i] = TO_STRING_INLINE(func_result);
}
- i++;
}
}
var resultBuilder = new ReplaceResultBuilder(subject, res);
@@ -478,9 +452,8 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
var matchInfo = DoRegExpExec(regexp, subject, 0);
if (IS_NULL(matchInfo)) return subject;
- var result = new ReplaceResultBuilder(subject);
var index = matchInfo[CAPTURE0];
- result.addSpecialSlice(0, index);
+ var result = SubString(subject, 0, index);
var endOfMatch = matchInfo[CAPTURE1];
// Compute the parameter list consisting of the match, captures, index,
// and subject for the replace function invocation.
@@ -492,8 +465,7 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
// No captures, only the match, which is always valid.
var s = SubString(subject, index, endOfMatch);
// Don't call directly to avoid exposing the built-in global object.
- replacement =
- %_CallFunction(receiver, s, index, subject, replace);
+ replacement = %_CallFunction(receiver, s, index, subject, replace);
} else {
var parameters = new InternalArray(m + 2);
for (var j = 0; j < m; j++) {
@@ -505,11 +477,10 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
replacement = %Apply(replace, receiver, parameters, 0, j + 2);
}
- result.add(replacement); // The add method converts to string if necessary.
+ result += replacement; // The add method converts to string if necessary.
// Can't use matchInfo any more from here, since the function could
// overwrite it.
- result.addSpecialSlice(endOfMatch, subject.length);
- return result.generate();
+ return result + SubString(subject, endOfMatch, subject.length);
}
diff --git a/src/3rdparty/v8/src/stub-cache.cc b/src/3rdparty/v8/src/stub-cache.cc
index b8c0058..bd7163a 100644
--- a/src/3rdparty/v8/src/stub-cache.cc
+++ b/src/3rdparty/v8/src/stub-cache.cc
@@ -763,8 +763,7 @@ Handle<Code> StubCache::ComputeCallPreMonomorphic(
Handle<Code> StubCache::ComputeCallNormal(int argc,
Code::Kind kind,
- Code::ExtraICState extra_state,
- bool has_qml_global_receiver) {
+ Code::ExtraICState extra_state) {
Code::Flags flags =
Code::ComputeFlags(kind, MONOMORPHIC, extra_state, NORMAL, argc);
Handle<UnseededNumberDictionary> cache =
@@ -773,7 +772,7 @@ Handle<Code> StubCache::ComputeCallNormal(int argc,
if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
StubCompiler compiler(isolate_);
- Handle<Code> code = compiler.CompileCallNormal(flags, has_qml_global_receiver);
+ Handle<Code> code = compiler.CompileCallNormal(flags);
FillCache(isolate_, code);
return code;
}
@@ -940,7 +939,8 @@ void StubCache::CollectMatchingMaps(SmallMapList* types,
RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty) {
ASSERT(args[0]->IsJSObject());
ASSERT(args[1]->IsJSObject());
- AccessorInfo* callback = AccessorInfo::cast(args[3]);
+ ASSERT(args[3]->IsSmi());
+ AccessorInfo* callback = AccessorInfo::cast(args[4]);
Address getter_address = v8::ToCData<Address>(callback->getter());
v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
ASSERT(fun != NULL);
@@ -951,7 +951,7 @@ RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty) {
// Leaving JavaScript.
VMState state(isolate, EXTERNAL);
ExternalCallbackScope call_scope(isolate, getter_address);
- result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
+ result = fun(v8::Utils::ToLocal(args.at<String>(5)), info);
}
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (result.IsEmpty()) return HEAP->undefined_value();
@@ -998,7 +998,8 @@ RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
ASSERT(args[2]->IsJSObject()); // Receiver.
ASSERT(args[3]->IsJSObject()); // Holder.
- ASSERT(args.length() == 5); // Last arg is data object.
+ ASSERT(args[5]->IsSmi()); // Isolate.
+ ASSERT(args.length() == 6);
Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
v8::NamedPropertyGetter getter =
@@ -1051,7 +1052,7 @@ static MaybeObject* LoadWithInterceptor(Arguments* args,
ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
Handle<JSObject> receiver_handle = args->at<JSObject>(2);
Handle<JSObject> holder_handle = args->at<JSObject>(3);
- ASSERT(args->length() == 5); // Last arg is data object.
+ ASSERT(args->length() == 6);
Isolate* isolate = receiver_handle->GetIsolate();
@@ -1178,15 +1179,13 @@ Handle<Code> StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
}
-Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags, bool has_qml_global_receiver) {
+Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags) {
int argc = Code::ExtractArgumentsCountFromFlags(flags);
Code::Kind kind = Code::ExtractKindFromFlags(flags);
if (kind == Code::CALL_IC) {
- // Call normal is always with a explict receiver,
- // or with an implicit qml global receiver.
+ // Call normal is always with a explict receiver.
ASSERT(!CallIC::Contextual::decode(
- Code::ExtractExtraICStateFromFlags(flags)) ||
- has_qml_global_receiver);
+ Code::ExtractExtraICStateFromFlags(flags)));
CallIC::GenerateNormal(masm(), argc);
} else {
KeyedCallIC::GenerateNormal(masm(), argc);
diff --git a/src/3rdparty/v8/src/stub-cache.h b/src/3rdparty/v8/src/stub-cache.h
index 206dddd..29bdb61 100644
--- a/src/3rdparty/v8/src/stub-cache.h
+++ b/src/3rdparty/v8/src/stub-cache.h
@@ -219,8 +219,7 @@ class StubCache {
Handle<Code> ComputeCallNormal(int argc,
Code::Kind kind,
- Code::ExtraICState state,
- bool has_qml_global_receiver);
+ Code::ExtraICState state);
Handle<Code> ComputeCallArguments(int argc, Code::Kind kind);
@@ -411,7 +410,7 @@ class StubCompiler BASE_EMBEDDED {
// is extracted from the code flags.
Handle<Code> CompileCallInitialize(Code::Flags flags);
Handle<Code> CompileCallPreMonomorphic(Code::Flags flags);
- Handle<Code> CompileCallNormal(Code::Flags flags, bool has_qml_global_receiver);
+ Handle<Code> CompileCallNormal(Code::Flags flags);
Handle<Code> CompileCallMegamorphic(Code::Flags flags);
Handle<Code> CompileCallArguments(Code::Flags flags);
Handle<Code> CompileCallMiss(Code::Flags flags);
diff --git a/src/3rdparty/v8/src/utils.cc b/src/3rdparty/v8/src/utils.cc
index 89ef4c6..7e8c088 100644
--- a/src/3rdparty/v8/src/utils.cc
+++ b/src/3rdparty/v8/src/utils.cc
@@ -89,4 +89,19 @@ char* SimpleStringBuilder::Finalize() {
return buffer_.start();
}
+
+const DivMagicNumbers DivMagicNumberFor(int32_t divisor) {
+ switch (divisor) {
+ case 3: return DivMagicNumberFor3;
+ case 5: return DivMagicNumberFor5;
+ case 7: return DivMagicNumberFor7;
+ case 9: return DivMagicNumberFor9;
+ case 11: return DivMagicNumberFor11;
+ case 25: return DivMagicNumberFor25;
+ case 125: return DivMagicNumberFor125;
+ case 625: return DivMagicNumberFor625;
+ default: return InvalidDivMagicNumber;
+ }
+}
+
} } // namespace v8::internal
diff --git a/src/3rdparty/v8/src/utils.h b/src/3rdparty/v8/src/utils.h
index 1d40c98..f116c14 100644
--- a/src/3rdparty/v8/src/utils.h
+++ b/src/3rdparty/v8/src/utils.h
@@ -85,6 +85,32 @@ inline int WhichPowerOf2(uint32_t x) {
}
+// Magic numbers for integer division.
+// These are kind of 2's complement reciprocal of the divisors.
+// Details and proofs can be found in:
+// - Hacker's Delight, Henry S. Warren, Jr.
+// - The PowerPC Compiler Writer’s Guide
+// and probably many others.
+// See details in the implementation of the algorithm in
+// lithium-codegen-arm.cc : LCodeGen::TryEmitSignedIntegerDivisionByConstant().
+struct DivMagicNumbers {
+ unsigned M;
+ unsigned s;
+};
+
+const DivMagicNumbers InvalidDivMagicNumber= {0, 0};
+const DivMagicNumbers DivMagicNumberFor3 = {0x55555556, 0};
+const DivMagicNumbers DivMagicNumberFor5 = {0x66666667, 1};
+const DivMagicNumbers DivMagicNumberFor7 = {0x92492493, 2};
+const DivMagicNumbers DivMagicNumberFor9 = {0x38e38e39, 1};
+const DivMagicNumbers DivMagicNumberFor11 = {0x2e8ba2e9, 1};
+const DivMagicNumbers DivMagicNumberFor25 = {0x51eb851f, 3};
+const DivMagicNumbers DivMagicNumberFor125 = {0x10624dd3, 3};
+const DivMagicNumbers DivMagicNumberFor625 = {0x68db8bad, 8};
+
+const DivMagicNumbers DivMagicNumberFor(int32_t divisor);
+
+
// The C++ standard leaves the semantics of '>>' undefined for
// negative signed operands. Most implementations do the right thing,
// though.
diff --git a/src/3rdparty/v8/src/v8.cc b/src/3rdparty/v8/src/v8.cc
index 45036c8..2910a07 100644
--- a/src/3rdparty/v8/src/v8.cc
+++ b/src/3rdparty/v8/src/v8.cc
@@ -118,6 +118,8 @@ void V8::TearDown() {
delete call_completed_callbacks_;
call_completed_callbacks_ = NULL;
+
+ OS::TearDown();
}
@@ -248,7 +250,6 @@ Object* V8::FillHeapNumberWithRandom(Object* heap_number,
}
void V8::InitializeOncePerProcessImpl() {
- // Set up the platform OS support.
OS::SetUp();
use_crankshaft_ = FLAG_crankshaft;
diff --git a/src/3rdparty/v8/src/v8globals.h b/src/3rdparty/v8/src/v8globals.h
index bfc5e23..6a1766a 100644
--- a/src/3rdparty/v8/src/v8globals.h
+++ b/src/3rdparty/v8/src/v8globals.h
@@ -48,6 +48,10 @@ const intptr_t kObjectAlignmentMask = kObjectAlignment - 1;
const intptr_t kPointerAlignment = (1 << kPointerSizeLog2);
const intptr_t kPointerAlignmentMask = kPointerAlignment - 1;
+// Desired alignment for double values.
+const intptr_t kDoubleAlignment = 8;
+const intptr_t kDoubleAlignmentMask = kDoubleAlignment - 1;
+
// Desired alignment for maps.
#if V8_HOST_ARCH_64_BIT
const intptr_t kMapAlignmentBits = kObjectAlignmentBits;
diff --git a/src/3rdparty/v8/src/v8utils.h b/src/3rdparty/v8/src/v8utils.h
index c73222a..bb587e1 100644
--- a/src/3rdparty/v8/src/v8utils.h
+++ b/src/3rdparty/v8/src/v8utils.h
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -199,10 +199,13 @@ Vector<const char> ReadFile(FILE* file,
bool verbose = true);
-
// Copy from ASCII/16bit chars to ASCII/16bit chars.
template <typename sourcechar, typename sinkchar>
-inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
+INLINE(void CopyChars(sinkchar* dest, const sourcechar* src, int chars));
+
+
+template <typename sourcechar, typename sinkchar>
+void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
sinkchar* limit = dest + chars;
#ifdef V8_HOST_CAN_READ_UNALIGNED
if (sizeof(*dest) == sizeof(*src)) {
diff --git a/src/3rdparty/v8/src/variables.cc b/src/3rdparty/v8/src/variables.cc
index 4984cbd..32ad5bc 100644
--- a/src/3rdparty/v8/src/variables.cc
+++ b/src/3rdparty/v8/src/variables.cc
@@ -73,8 +73,7 @@ Variable::Variable(Scope* scope,
force_context_allocation_(false),
is_used_(false),
initialization_flag_(initialization_flag),
- interface_(interface),
- is_qml_global_(false) {
+ interface_(interface) {
// Names must be canonicalized for fast equality checks.
ASSERT(name->IsSymbol());
// Var declared variables never need initialization.
diff --git a/src/3rdparty/v8/src/variables.h b/src/3rdparty/v8/src/variables.h
index 43b2c81..f49b6e1 100644
--- a/src/3rdparty/v8/src/variables.h
+++ b/src/3rdparty/v8/src/variables.h
@@ -164,9 +164,6 @@ class Variable: public ZoneObject {
static int CompareIndex(Variable* const* v, Variable* const* w);
- bool is_qml_global() const { return is_qml_global_; }
- void set_is_qml_global(bool is_qml_global) { is_qml_global_ = is_qml_global; }
-
private:
Scope* scope_;
Handle<String> name_;
@@ -192,9 +189,6 @@ class Variable: public ZoneObject {
// Module type info.
Interface* interface_;
-
- // QML info
- bool is_qml_global_;
};
diff --git a/src/3rdparty/v8/src/version.cc b/src/3rdparty/v8/src/version.cc
index 6b07103..79b6ebd 100644
--- a/src/3rdparty/v8/src/version.cc
+++ b/src/3rdparty/v8/src/version.cc
@@ -33,8 +33,8 @@
// NOTE these macros are used by the SCons build script so their names
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
-#define MINOR_VERSION 10
-#define BUILD_NUMBER 1
+#define MINOR_VERSION 11
+#define BUILD_NUMBER 4
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/3rdparty/v8/src/x64/assembler-x64.h b/src/3rdparty/v8/src/x64/assembler-x64.h
index 60b29e6..9f5f850 100644
--- a/src/3rdparty/v8/src/x64/assembler-x64.h
+++ b/src/3rdparty/v8/src/x64/assembler-x64.h
@@ -629,7 +629,8 @@ class Assembler : public AssemblerBase {
static const byte kJccShortPrefix = 0x70;
static const byte kJncShortOpcode = kJccShortPrefix | not_carry;
static const byte kJcShortOpcode = kJccShortPrefix | carry;
-
+ static const byte kJnzShortOpcode = kJccShortPrefix | not_zero;
+ static const byte kJzShortOpcode = kJccShortPrefix | zero;
// ---------------------------------------------------------------------------
diff --git a/src/3rdparty/v8/src/x64/code-stubs-x64.cc b/src/3rdparty/v8/src/x64/code-stubs-x64.cc
index 63c44e9..d179d2a 100644
--- a/src/3rdparty/v8/src/x64/code-stubs-x64.cc
+++ b/src/3rdparty/v8/src/x64/code-stubs-x64.cc
@@ -139,10 +139,6 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
__ movq(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ movq(Operand(rax, Context::SlotOffset(Context::GLOBAL_INDEX)), rbx);
- // Copy the qmlglobal object from the previous context.
- __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::QML_GLOBAL_INDEX)));
- __ movq(Operand(rax, Context::SlotOffset(Context::QML_GLOBAL_INDEX)), rbx);
-
// Initialize the rest of the slots to undefined.
__ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
@@ -207,10 +203,6 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
__ movq(rbx, ContextOperand(rsi, Context::GLOBAL_INDEX));
__ movq(ContextOperand(rax, Context::GLOBAL_INDEX), rbx);
- // Copy the qmlglobal object from the previous context.
- __ movq(rbx, ContextOperand(rsi, Context::QML_GLOBAL_INDEX));
- __ movq(ContextOperand(rax, Context::QML_GLOBAL_INDEX), rbx);
-
// Initialize the rest of the slots to the hole value.
__ LoadRoot(rbx, Heap::kTheHoleValueRootIndex);
for (int i = 0; i < slots_; i++) {
@@ -3328,37 +3320,6 @@ void CompareStub::Generate(MacroAssembler* masm) {
// NOTICE! This code is only reached after a smi-fast-case check, so
// it is certain that at least one operand isn't a smi.
- {
- Label not_user_equal, user_equal;
- __ JumpIfSmi(rax, &not_user_equal);
- __ JumpIfSmi(rdx, &not_user_equal);
-
- __ CmpObjectType(rax, JS_OBJECT_TYPE, rbx);
- __ j(not_equal, &not_user_equal);
-
- __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
- __ j(not_equal, &not_user_equal);
-
- __ testb(FieldOperand(rbx, Map::kBitField2Offset),
- Immediate(1 << Map::kUseUserObjectComparison));
- __ j(not_zero, &user_equal);
- __ testb(FieldOperand(rcx, Map::kBitField2Offset),
- Immediate(1 << Map::kUseUserObjectComparison));
- __ j(not_zero, &user_equal);
-
- __ jmp(&not_user_equal);
-
- __ bind(&user_equal);
-
- __ pop(rbx); // Return address.
- __ push(rax);
- __ push(rdx);
- __ push(rbx);
- __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
-
- __ bind(&not_user_equal);
- }
-
// Two identical objects are equal unless they are both NaN or undefined.
{
Label not_identical;
@@ -3667,8 +3628,9 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
void CallFunctionStub::Generate(MacroAssembler* masm) {
- // rdi : the function to call
// rbx : cache cell for call target
+ // rdi : the function to call
+ Isolate* isolate = masm->isolate();
Label slow, non_function;
// The receiver might implicitly be the global object. This is
@@ -3683,9 +3645,9 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
__ j(not_equal, &call, Label::kNear);
// Patch the receiver on the stack with the global receiver object.
- __ movq(rbx, GlobalObjectOperand());
- __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
- __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rbx);
+ __ movq(rcx, GlobalObjectOperand());
+ __ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
+ __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rcx);
__ bind(&call);
}
@@ -3695,6 +3657,10 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
__ j(not_equal, &slow);
+ if (RecordCallTarget()) {
+ GenerateRecordCallTarget(masm);
+ }
+
// Fast-case: Just invoke the function.
ParameterCount actual(argc_);
@@ -3717,6 +3683,13 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
// Slow-case: Non-function called.
__ bind(&slow);
+ if (RecordCallTarget()) {
+ // If there is a call target cache, mark it megamorphic in the
+ // non-function case. MegamorphicSentinel is an immortal immovable
+ // object (undefined) so no write barrier is needed.
+ __ Move(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
+ TypeFeedbackCells::MegamorphicSentinel(isolate));
+ }
// Check for function proxy.
__ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
__ j(not_equal, &non_function);
@@ -5151,56 +5124,24 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// rax: string
// rbx: instance type
// Calculate length of sub string using the smi values.
- Label result_longer_than_two;
__ movq(rcx, Operand(rsp, kToOffset));
__ movq(rdx, Operand(rsp, kFromOffset));
__ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime);
__ SmiSub(rcx, rcx, rdx); // Overflow doesn't happen.
- __ cmpq(FieldOperand(rax, String::kLengthOffset), rcx);
+ __ cmpq(rcx, FieldOperand(rax, String::kLengthOffset));
Label not_original_string;
- __ j(not_equal, &not_original_string, Label::kNear);
+ // Shorter than original string's length: an actual substring.
+ __ j(below, &not_original_string, Label::kNear);
+ // Longer than original string's length or negative: unsafe arguments.
+ __ j(above, &runtime);
+ // Return original string.
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->sub_string_native(), 1);
__ ret(kArgumentsSize);
__ bind(&not_original_string);
- // Special handling of sub-strings of length 1 and 2. One character strings
- // are handled in the runtime system (looked up in the single character
- // cache). Two character strings are looked for in the symbol cache.
__ SmiToInteger32(rcx, rcx);
- __ cmpl(rcx, Immediate(2));
- __ j(greater, &result_longer_than_two);
- __ j(less, &runtime);
-
- // Sub string of length 2 requested.
- // rax: string
- // rbx: instance type
- // rcx: sub string length (value is 2)
- // rdx: from index (smi)
- __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &runtime);
-
- // Get the two characters forming the sub string.
- __ SmiToInteger32(rdx, rdx); // From index is no longer smi.
- __ movzxbq(rbx, FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize));
- __ movzxbq(rdi,
- FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize + 1));
-
- // Try to lookup two character string in symbol table.
- Label make_two_character_string;
- StringHelper::GenerateTwoCharacterSymbolTableProbe(
- masm, rbx, rdi, r9, r11, r14, r15, &make_two_character_string);
- __ IncrementCounter(counters->sub_string_native(), 1);
- __ ret(3 * kPointerSize);
-
- __ bind(&make_two_character_string);
- // Set up registers for allocating the two character string.
- __ movzxwq(rbx, FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize));
- __ AllocateAsciiString(rax, rcx, r11, r14, r15, &runtime);
- __ movw(FieldOperand(rax, SeqAsciiString::kHeaderSize), rbx);
- __ IncrementCounter(counters->sub_string_native(), 1);
- __ ret(3 * kPointerSize);
- __ bind(&result_longer_than_two);
// rax: string
// rbx: instance type
// rcx: sub string length
@@ -5756,14 +5697,8 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ CmpObjectType(rax, JS_OBJECT_TYPE, rcx);
__ j(not_equal, &miss, Label::kNear);
- __ testb(FieldOperand(rcx, Map::kBitField2Offset),
- Immediate(1 << Map::kUseUserObjectComparison));
- __ j(not_zero, &miss, Label::kNear);
__ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
__ j(not_equal, &miss, Label::kNear);
- __ testb(FieldOperand(rcx, Map::kBitField2Offset),
- Immediate(1 << Map::kUseUserObjectComparison));
- __ j(not_zero, &miss, Label::kNear);
ASSERT(GetCondition() == equal);
__ subq(rax, rdx);
@@ -5783,14 +5718,8 @@ void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
__ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
__ Cmp(rcx, known_map_);
__ j(not_equal, &miss, Label::kNear);
- __ testb(FieldOperand(rcx, Map::kBitField2Offset),
- Immediate(1 << Map::kUseUserObjectComparison));
- __ j(not_zero, &miss, Label::kNear);
__ Cmp(rbx, known_map_);
__ j(not_equal, &miss, Label::kNear);
- __ testb(FieldOperand(rbx, Map::kBitField2Offset),
- Immediate(1 << Map::kUseUserObjectComparison));
- __ j(not_zero, &miss, Label::kNear);
__ subq(rax, rdx);
__ ret(0);
diff --git a/src/3rdparty/v8/src/x64/debug-x64.cc b/src/3rdparty/v8/src/x64/debug-x64.cc
index eec83d9..1b29e58 100644
--- a/src/3rdparty/v8/src/x64/debug-x64.cc
+++ b/src/3rdparty/v8/src/x64/debug-x64.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -91,6 +91,8 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() {
rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
}
+const bool Debug::FramePaddingLayout::kIsSupported = true;
+
#define __ ACCESS_MASM(masm)
@@ -103,6 +105,12 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
{
FrameScope scope(masm, StackFrame::INTERNAL);
+ // Load padding words on stack.
+ for (int i = 0; i < Debug::FramePaddingLayout::kInitialSize; i++) {
+ __ Push(Smi::FromInt(Debug::FramePaddingLayout::kPaddingValue));
+ }
+ __ Push(Smi::FromInt(Debug::FramePaddingLayout::kInitialSize));
+
// Store the registers containing live values on the expression stack to
// make sure that these are correctly updated during GC. Non object values
// are stored as as two smis causing it to be untouched by GC.
@@ -157,6 +165,11 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
}
}
+ // Read current padding counter and skip corresponding number of words.
+ __ pop(kScratchRegister);
+ __ SmiToInteger32(kScratchRegister, kScratchRegister);
+ __ lea(rsp, Operand(rsp, kScratchRegister, times_pointer_size, 0));
+
// Get rid of the internal frame.
}
diff --git a/src/3rdparty/v8/src/x64/deoptimizer-x64.cc b/src/3rdparty/v8/src/x64/deoptimizer-x64.cc
index 40b9a1c..f3046b9 100644
--- a/src/3rdparty/v8/src/x64/deoptimizer-x64.cc
+++ b/src/3rdparty/v8/src/x64/deoptimizer-x64.cc
@@ -458,6 +458,8 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
int frame_index) {
+ Builtins* builtins = isolate_->builtins();
+ Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
unsigned height = iterator->Next();
unsigned height_in_bytes = height * kPointerSize;
@@ -465,7 +467,7 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
PrintF(" translating construct stub => height=%d\n", height_in_bytes);
}
- unsigned fixed_frame_size = 6 * kPointerSize;
+ unsigned fixed_frame_size = 7 * kPointerSize;
unsigned output_frame_size = height_in_bytes + fixed_frame_size;
// Allocate and store the output frame description.
@@ -534,6 +536,16 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
top_address + output_offset, output_offset, value);
}
+ // The output frame reflects a JSConstructStubGeneric frame.
+ output_offset -= kPointerSize;
+ value = reinterpret_cast<intptr_t>(construct_stub);
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ V8PRIxPTR " ; code object\n",
+ top_address + output_offset, output_offset, value);
+ }
+
// Number of incoming arguments.
output_offset -= kPointerSize;
value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
@@ -557,8 +569,6 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
ASSERT(0 == output_offset);
- Builtins* builtins = isolate_->builtins();
- Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
intptr_t pc = reinterpret_cast<intptr_t>(
construct_stub->instruction_start() +
isolate_->heap()->construct_stub_deopt_pc_offset()->value());
diff --git a/src/3rdparty/v8/src/x64/full-codegen-x64.cc b/src/3rdparty/v8/src/x64/full-codegen-x64.cc
index a0218f5..974269e 100644
--- a/src/3rdparty/v8/src/x64/full-codegen-x64.cc
+++ b/src/3rdparty/v8/src/x64/full-codegen-x64.cc
@@ -171,13 +171,12 @@ void FullCodeGenerator::Generate() {
// Possibly allocate a local context.
int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
- if (heap_slots > 0 ||
- (scope()->is_qml_mode() && scope()->is_global_scope())) {
+ if (heap_slots > 0) {
Comment cmnt(masm_, "[ Allocate local context");
// Argument to NewContext is the function, which is still in rdi.
__ push(rdi);
if (heap_slots <= FastNewContextStub::kMaximumSlots) {
- FastNewContextStub stub((heap_slots < 0)?0:heap_slots);
+ FastNewContextStub stub(heap_slots);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kNewFunctionContext, 1);
@@ -258,11 +257,11 @@ void FullCodeGenerator::Generate() {
// For named function expressions, declare the function name as a
// constant.
if (scope()->is_function_scope() && scope()->function() != NULL) {
- VariableProxy* proxy = scope()->function();
- ASSERT(proxy->var()->mode() == CONST ||
- proxy->var()->mode() == CONST_HARMONY);
- ASSERT(proxy->var()->location() != Variable::UNALLOCATED);
- EmitDeclaration(proxy, proxy->var()->mode(), NULL);
+ VariableDeclaration* function = scope()->function();
+ ASSERT(function->proxy()->var()->mode() == CONST ||
+ function->proxy()->var()->mode() == CONST_HARMONY);
+ ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED);
+ VisitVariableDeclaration(function);
}
VisitDeclarations(scope()->declarations());
}
@@ -754,61 +753,51 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
}
-void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
- VariableMode mode,
- FunctionLiteral* function) {
+void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
+ // The variable in the declaration always resides in the current function
+ // context.
+ ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
+ if (FLAG_debug_code) {
+ // Check that we're not inside a with or catch context.
+ __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
+ __ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
+ __ Check(not_equal, "Declaration in with context.");
+ __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
+ __ Check(not_equal, "Declaration in catch context.");
+ }
+}
+
+
+void FullCodeGenerator::VisitVariableDeclaration(
+ VariableDeclaration* declaration) {
// If it was not possible to allocate the variable at compile time, we
// need to "declare" it at runtime to make sure it actually exists in the
// local context.
+ VariableProxy* proxy = declaration->proxy();
+ VariableMode mode = declaration->mode();
Variable* variable = proxy->var();
- bool binding_needs_init = (function == NULL) &&
- (mode == CONST || mode == CONST_HARMONY || mode == LET);
+ bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
switch (variable->location()) {
case Variable::UNALLOCATED:
- ++global_count_;
+ globals_->Add(variable->name());
+ globals_->Add(variable->binding_needs_init()
+ ? isolate()->factory()->the_hole_value()
+ : isolate()->factory()->undefined_value());
break;
case Variable::PARAMETER:
case Variable::LOCAL:
- if (function != NULL) {
- Comment cmnt(masm_, "[ Declaration");
- VisitForAccumulatorValue(function);
- __ movq(StackOperand(variable), result_register());
- } else if (binding_needs_init) {
- Comment cmnt(masm_, "[ Declaration");
+ if (hole_init) {
+ Comment cmnt(masm_, "[ VariableDeclaration");
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
__ movq(StackOperand(variable), kScratchRegister);
}
break;
case Variable::CONTEXT:
- // The variable in the decl always resides in the current function
- // context.
- ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
- if (FLAG_debug_code) {
- // Check that we're not inside a with or catch context.
- __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
- __ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
- __ Check(not_equal, "Declaration in with context.");
- __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
- __ Check(not_equal, "Declaration in catch context.");
- }
- if (function != NULL) {
- Comment cmnt(masm_, "[ Declaration");
- VisitForAccumulatorValue(function);
- __ movq(ContextOperand(rsi, variable->index()), result_register());
- int offset = Context::SlotOffset(variable->index());
- // We know that we have written a function, which is not a smi.
- __ RecordWriteContextSlot(rsi,
- offset,
- result_register(),
- rcx,
- kDontSaveFPRegs,
- EMIT_REMEMBERED_SET,
- OMIT_SMI_CHECK);
- PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
- } else if (binding_needs_init) {
- Comment cmnt(masm_, "[ Declaration");
+ if (hole_init) {
+ Comment cmnt(masm_, "[ VariableDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
__ movq(ContextOperand(rsi, variable->index()), kScratchRegister);
// No write barrier since the hole value is in old space.
@@ -817,14 +806,12 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
break;
case Variable::LOOKUP: {
- Comment cmnt(masm_, "[ Declaration");
+ Comment cmnt(masm_, "[ VariableDeclaration");
__ push(rsi);
__ Push(variable->name());
// Declaration nodes are always introduced in one of four modes.
- ASSERT(mode == VAR ||
- mode == CONST ||
- mode == CONST_HARMONY ||
- mode == LET);
+ ASSERT(mode == VAR || mode == LET ||
+ mode == CONST || mode == CONST_HARMONY);
PropertyAttributes attr =
(mode == CONST || mode == CONST_HARMONY) ? READ_ONLY : NONE;
__ Push(Smi::FromInt(attr));
@@ -832,9 +819,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
// Note: For variables we must not push an initial value (such as
// 'undefined') because we may have a (legal) redeclaration and we
// must not destroy the current value.
- if (function != NULL) {
- VisitForStackValue(function);
- } else if (binding_needs_init) {
+ if (hole_init) {
__ PushRoot(Heap::kTheHoleValueRootIndex);
} else {
__ Push(Smi::FromInt(0)); // Indicates no initial value.
@@ -846,6 +831,119 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
}
+void FullCodeGenerator::VisitFunctionDeclaration(
+ FunctionDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED: {
+ globals_->Add(variable->name());
+ Handle<SharedFunctionInfo> function =
+ Compiler::BuildFunctionInfo(declaration->fun(), script());
+ // Check for stack-overflow exception.
+ if (function.is_null()) return SetStackOverflow();
+ globals_->Add(function);
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ VisitForAccumulatorValue(declaration->fun());
+ __ movq(StackOperand(variable), result_register());
+ break;
+ }
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ VisitForAccumulatorValue(declaration->fun());
+ __ movq(ContextOperand(rsi, variable->index()), result_register());
+ int offset = Context::SlotOffset(variable->index());
+ // We know that we have written a function, which is not a smi.
+ __ RecordWriteContextSlot(rsi,
+ offset,
+ result_register(),
+ rcx,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
+ break;
+ }
+
+ case Variable::LOOKUP: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ __ push(rsi);
+ __ Push(variable->name());
+ __ Push(Smi::FromInt(NONE));
+ VisitForStackValue(declaration->fun());
+ __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ break;
+ }
+ }
+}
+
+
+void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ Handle<JSModule> instance = declaration->module()->interface()->Instance();
+ ASSERT(!instance.is_null());
+
+ switch (variable->location()) {
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "[ ModuleDeclaration");
+ globals_->Add(variable->name());
+ globals_->Add(instance);
+ Visit(declaration->module());
+ break;
+ }
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ ModuleDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ __ Move(ContextOperand(rsi, variable->index()), instance);
+ Visit(declaration->module());
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::LOOKUP:
+ UNREACHABLE();
+ }
+}
+
+
+void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ // TODO(rossberg)
+ break;
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ ImportDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ // TODO(rossberg)
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::LOOKUP:
+ UNREACHABLE();
+ }
+}
+
+
+void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
+ // TODO(rossberg)
+}
+
+
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
__ push(rsi); // The context is the first argument.
@@ -1200,7 +1298,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
// All extension objects were empty and it is safe to use a global
// load IC call.
- __ movq(rax, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ __ movq(rax, GlobalObjectOperand());
__ Move(rcx, var->name());
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
@@ -1285,7 +1383,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
// Use inline caching. Variable name is passed in rcx and the global
// object on the stack.
__ Move(rcx, var->name());
- __ movq(rax, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ __ movq(rax, GlobalObjectOperand());
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
context()->Plug(rax);
@@ -1912,7 +2010,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
if (var->IsUnallocated()) {
// Global var, const, or let.
__ Move(rcx, var->name());
- __ movq(rdx, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ __ movq(rdx, GlobalObjectOperand());
Handle<Code> ic = is_classic_mode()
? isolate()->builtins()->StoreIC_Initialize()
: isolate()->builtins()->StoreIC_Initialize_Strict();
@@ -2175,6 +2273,18 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
}
// Record source position for debugger.
SetSourcePosition(expr->position());
+
+ // Record call targets in unoptimized code, but not in the snapshot.
+ if (!Serializer::enabled()) {
+ flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
+ Handle<Object> uninitialized =
+ TypeFeedbackCells::UninitializedSentinel(isolate());
+ Handle<JSGlobalPropertyCell> cell =
+ isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
+ RecordTypeFeedbackCell(expr->id(), cell);
+ __ Move(rbx, cell);
+ }
+
CallFunctionStub stub(arg_count, flags);
__ movq(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
@@ -2203,11 +2313,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
// Push the start position of the scope the calls resides in.
__ Push(Smi::FromInt(scope()->start_position()));
- // Push the qml mode flag
- __ Push(Smi::FromInt(is_qml_mode()));
-
// Do the runtime call.
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
}
@@ -2260,7 +2367,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} else if (proxy != NULL && proxy->var()->IsUnallocated()) {
// Call to a global variable. Push global object as receiver for the
// call IC lookup.
- __ push(proxy->var()->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ __ push(GlobalObjectOperand());
EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
} else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
// Call to a lookup slot (dynamically introduced variable).
@@ -3253,102 +3360,6 @@ void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
}
-void FullCodeGenerator::EmitSwapElements(CallRuntime* expr) {
- ZoneList<Expression*>* args = expr->arguments();
- ASSERT(args->length() == 3);
- VisitForStackValue(args->at(0));
- VisitForStackValue(args->at(1));
- VisitForStackValue(args->at(2));
- Label done;
- Label slow_case;
- Register object = rax;
- Register index_1 = rbx;
- Register index_2 = rcx;
- Register elements = rdi;
- Register temp = rdx;
- __ movq(object, Operand(rsp, 2 * kPointerSize));
- // Fetch the map and check if array is in fast case.
- // Check that object doesn't require security checks and
- // has no indexed interceptor.
- __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
- __ j(not_equal, &slow_case);
- __ testb(FieldOperand(temp, Map::kBitFieldOffset),
- Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
- __ j(not_zero, &slow_case);
-
- // Check the object's elements are in fast case and writable.
- __ movq(elements, FieldOperand(object, JSObject::kElementsOffset));
- __ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
- Heap::kFixedArrayMapRootIndex);
- __ j(not_equal, &slow_case);
-
- // Check that both indices are smis.
- __ movq(index_1, Operand(rsp, 1 * kPointerSize));
- __ movq(index_2, Operand(rsp, 0 * kPointerSize));
- __ JumpIfNotBothSmi(index_1, index_2, &slow_case);
-
- // Check that both indices are valid.
- // The JSArray length field is a smi since the array is in fast case mode.
- __ movq(temp, FieldOperand(object, JSArray::kLengthOffset));
- __ SmiCompare(temp, index_1);
- __ j(below_equal, &slow_case);
- __ SmiCompare(temp, index_2);
- __ j(below_equal, &slow_case);
-
- __ SmiToInteger32(index_1, index_1);
- __ SmiToInteger32(index_2, index_2);
- // Bring addresses into index1 and index2.
- __ lea(index_1, FieldOperand(elements, index_1, times_pointer_size,
- FixedArray::kHeaderSize));
- __ lea(index_2, FieldOperand(elements, index_2, times_pointer_size,
- FixedArray::kHeaderSize));
-
- // Swap elements. Use object and temp as scratch registers.
- __ movq(object, Operand(index_1, 0));
- __ movq(temp, Operand(index_2, 0));
- __ movq(Operand(index_2, 0), object);
- __ movq(Operand(index_1, 0), temp);
-
- Label no_remembered_set;
- __ CheckPageFlag(elements,
- temp,
- 1 << MemoryChunk::SCAN_ON_SCAVENGE,
- not_zero,
- &no_remembered_set,
- Label::kNear);
- // Possible optimization: do a check that both values are Smis
- // (or them and test against Smi mask.)
-
- // We are swapping two objects in an array and the incremental marker never
- // pauses in the middle of scanning a single object. Therefore the
- // incremental marker is not disturbed, so we don't need to call the
- // RecordWrite stub that notifies the incremental marker.
- __ RememberedSetHelper(elements,
- index_1,
- temp,
- kDontSaveFPRegs,
- MacroAssembler::kFallThroughAtEnd);
- __ RememberedSetHelper(elements,
- index_2,
- temp,
- kDontSaveFPRegs,
- MacroAssembler::kFallThroughAtEnd);
-
- __ bind(&no_remembered_set);
-
- // We are done. Drop elements from the stack, and return undefined.
- __ addq(rsp, Immediate(3 * kPointerSize));
- __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
- __ jmp(&done);
-
- __ bind(&slow_case);
- __ CallRuntime(Runtime::kSwapElements, 3);
-
- __ bind(&done);
- context()->Plug(rax);
-}
-
-
void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(2, args->length());
@@ -3830,7 +3841,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
// but "delete this" is allowed.
ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
if (var->IsUnallocated()) {
- __ push(var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ __ push(GlobalObjectOperand());
__ Push(var->name());
__ Push(Smi::FromInt(kNonStrictMode));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
@@ -4152,7 +4163,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
if (proxy != NULL && proxy->var()->IsUnallocated()) {
Comment cmnt(masm_, "Global variable");
__ Move(rcx, proxy->name());
- __ movq(rax, proxy->var()->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ __ movq(rax, GlobalObjectOperand());
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
// Use a regular load, not a contextual load, to avoid a reference
// error.
@@ -4416,7 +4427,8 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
Scope* declaration_scope = scope()->DeclarationScope();
- if (declaration_scope->is_global_scope()) {
+ if (declaration_scope->is_global_scope() ||
+ declaration_scope->is_module_scope()) {
// Contexts nested in the global context have a canonical empty function
// as their closure, not the anonymous closure containing the global
// code. Pass a smi sentinel and let the runtime look up the empty
diff --git a/src/3rdparty/v8/src/x64/ic-x64.cc b/src/3rdparty/v8/src/x64/ic-x64.cc
index 0632ce4..6ba5fb6 100644
--- a/src/3rdparty/v8/src/x64/ic-x64.cc
+++ b/src/3rdparty/v8/src/x64/ic-x64.cc
@@ -1741,11 +1741,11 @@ void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
// Activate inlined smi code.
if (previous_state == UNINITIALIZED) {
- PatchInlinedSmiCode(address());
+ PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
}
}
-void PatchInlinedSmiCode(Address address) {
+void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
// The address of the instruction following the call.
Address test_instruction_address =
address + Assembler::kCallTargetAddressOffset;
@@ -1766,14 +1766,18 @@ void PatchInlinedSmiCode(Address address) {
address, test_instruction_address, delta);
}
- // Patch with a short conditional jump. There must be a
- // short jump-if-carry/not-carry at this position.
+ // Patch with a short conditional jump. Enabling means switching from a short
+ // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the
+ // reverse operation of that.
Address jmp_address = test_instruction_address - delta;
- ASSERT(*jmp_address == Assembler::kJncShortOpcode ||
- *jmp_address == Assembler::kJcShortOpcode);
- Condition cc = *jmp_address == Assembler::kJncShortOpcode
- ? not_zero
- : zero;
+ ASSERT((check == ENABLE_INLINED_SMI_CHECK)
+ ? (*jmp_address == Assembler::kJncShortOpcode ||
+ *jmp_address == Assembler::kJcShortOpcode)
+ : (*jmp_address == Assembler::kJnzShortOpcode ||
+ *jmp_address == Assembler::kJzShortOpcode));
+ Condition cc = (check == ENABLE_INLINED_SMI_CHECK)
+ ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero)
+ : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry);
*jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
}
diff --git a/src/3rdparty/v8/src/x64/lithium-codegen-x64.cc b/src/3rdparty/v8/src/x64/lithium-codegen-x64.cc
index dc15213..d1cf338 100644
--- a/src/3rdparty/v8/src/x64/lithium-codegen-x64.cc
+++ b/src/3rdparty/v8/src/x64/lithium-codegen-x64.cc
@@ -184,13 +184,12 @@ bool LCodeGen::GeneratePrologue() {
// Possibly allocate a local context.
int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
- if (heap_slots > 0 ||
- (scope()->is_qml_mode() && scope()->is_global_scope())) {
+ if (heap_slots > 0) {
Comment(";;; Allocate local context");
// Argument to NewContext is the function, which is still in rdi.
__ push(rdi);
if (heap_slots <= FastNewContextStub::kMaximumSlots) {
- FastNewContextStub stub((heap_slots < 0)?0:heap_slots);
+ FastNewContextStub stub(heap_slots);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kNewFunctionContext, 1);
@@ -2017,8 +2016,7 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
RECORD_SAFEPOINT_WITH_REGISTERS,
2);
ASSERT(delta == masm_->SizeOfCodeGeneratedSince(map_check));
- ASSERT(instr->HasDeoptimizationEnvironment());
- LEnvironment* env = instr->deoptimization_environment();
+ LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
// Move result to a register that survives the end of the
// PushSafepointRegisterScope.
@@ -2225,41 +2223,35 @@ void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
Register result = ToRegister(instr->result());
int map_count = instr->hydrogen()->types()->length();
- Handle<String> name = instr->hydrogen()->name();
+ bool need_generic = instr->hydrogen()->need_generic();
- if (map_count == 0) {
- ASSERT(instr->hydrogen()->need_generic());
- __ Move(rcx, instr->hydrogen()->name());
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- CallCode(ic, RelocInfo::CODE_TARGET, instr);
- } else {
- Label done;
- for (int i = 0; i < map_count - 1; ++i) {
- Handle<Map> map = instr->hydrogen()->types()->at(i);
+ if (map_count == 0 && !need_generic) {
+ DeoptimizeIf(no_condition, instr->environment());
+ return;
+ }
+ Handle<String> name = instr->hydrogen()->name();
+ Label done;
+ for (int i = 0; i < map_count; ++i) {
+ bool last = (i == map_count - 1);
+ Handle<Map> map = instr->hydrogen()->types()->at(i);
+ __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map);
+ if (last && !need_generic) {
+ DeoptimizeIf(not_equal, instr->environment());
+ EmitLoadFieldOrConstantFunction(result, object, map, name);
+ } else {
Label next;
- __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map);
__ j(not_equal, &next, Label::kNear);
EmitLoadFieldOrConstantFunction(result, object, map, name);
__ jmp(&done, Label::kNear);
__ bind(&next);
}
- Handle<Map> map = instr->hydrogen()->types()->last();
- __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map);
- if (instr->hydrogen()->need_generic()) {
- Label generic;
- __ j(not_equal, &generic, Label::kNear);
- EmitLoadFieldOrConstantFunction(result, object, map, name);
- __ jmp(&done, Label::kNear);
- __ bind(&generic);
- __ Move(rcx, instr->hydrogen()->name());
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- CallCode(ic, RelocInfo::CODE_TARGET, instr);
- } else {
- DeoptimizeIf(not_equal, instr->environment());
- EmitLoadFieldOrConstantFunction(result, object, map, name);
- }
- __ bind(&done);
}
+ if (need_generic) {
+ __ Move(rcx, name);
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ }
+ __ bind(&done);
}
@@ -2377,11 +2369,20 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
Register result = ToRegister(instr->result());
+ if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits.
+ Register key_reg = ToRegister(instr->key());
+ __ movsxlq(key_reg, key_reg);
+ }
+
// Load the result.
__ movq(result,
- BuildFastArrayOperand(instr->elements(), instr->key(),
+ BuildFastArrayOperand(instr->elements(),
+ instr->key(),
FAST_ELEMENTS,
- FixedArray::kHeaderSize - kHeapObjectTag));
+ FixedArray::kHeaderSize - kHeapObjectTag,
+ instr->additional_index()));
// Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) {
@@ -2395,19 +2396,30 @@ void LCodeGen::DoLoadKeyedFastDoubleElement(
LLoadKeyedFastDoubleElement* instr) {
XMMRegister result(ToDoubleRegister(instr->result()));
+ if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ Register key_reg = ToRegister(instr->key());
+ __ movsxlq(key_reg, key_reg);
+ }
+
int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
sizeof(kHoleNanLower32);
Operand hole_check_operand = BuildFastArrayOperand(
instr->elements(),
instr->key(),
FAST_DOUBLE_ELEMENTS,
- offset);
+ offset,
+ instr->additional_index());
__ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
DeoptimizeIf(equal, instr->environment());
Operand double_load_operand = BuildFastArrayOperand(
- instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
- FixedDoubleArray::kHeaderSize - kHeapObjectTag);
+ instr->elements(),
+ instr->key(),
+ FAST_DOUBLE_ELEMENTS,
+ FixedDoubleArray::kHeaderSize - kHeapObjectTag,
+ instr->additional_index());
__ movsd(result, double_load_operand);
}
@@ -2416,7 +2428,8 @@ Operand LCodeGen::BuildFastArrayOperand(
LOperand* elements_pointer,
LOperand* key,
ElementsKind elements_kind,
- uint32_t offset) {
+ uint32_t offset,
+ uint32_t additional_index) {
Register elements_pointer_reg = ToRegister(elements_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind);
if (key->IsConstantOperand()) {
@@ -2425,11 +2438,14 @@ Operand LCodeGen::BuildFastArrayOperand(
Abort("array index constant value too big");
}
return Operand(elements_pointer_reg,
- constant_value * (1 << shift_size) + offset);
+ ((constant_value + additional_index) << shift_size)
+ + offset);
} else {
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
- return Operand(elements_pointer_reg, ToRegister(key),
- scale_factor, offset);
+ return Operand(elements_pointer_reg,
+ ToRegister(key),
+ scale_factor,
+ offset + (additional_index << shift_size));
}
}
@@ -2438,7 +2454,17 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
- instr->key(), elements_kind, 0));
+ instr->key(),
+ elements_kind,
+ 0,
+ instr->additional_index()));
+ if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ Register key_reg = ToRegister(instr->key());
+ __ movsxlq(key_reg, key_reg);
+ }
+
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand);
@@ -2498,24 +2524,28 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
Register result = ToRegister(instr->result());
- // Check for arguments adapter frame.
- Label done, adapted;
- __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
- __ Cmp(Operand(result, StandardFrameConstants::kContextOffset),
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
- __ j(equal, &adapted, Label::kNear);
-
- // No arguments adaptor frame.
- __ movq(result, rbp);
- __ jmp(&done, Label::kNear);
+ if (instr->hydrogen()->from_inlined()) {
+ __ lea(result, Operand(rsp, -2 * kPointerSize));
+ } else {
+ // Check for arguments adapter frame.
+ Label done, adapted;
+ __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
+ __ Cmp(Operand(result, StandardFrameConstants::kContextOffset),
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ __ j(equal, &adapted, Label::kNear);
+
+ // No arguments adaptor frame.
+ __ movq(result, rbp);
+ __ jmp(&done, Label::kNear);
- // Arguments adaptor frame present.
- __ bind(&adapted);
- __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
+ // Arguments adaptor frame present.
+ __ bind(&adapted);
+ __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
- // Result is the frame pointer for the frame if not adapted and for the real
- // frame below the adaptor frame if adapted.
- __ bind(&done);
+ // Result is the frame pointer for the frame if not adapted and for the real
+ // frame below the adaptor frame if adapted.
+ __ bind(&done);
+ }
}
@@ -2623,7 +2653,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
// Invoke the function.
__ bind(&invoke);
- ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ ASSERT(instr->HasPointerMap());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator safepoint_generator(
@@ -2641,6 +2671,11 @@ void LCodeGen::DoPushArgument(LPushArgument* instr) {
}
+void LCodeGen::DoDrop(LDrop* instr) {
+ __ Drop(instr->count());
+}
+
+
void LCodeGen::DoThisFunction(LThisFunction* instr) {
Register result = ToRegister(instr->result());
__ LoadHeapObject(result, instr->hydrogen()->closure());
@@ -2671,7 +2706,7 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
Register result = ToRegister(instr->result());
- __ movq(result, instr->qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ movq(result, GlobalObjectOperand());
}
@@ -2685,7 +2720,8 @@ void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
- CallKind call_kind) {
+ CallKind call_kind,
+ RDIState rdi_state) {
bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
function->shared()->formal_parameter_count() == arity;
@@ -2693,7 +2729,9 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
RecordPosition(pointers->position());
if (can_invoke_directly) {
- __ LoadHeapObject(rdi, function);
+ if (rdi_state == RDI_UNINITIALIZED) {
+ __ LoadHeapObject(rdi, function);
+ }
// Change context if needed.
bool change_context =
@@ -2738,7 +2776,8 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
CallKnownFunction(instr->function(),
instr->arity(),
instr,
- CALL_AS_METHOD);
+ CALL_AS_METHOD,
+ RDI_UNINITIALIZED);
}
@@ -3175,13 +3214,21 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(ToRegister(instr->function()).is(rdi));
ASSERT(instr->HasPointerMap());
- ASSERT(instr->HasDeoptimizationEnvironment());
- LPointerMap* pointers = instr->pointer_map();
- RecordPosition(pointers->position());
- SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
- ParameterCount count(instr->arity());
- __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
- __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+
+ if (instr->known_function().is_null()) {
+ LPointerMap* pointers = instr->pointer_map();
+ RecordPosition(pointers->position());
+ SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+ ParameterCount count(instr->arity());
+ __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
+ __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+ } else {
+ CallKnownFunction(instr->known_function(),
+ instr->arity(),
+ instr,
+ CALL_AS_METHOD,
+ RDI_CONTAINS_TARGET);
+ }
}
@@ -3235,7 +3282,11 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(rax));
- CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
+ CallKnownFunction(instr->target(),
+ instr->arity(),
+ instr,
+ CALL_AS_FUNCTION,
+ RDI_UNINITIALIZED);
}
@@ -3315,7 +3366,18 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
- instr->key(), elements_kind, 0));
+ instr->key(),
+ elements_kind,
+ 0,
+ instr->additional_index()));
+
+ if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ Register key_reg = ToRegister(instr->key());
+ __ movsxlq(key_reg, key_reg);
+ }
+
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister value(ToDoubleRegister(instr->value()));
__ cvtsd2ss(value, value);
@@ -3385,30 +3447,29 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
Register elements = ToRegister(instr->object());
Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
- // Do the store.
- if (instr->key()->IsConstantOperand()) {
- ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
- LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
- int offset =
- ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
- __ movq(FieldOperand(elements, offset), value);
- } else {
- __ movq(FieldOperand(elements,
- key,
- times_pointer_size,
- FixedArray::kHeaderSize),
- value);
+ Operand operand =
+ BuildFastArrayOperand(instr->object(),
+ instr->key(),
+ FAST_ELEMENTS,
+ FixedArray::kHeaderSize - kHeapObjectTag,
+ instr->additional_index());
+
+ if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ Register key_reg = ToRegister(instr->key());
+ __ movsxlq(key_reg, key_reg);
}
+ __ movq(operand, value);
+
if (instr->hydrogen()->NeedsWriteBarrier()) {
+ ASSERT(!instr->key()->IsConstantOperand());
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register.
- __ lea(key, FieldOperand(elements,
- key,
- times_pointer_size,
- FixedArray::kHeaderSize));
+ __ lea(key, operand);
__ RecordWrite(elements,
key,
value,
@@ -3422,19 +3483,34 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
void LCodeGen::DoStoreKeyedFastDoubleElement(
LStoreKeyedFastDoubleElement* instr) {
XMMRegister value = ToDoubleRegister(instr->value());
- Label have_value;
- __ ucomisd(value, value);
- __ j(parity_odd, &have_value); // NaN.
+ if (instr->NeedsCanonicalization()) {
+ Label have_value;
+
+ __ ucomisd(value, value);
+ __ j(parity_odd, &have_value); // NaN.
- __ Set(kScratchRegister, BitCast<uint64_t>(
- FixedDoubleArray::canonical_not_the_hole_nan_as_double()));
- __ movq(value, kScratchRegister);
+ __ Set(kScratchRegister, BitCast<uint64_t>(
+ FixedDoubleArray::canonical_not_the_hole_nan_as_double()));
+ __ movq(value, kScratchRegister);
+
+ __ bind(&have_value);
+ }
- __ bind(&have_value);
Operand double_store_operand = BuildFastArrayOperand(
- instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
- FixedDoubleArray::kHeaderSize - kHeapObjectTag);
+ instr->elements(),
+ instr->key(),
+ FAST_DOUBLE_ELEMENTS,
+ FixedDoubleArray::kHeaderSize - kHeapObjectTag,
+ instr->additional_index());
+
+ if (instr->hydrogen()->IsDehoisted() && !instr->key()->IsConstantOperand()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ Register key_reg = ToRegister(instr->key());
+ __ movsxlq(key_reg, key_reg);
+ }
+
__ movsd(double_store_operand, value);
}
@@ -4268,9 +4344,10 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
__ movq(FieldOperand(result, total_offset), rcx);
}
} else if (elements->IsFixedArray()) {
+ Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
for (int i = 0; i < elements_length; i++) {
int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
- Handle<Object> value = JSObject::GetElement(object, i);
+ Handle<Object> value(fast_elements->get(i));
if (value->IsJSObject()) {
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
__ lea(rcx, Operand(result, *offset));
@@ -4294,6 +4371,23 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
int size = instr->hydrogen()->total_size();
+ ElementsKind boilerplate_elements_kind =
+ instr->hydrogen()->boilerplate()->GetElementsKind();
+
+ // Deopt if the literal boilerplate ElementsKind is of a type different than
+ // the expected one. The check isn't necessary if the boilerplate has already
+ // been converted to FAST_ELEMENTS.
+ if (boilerplate_elements_kind != FAST_ELEMENTS) {
+ __ LoadHeapObject(rbx, instr->hydrogen()->boilerplate());
+ __ movq(rcx, FieldOperand(rbx, HeapObject::kMapOffset));
+ // Load the map's "bit field 2".
+ __ movb(rcx, FieldOperand(rcx, Map::kBitField2Offset));
+ // Retrieve elements_kind from bit field 2.
+ __ and_(rcx, Immediate(Map::kElementsKindMask));
+ __ cmpb(rcx, Immediate(boilerplate_elements_kind <<
+ Map::kElementsKindShift));
+ DeoptimizeIf(not_equal, instr->environment());
+ }
// Allocate all objects that are part of the literal in one big
// allocation. This avoids multiple limit checks.
@@ -4592,7 +4686,7 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
LOperand* key = instr->key();
EmitPushTaggedOperand(obj);
EmitPushTaggedOperand(key);
- ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ ASSERT(instr->HasPointerMap());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
// Create safepoint generator that will also ensure enough space in the
@@ -4610,7 +4704,7 @@ void LCodeGen::DoIn(LIn* instr) {
LOperand* key = instr->key();
EmitPushTaggedOperand(key);
EmitPushTaggedOperand(obj);
- ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ ASSERT(instr->HasPointerMap());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator safepoint_generator(
diff --git a/src/3rdparty/v8/src/x64/lithium-codegen-x64.h b/src/3rdparty/v8/src/x64/lithium-codegen-x64.h
index f5045b6..73e1a9b 100644
--- a/src/3rdparty/v8/src/x64/lithium-codegen-x64.h
+++ b/src/3rdparty/v8/src/x64/lithium-codegen-x64.h
@@ -196,12 +196,18 @@ class LCodeGen BASE_EMBEDDED {
int argc,
LInstruction* instr);
+ enum RDIState {
+ RDI_UNINITIALIZED,
+ RDI_CONTAINS_TARGET
+ };
+
// Generate a direct call to a known function. Expects the function
// to be in rdi.
void CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
- CallKind call_kind);
+ CallKind call_kind,
+ RDIState rdi_state);
void RecordSafepointWithLazyDeopt(LInstruction* instr,
@@ -225,7 +231,8 @@ class LCodeGen BASE_EMBEDDED {
LOperand* elements_pointer,
LOperand* key,
ElementsKind elements_kind,
- uint32_t offset);
+ uint32_t offset,
+ uint32_t additional_index = 0);
// Specific math operations - used from DoUnaryMathOperation.
void EmitIntegerMathAbs(LUnaryMathOperation* instr);
diff --git a/src/3rdparty/v8/src/x64/lithium-x64.cc b/src/3rdparty/v8/src/x64/lithium-x64.cc
index 95c3a8e..3ba0cae 100644
--- a/src/3rdparty/v8/src/x64/lithium-x64.cc
+++ b/src/3rdparty/v8/src/x64/lithium-x64.cc
@@ -110,22 +110,17 @@ void LInstruction::PrintTo(StringStream* stream) {
}
-template<int R, int I, int T>
-void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) {
+void LInstruction::PrintDataTo(StringStream* stream) {
stream->Add("= ");
- for (int i = 0; i < inputs_.length(); i++) {
+ for (int i = 0; i < InputCount(); i++) {
if (i > 0) stream->Add(" ");
- inputs_[i]->PrintTo(stream);
+ InputAt(i)->PrintTo(stream);
}
}
-template<int R, int I, int T>
-void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) {
- for (int i = 0; i < results_.length(); i++) {
- if (i > 0) stream->Add(" ");
- results_[i]->PrintTo(stream);
- }
+void LInstruction::PrintOutputOperandTo(StringStream* stream) {
+ if (HasResult()) result()->PrintTo(stream);
}
@@ -727,22 +722,6 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
}
-LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
- LInstruction* instr, int ast_id) {
- ASSERT(instruction_pending_deoptimization_environment_ == NULL);
- ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
- instruction_pending_deoptimization_environment_ = instr;
- pending_deoptimization_ast_id_ = ast_id;
- return instr;
-}
-
-
-void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
- instruction_pending_deoptimization_environment_ = NULL;
- pending_deoptimization_ast_id_ = AstNode::kNoNumber;
-}
-
-
LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
HInstruction* hinstr,
CanDeoptimize can_deoptimize) {
@@ -755,8 +734,10 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
if (hinstr->HasObservableSideEffects()) {
ASSERT(hinstr->next()->IsSimulate());
HSimulate* sim = HSimulate::cast(hinstr->next());
- instr = SetInstructionPendingDeoptimizationEnvironment(
- instr, sim->ast_id());
+ ASSERT(instruction_pending_deoptimization_environment_ == NULL);
+ ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
+ instruction_pending_deoptimization_environment_ = instr;
+ pending_deoptimization_ast_id_ = sim->ast_id();
}
// If instruction does not have side-effects lazy deoptimization
@@ -774,12 +755,6 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
}
-LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
- instr->MarkAsSaveDoubles();
- return instr;
-}
-
-
LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
ASSERT(!instr->HasPointerMap());
instr->set_pointer_map(new(zone()) LPointerMap(position_));
@@ -1144,7 +1119,7 @@ LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
- return DefineAsRegister(new(zone()) LGlobalObject(instr->qml_global()));
+ return DefineAsRegister(new(zone()) LGlobalObject);
}
@@ -1214,7 +1189,7 @@ LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
argument_count_ -= instr->argument_count();
- return MarkAsCall(DefineFixed(new(zone()) LCallGlobal(instr->qml_global()), rax), instr);
+ return MarkAsCall(DefineFixed(new(zone()) LCallGlobal, rax), instr);
}
@@ -1285,6 +1260,7 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
ASSERT(instr->value()->representation().IsInteger32());
ASSERT(instr->representation().IsInteger32());
+ if (instr->HasNoUses()) return NULL;
LOperand* input = UseRegisterAtStart(instr->value());
LBitNotI* result = new(zone()) LBitNotI(input);
return DefineSameAsFirst(result);
@@ -1309,6 +1285,12 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
}
+LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
if (instr->representation().IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
@@ -2241,9 +2223,12 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
if (pending_deoptimization_ast_id_ == instr->ast_id()) {
LLazyBailout* lazy_bailout = new(zone()) LLazyBailout;
LInstruction* result = AssignEnvironment(lazy_bailout);
+ // Store the lazy deopt environment with the instruction if needed. Right
+ // now it is only used for LInstanceOfKnownGlobal.
instruction_pending_deoptimization_environment_->
- set_deoptimization_environment(result->environment());
- ClearInstructionPendingDeoptimizationEnvironment();
+ SetDeferredLazyDeoptimizationEnvironment(result->environment());
+ instruction_pending_deoptimization_environment_ = NULL;
+ pending_deoptimization_ast_id_ = AstNode::kNoNumber;
return result;
}
@@ -2270,8 +2255,8 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
undefined,
instr->call_kind(),
instr->is_construct());
- if (instr->arguments() != NULL) {
- inner->Bind(instr->arguments(), graph()->GetArgumentsObject());
+ if (instr->arguments_var() != NULL) {
+ inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
}
current_block_->UpdateEnvironment(inner);
chunk_->AddInlinedClosure(instr->closure());
@@ -2280,10 +2265,21 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
+ LInstruction* pop = NULL;
+
+ HEnvironment* env = current_block_->last_environment();
+
+ if (instr->arguments_pushed()) {
+ int argument_count = env->arguments_environment()->parameter_count();
+ pop = new(zone()) LDrop(argument_count);
+ argument_count_ -= argument_count;
+ }
+
HEnvironment* outer = current_block_->last_environment()->
DiscardInlined(false);
current_block_->UpdateEnvironment(outer);
- return NULL;
+
+ return pop;
}
diff --git a/src/3rdparty/v8/src/x64/lithium-x64.h b/src/3rdparty/v8/src/x64/lithium-x64.h
index 390eb49..642a0a0 100644
--- a/src/3rdparty/v8/src/x64/lithium-x64.h
+++ b/src/3rdparty/v8/src/x64/lithium-x64.h
@@ -179,7 +179,8 @@ class LCodeGen;
V(CheckMapValue) \
V(LoadFieldByIndex) \
V(DateField) \
- V(WrapReceiver)
+ V(WrapReceiver) \
+ V(Drop)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
@@ -203,16 +204,15 @@ class LInstruction: public ZoneObject {
LInstruction()
: environment_(NULL),
hydrogen_value_(NULL),
- is_call_(false),
- is_save_doubles_(false) { }
+ is_call_(false) { }
virtual ~LInstruction() { }
virtual void CompileToNative(LCodeGen* generator) = 0;
virtual const char* Mnemonic() const = 0;
virtual void PrintTo(StringStream* stream);
- virtual void PrintDataTo(StringStream* stream) = 0;
- virtual void PrintOutputOperandTo(StringStream* stream) = 0;
+ virtual void PrintDataTo(StringStream* stream);
+ virtual void PrintOutputOperandTo(StringStream* stream);
enum Opcode {
// Declare a unique enum value for each instruction.
@@ -247,22 +247,12 @@ class LInstruction: public ZoneObject {
void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; }
HValue* hydrogen_value() const { return hydrogen_value_; }
- void set_deoptimization_environment(LEnvironment* env) {
- deoptimization_environment_.set(env);
- }
- LEnvironment* deoptimization_environment() const {
- return deoptimization_environment_.get();
- }
- bool HasDeoptimizationEnvironment() const {
- return deoptimization_environment_.is_set();
- }
-
void MarkAsCall() { is_call_ = true; }
- void MarkAsSaveDoubles() { is_save_doubles_ = true; }
+
+ virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { }
// Interface to the register allocator and iterators.
bool IsMarkedAsCall() const { return is_call_; }
- bool IsMarkedAsSaveDoubles() const { return is_save_doubles_; }
virtual bool HasResult() const = 0;
virtual LOperand* result() = 0;
@@ -283,9 +273,7 @@ class LInstruction: public ZoneObject {
LEnvironment* environment_;
SetOncePointer<LPointerMap> pointer_map_;
HValue* hydrogen_value_;
- SetOncePointer<LEnvironment> deoptimization_environment_;
bool is_call_;
- bool is_save_doubles_;
};
@@ -307,9 +295,6 @@ class LTemplateInstruction: public LInstruction {
int TempCount() { return T; }
LOperand* TempAt(int i) { return temps_[i]; }
- virtual void PrintDataTo(StringStream* stream);
- virtual void PrintOutputOperandTo(StringStream* stream);
-
protected:
EmbeddedContainer<LOperand*, R> results_;
EmbeddedContainer<LOperand*, I> inputs_;
@@ -535,9 +520,8 @@ class LArgumentsLength: public LTemplateInstruction<1, 1, 0> {
class LArgumentsElements: public LTemplateInstruction<1, 0, 0> {
public:
- LArgumentsElements() { }
-
DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements")
+ DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements)
};
@@ -831,6 +815,15 @@ class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> {
DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal)
Handle<JSFunction> function() const { return hydrogen()->function(); }
+ LEnvironment* GetDeferredLazyDeoptimizationEnvironment() {
+ return lazy_deopt_env_;
+ }
+ virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) {
+ lazy_deopt_env_ = env;
+ }
+
+ private:
+ LEnvironment* lazy_deopt_env_;
};
@@ -1206,6 +1199,7 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -1222,13 +1216,13 @@ class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
- LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
- LOperand* key) {
+ LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) {
inputs_[0] = external_pointer;
inputs_[1] = key;
}
@@ -1242,6 +1236,7 @@ class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -1358,6 +1353,19 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> {
};
+class LDrop: public LTemplateInstruction<0, 0, 0> {
+ public:
+ explicit LDrop(int count) : count_(count) { }
+
+ int count() const { return count_; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Drop, "drop")
+
+ private:
+ int count_;
+};
+
+
class LThisFunction: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function")
@@ -1392,13 +1400,7 @@ class LDeclareGlobals: public LTemplateInstruction<0, 0, 0> {
class LGlobalObject: public LTemplateInstruction<1, 0, 0> {
public:
- explicit LGlobalObject(bool qml_global) : qml_global_(qml_global) {}
-
DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object")
-
- bool qml_global() { return qml_global_; }
- private:
- bool qml_global_;
};
@@ -1440,6 +1442,7 @@ class LInvokeFunction: public LTemplateInstruction<1, 1, 0> {
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
+ Handle<JSFunction> known_function() { return hydrogen()->known_function(); }
};
@@ -1491,16 +1494,10 @@ class LCallGlobal: public LTemplateInstruction<1, 0, 0> {
DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call-global")
DECLARE_HYDROGEN_ACCESSOR(CallGlobal)
- explicit LCallGlobal(bool qml_global) : qml_global_(qml_global) {}
-
virtual void PrintDataTo(StringStream* stream);
Handle<String> name() const {return hydrogen()->name(); }
int arity() const { return hydrogen()->argument_count() - 1; }
-
- bool qml_global() { return qml_global_; }
- private:
- bool qml_global_;
};
@@ -1697,6 +1694,7 @@ class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
LOperand* object() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -1719,6 +1717,9 @@ class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
+
+ bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -1742,6 +1743,7 @@ class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
+ uint32_t additional_index() const { return hydrogen()->index_offset(); }
};
@@ -2347,11 +2349,6 @@ class LChunkBuilder BASE_EMBEDDED {
LInstruction* instr,
HInstruction* hinstr,
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
- LInstruction* MarkAsSaveDoubles(LInstruction* instr);
-
- LInstruction* SetInstructionPendingDeoptimizationEnvironment(
- LInstruction* instr, int ast_id);
- void ClearInstructionPendingDeoptimizationEnvironment();
LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
int* argument_index_accumulator);
diff --git a/src/3rdparty/v8/src/x64/macro-assembler-x64.cc b/src/3rdparty/v8/src/x64/macro-assembler-x64.cc
index 12e653c..3d380a2 100644
--- a/src/3rdparty/v8/src/x64/macro-assembler-x64.cc
+++ b/src/3rdparty/v8/src/x64/macro-assembler-x64.cc
@@ -150,6 +150,20 @@ int MacroAssembler::LoadAddressSize(ExternalReference source) {
}
+void MacroAssembler::PushAddress(ExternalReference source) {
+ int64_t address = reinterpret_cast<int64_t>(source.address());
+ if (is_int32(address) && !Serializer::enabled()) {
+ if (emit_debug_code()) {
+ movq(kScratchRegister, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
+ }
+ push(Immediate(static_cast<int32_t>(address)));
+ return;
+ }
+ LoadAddress(kScratchRegister, source);
+ push(kScratchRegister);
+}
+
+
void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) {
ASSERT(root_array_available_);
movq(destination, Operand(kRootRegister,
@@ -4174,7 +4188,7 @@ bool AreAliased(Register r1, Register r2, Register r3, Register r4) {
CodePatcher::CodePatcher(byte* address, int size)
: address_(address),
size_(size),
- masm_(Isolate::Current(), address, size + Assembler::kGap) {
+ masm_(NULL, address, size + Assembler::kGap) {
// Create a new macro assembler pointing to the address of the code to patch.
// The size is adjusted with kGap on order for the assembler to generate size
// bytes of instructions without failing with buffer size constraints.
diff --git a/src/3rdparty/v8/src/x64/macro-assembler-x64.h b/src/3rdparty/v8/src/x64/macro-assembler-x64.h
index f7b36c5..66587d5 100644
--- a/src/3rdparty/v8/src/x64/macro-assembler-x64.h
+++ b/src/3rdparty/v8/src/x64/macro-assembler-x64.h
@@ -127,6 +127,8 @@ class MacroAssembler: public Assembler {
// Returns the size of the code generated by LoadAddress.
// Used by CallSize(ExternalReference) to find the size of a call.
int LoadAddressSize(ExternalReference source);
+ // Pushes the address of the external reference onto the stack.
+ void PushAddress(ExternalReference source);
// Operations on roots in the root-array.
void LoadRoot(Register destination, Heap::RootListIndex index);
@@ -1443,11 +1445,6 @@ inline Operand GlobalObjectOperand() {
}
-static inline Operand QmlGlobalObjectOperand() {
- return ContextOperand(rsi, Context::QML_GLOBAL_INDEX);
-}
-
-
// Provides access to exit frame stack space (not GCed).
inline Operand StackSpaceOperand(int index) {
#ifdef _WIN64
diff --git a/src/3rdparty/v8/src/x64/stub-cache-x64.cc b/src/3rdparty/v8/src/x64/stub-cache-x64.cc
index 9dfcf7a..5721e9b 100644
--- a/src/3rdparty/v8/src/x64/stub-cache-x64.cc
+++ b/src/3rdparty/v8/src/x64/stub-cache-x64.cc
@@ -379,6 +379,7 @@ static void PushInterceptorArguments(MacroAssembler* masm,
__ push(receiver);
__ push(holder);
__ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset));
+ __ PushAddress(ExternalReference::isolate_address());
}
@@ -393,7 +394,7 @@ static void CompileCallLoadPropertyWithInterceptor(
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
masm->isolate());
- __ Set(rax, 5);
+ __ Set(rax, 6);
__ LoadAddress(rbx, ref);
CEntryStub stub(1);
@@ -402,7 +403,7 @@ static void CompileCallLoadPropertyWithInterceptor(
// Number of pointers to be reserved on stack for fast API call.
-static const int kFastApiCallArguments = 3;
+static const int kFastApiCallArguments = 4;
// Reserves space for the extra arguments to API function in the
@@ -452,10 +453,11 @@ static void GenerateFastApiCall(MacroAssembler* masm,
// -- rsp[16] : api function
// (first fast api call extra argument)
// -- rsp[24] : api call data
- // -- rsp[32] : last argument
+ // -- rsp[32] : isolate
+ // -- rsp[40] : last argument
// -- ...
- // -- rsp[(argc + 3) * 8] : first argument
- // -- rsp[(argc + 4) * 8] : receiver
+ // -- rsp[(argc + 4) * 8] : first argument
+ // -- rsp[(argc + 5) * 8] : receiver
// -----------------------------------
// Get the function and setup the context.
Handle<JSFunction> function = optimization.constant_function();
@@ -473,9 +475,11 @@ static void GenerateFastApiCall(MacroAssembler* masm,
} else {
__ Move(Operand(rsp, 3 * kPointerSize), call_data);
}
+ __ movq(kScratchRegister, ExternalReference::isolate_address());
+ __ movq(Operand(rsp, 4 * kPointerSize), kScratchRegister);
// Prepare arguments.
- __ lea(rbx, Operand(rsp, 3 * kPointerSize));
+ __ lea(rbx, Operand(rsp, 4 * kPointerSize));
#if defined(__MINGW64__)
Register arguments_arg = rcx;
@@ -665,7 +669,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
__ CallExternalReference(
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
masm->isolate()),
- 5);
+ 6);
// Restore the name_ register.
__ pop(name_);
@@ -732,8 +736,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
Register scratch,
Label* miss_label) {
// Check that the map of the object hasn't changed.
+ CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
+ : REQUIRE_EXACT_MAP;
__ CheckMap(receiver_reg, Handle<Map>(object->map()),
- miss_label, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ miss_label, DO_SMI_CHECK, mode);
// Perform global security token check if needed.
if (object->IsJSGlobalProxy()) {
@@ -1005,6 +1011,7 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
} else {
__ Push(Handle<Object>(callback->data()));
}
+ __ PushAddress(ExternalReference::isolate_address()); // isolate
__ push(name_reg); // name
// Save a pointer to where we pushed the arguments pointer.
// This will be passed as the const AccessorInfo& to the C++ callback.
@@ -1025,14 +1032,14 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
__ movq(name_arg, rsp);
__ push(scratch2); // Restore return address.
- // 3 elements array for v8::Arguments::values_ and handler for name.
- const int kStackSpace = 4;
+ // 4 elements array for v8::Arguments::values_ and handler for name.
+ const int kStackSpace = 5;
// Allocate v8::AccessorInfo in non-GCed stack space.
const int kArgStackSpace = 1;
__ PrepareCallApiFunction(kArgStackSpace);
- __ lea(rax, Operand(name_arg, 3 * kPointerSize));
+ __ lea(rax, Operand(name_arg, 4 * kPointerSize));
// v8::AccessorInfo::args_.
__ movq(StackSpaceOperand(0), rax);
@@ -1107,13 +1114,20 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
name, miss);
ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
+ // Preserve the receiver register explicitly whenever it is different from
+ // the holder and it is needed should the interceptor return without any
+ // result. The CALLBACKS case needs the receiver to be passed into C++ code,
+ // the FIELD case might cause a miss during the prototype check.
+ bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
+ bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
+ (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
+
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
{
FrameScope frame_scope(masm(), StackFrame::INTERNAL);
- if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
- // CALLBACKS case needs a receiver to be passed into C++ callback.
+ if (must_preserve_receiver_reg) {
__ push(receiver);
}
__ push(holder_reg);
@@ -1139,7 +1153,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
__ bind(&interceptor_failed);
__ pop(name_reg);
__ pop(holder_reg);
- if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
+ if (must_preserve_receiver_reg) {
__ pop(receiver);
}
@@ -1148,7 +1162,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
// Check that the maps from interceptor's holder to lookup's holder
// haven't changed. And load lookup's holder into |holder| register.
- if (*interceptor_holder != lookup->holder()) {
+ if (must_perfrom_prototype_check) {
holder_reg = CheckPrototypes(interceptor_holder,
holder_reg,
Handle<JSObject>(lookup->holder()),
@@ -1182,6 +1196,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
__ push(holder_reg);
__ Move(holder_reg, callback);
__ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
+ __ PushAddress(ExternalReference::isolate_address());
__ push(holder_reg);
__ push(name_reg);
__ push(scratch2); // restore return address
@@ -1189,7 +1204,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
isolate());
- __ TailCallExternalReference(ref, 5, 1);
+ __ TailCallExternalReference(ref, 6, 1);
}
} else { // !compile_followup_inline
// Call the runtime system to load the interceptor.
@@ -1204,7 +1219,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
ExternalReference ref = ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
- __ TailCallExternalReference(ref, 5, 1);
+ __ TailCallExternalReference(ref, 6, 1);
}
}
@@ -1996,7 +2011,7 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
name, depth, &miss);
// Move the return address on top of the stack.
- __ movq(rax, Operand(rsp, 3 * kPointerSize));
+ __ movq(rax, Operand(rsp, 4 * kPointerSize));
__ movq(Operand(rsp, 0 * kPointerSize), rax);
GenerateFastApiCall(masm(), optimization, argc);
@@ -3117,6 +3132,32 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
__ jmp(miss_ic, RelocInfo::CODE_TARGET);
}
+
+static void GenerateSmiKeyCheck(MacroAssembler* masm,
+ Register key,
+ Register scratch,
+ XMMRegister xmm_scratch0,
+ XMMRegister xmm_scratch1,
+ Label* fail) {
+ // Check that key is a smi or a heap number containing a smi and branch
+ // if the check fails.
+ Label key_ok;
+ __ JumpIfSmi(key, &key_ok);
+ __ CheckMap(key,
+ masm->isolate()->factory()->heap_number_map(),
+ fail,
+ DONT_DO_SMI_CHECK);
+ __ movsd(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset));
+ __ cvttsd2si(scratch, xmm_scratch0);
+ __ cvtlsi2sd(xmm_scratch1, scratch);
+ __ ucomisd(xmm_scratch1, xmm_scratch0);
+ __ j(not_equal, fail);
+ __ j(parity_even, fail); // NaN.
+ __ Integer32ToSmi(key, scratch);
+ __ bind(&key_ok);
+}
+
+
void KeyedLoadStubCompiler::GenerateLoadExternalArray(
MacroAssembler* masm,
ElementsKind elements_kind) {
@@ -3130,8 +3171,8 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(rax, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, rax, rcx, xmm0, xmm1, &miss_force_generic);
// Check that the index is in range.
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
@@ -3265,8 +3306,8 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(rcx, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic);
// Check that the index is in range.
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
@@ -3367,30 +3408,28 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
} else {
// Perform float-to-int conversion with truncation (round-to-zero)
// behavior.
+ // Fast path: use machine instruction to convert to int64. If that
+ // fails (out-of-range), go into the runtime.
+ __ cvttsd2siq(r8, xmm0);
+ __ Set(kScratchRegister, V8_UINT64_C(0x8000000000000000));
+ __ cmpq(r8, kScratchRegister);
+ __ j(equal, &slow);
- // Convert to int32 and store the low byte/word.
- // If the value is NaN or +/-infinity, the result is 0x80000000,
- // which is automatically zero when taken mod 2^n, n < 32.
// rdx: value (converted to an untagged integer)
// rdi: untagged index
// rbx: base pointer of external storage
switch (elements_kind) {
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- __ cvttsd2si(rdx, xmm0);
- __ movb(Operand(rbx, rdi, times_1, 0), rdx);
+ __ movb(Operand(rbx, rdi, times_1, 0), r8);
break;
case EXTERNAL_SHORT_ELEMENTS:
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- __ cvttsd2si(rdx, xmm0);
- __ movw(Operand(rbx, rdi, times_2, 0), rdx);
+ __ movw(Operand(rbx, rdi, times_2, 0), r8);
break;
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- // Convert to int64, so that NaN and infinities become
- // 0x8000000000000000, which is zero mod 2^32.
- __ cvttsd2siq(rdx, xmm0);
- __ movl(Operand(rbx, rdi, times_4, 0), rdx);
+ __ movl(Operand(rbx, rdi, times_4, 0), r8);
break;
case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
@@ -3447,8 +3486,8 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(rax, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, rax, rcx, xmm0, xmm1, &miss_force_generic);
// Get the elements array.
__ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
@@ -3489,8 +3528,8 @@ void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(rax, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, rax, rcx, xmm0, xmm1, &miss_force_generic);
// Get the elements array.
__ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
@@ -3545,8 +3584,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(rcx, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic);
if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
__ JumpIfNotSmi(rax, &transition_elements_kind);
@@ -3687,8 +3726,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
- // Check that the key is a smi.
- __ JumpIfNotSmi(rcx, &miss_force_generic);
+ // Check that the key is a smi or a heap number convertible to a smi.
+ GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic);
// Get the elements array.
__ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
@@ -3770,6 +3809,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
// Increment the length of the array.
__ Move(FieldOperand(rdx, JSArray::kLengthOffset), Smi::FromInt(1));
+ __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
__ jmp(&finish_store);
__ bind(&check_capacity);
diff --git a/src/3rdparty/v8/test/cctest/test-accessors.cc b/src/3rdparty/v8/test/cctest/test-accessors.cc
index b1900f9..0b342ff 100644
--- a/src/3rdparty/v8/test/cctest/test-accessors.cc
+++ b/src/3rdparty/v8/test/cctest/test-accessors.cc
@@ -1,4 +1,4 @@
-// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -116,6 +116,8 @@ static v8::Handle<v8::Object> x_holder;
static v8::Handle<Value> XGetter(Local<String> name, const AccessorInfo& info) {
ApiTestFuzzer::Fuzz();
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ CHECK_EQ(isolate, info.GetIsolate());
CHECK_EQ(x_receiver, info.This());
CHECK_EQ(x_holder, info.Holder());
return v8_num(x_register);
@@ -125,6 +127,8 @@ static v8::Handle<Value> XGetter(Local<String> name, const AccessorInfo& info) {
static void XSetter(Local<String> name,
Local<Value> value,
const AccessorInfo& info) {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ CHECK_EQ(isolate, info.GetIsolate());
CHECK_EQ(x_holder, info.This());
CHECK_EQ(x_holder, info.Holder());
x_register = value->Int32Value();
@@ -236,12 +240,15 @@ THREADED_TEST(HandleScopePop) {
static v8::Handle<Value> CheckAccessorArgsCorrect(Local<String> name,
const AccessorInfo& info) {
+ CHECK(info.GetIsolate() == v8::Isolate::GetCurrent());
CHECK(info.This() == info.Holder());
CHECK(info.Data()->Equals(v8::String::New("data")));
ApiTestFuzzer::Fuzz();
+ CHECK(info.GetIsolate() == v8::Isolate::GetCurrent());
CHECK(info.This() == info.Holder());
CHECK(info.Data()->Equals(v8::String::New("data")));
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CHECK(info.GetIsolate() == v8::Isolate::GetCurrent());
CHECK(info.This() == info.Holder());
CHECK(info.Data()->Equals(v8::String::New("data")));
return v8::Integer::New(17);
diff --git a/src/3rdparty/v8/test/cctest/test-alloc.cc b/src/3rdparty/v8/test/cctest/test-alloc.cc
index 769fe7b..e195d14 100644
--- a/src/3rdparty/v8/test/cctest/test-alloc.cc
+++ b/src/3rdparty/v8/test/cctest/test-alloc.cc
@@ -34,6 +34,15 @@
using namespace v8::internal;
+static inline void SimulateFullSpace(PagedSpace* space) {
+ int old_linear_size = static_cast<int>(space->limit() - space->top());
+ space->Free(space->top(), old_linear_size);
+ space->SetTop(space->limit(), space->limit());
+ space->ResetFreeList();
+ space->ClearStats();
+}
+
+
static MaybeObject* AllocateAfterFailures() {
static int attempts = 0;
if (++attempts < 3) return Failure::RetryAfterGC();
@@ -65,24 +74,12 @@ static MaybeObject* AllocateAfterFailures() {
CHECK(!heap->CopyJSObject(JSObject::cast(object))->IsFailure());
// Old data space.
- OldSpace* old_data_space = heap->old_data_space();
- static const int kOldDataSpaceFillerSize = ByteArray::SizeFor(0);
- while (old_data_space->Available() > kOldDataSpaceFillerSize) {
- CHECK(!heap->AllocateByteArray(0, TENURED)->IsFailure());
- }
+ SimulateFullSpace(heap->old_data_space());
CHECK(!heap->AllocateRawAsciiString(100, TENURED)->IsFailure());
// Old pointer space.
- OldSpace* old_pointer_space = heap->old_pointer_space();
- static const int kOldPointerSpaceFillerLength = 10000;
- static const int kOldPointerSpaceFillerSize = FixedArray::SizeFor(
- kOldPointerSpaceFillerLength);
- while (old_pointer_space->Available() > kOldPointerSpaceFillerSize) {
- CHECK(!heap->AllocateFixedArray(kOldPointerSpaceFillerLength, TENURED)->
- IsFailure());
- }
- CHECK(!heap->AllocateFixedArray(kOldPointerSpaceFillerLength, TENURED)->
- IsFailure());
+ SimulateFullSpace(heap->old_pointer_space());
+ CHECK(!heap->AllocateFixedArray(10000, TENURED)->IsFailure());
// Large object space.
static const int kLargeObjectSpaceFillerLength = 300000;
@@ -97,14 +94,9 @@ static MaybeObject* AllocateAfterFailures() {
IsFailure());
// Map space.
- MapSpace* map_space = heap->map_space();
- static const int kMapSpaceFillerSize = Map::kSize;
- InstanceType instance_type = JS_OBJECT_TYPE;
+ SimulateFullSpace(heap->map_space());
int instance_size = JSObject::kHeaderSize;
- while (map_space->Available() > kMapSpaceFillerSize) {
- CHECK(!heap->AllocateMap(instance_type, instance_size)->IsFailure());
- }
- CHECK(!heap->AllocateMap(instance_type, instance_size)->IsFailure());
+ CHECK(!heap->AllocateMap(JS_OBJECT_TYPE, instance_size)->IsFailure());
// Test that we can allocate in old pointer space and code space.
CHECK(!heap->AllocateFixedArray(100, TENURED)->IsFailure());
diff --git a/src/3rdparty/v8/test/cctest/test-api.cc b/src/3rdparty/v8/test/cctest/test-api.cc
index c013150..8a1e914 100644
--- a/src/3rdparty/v8/test/cctest/test-api.cc
+++ b/src/3rdparty/v8/test/cctest/test-api.cc
@@ -8608,6 +8608,8 @@ static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
const AccessorInfo& info) {
ApiTestFuzzer::Fuzz();
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ CHECK_EQ(isolate, info.GetIsolate());
CHECK_EQ(v8_str("data"), info.Data());
CHECK_EQ(v8_str("x"), name);
return v8::Integer::New(42);
@@ -9334,6 +9336,8 @@ static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
static v8::Handle<Value> FastApiCallback_TrivialSignature(
const v8::Arguments& args) {
ApiTestFuzzer::Fuzz();
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ CHECK_EQ(isolate, args.GetIsolate());
CHECK_EQ(args.This(), args.Holder());
CHECK(args.Data()->Equals(v8_str("method_data")));
return v8::Integer::New(args[0]->Int32Value() + 1);
@@ -9342,6 +9346,8 @@ static v8::Handle<Value> FastApiCallback_TrivialSignature(
static v8::Handle<Value> FastApiCallback_SimpleSignature(
const v8::Arguments& args) {
ApiTestFuzzer::Fuzz();
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ CHECK_EQ(isolate, args.GetIsolate());
CHECK_EQ(args.This()->GetPrototype(), args.Holder());
CHECK(args.Data()->Equals(v8_str("method_data")));
// Note, we're using HasRealNamedProperty instead of Has to avoid
@@ -10865,13 +10871,18 @@ THREADED_TEST(NestedHandleScopeAndContexts) {
}
+static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
+
+
THREADED_TEST(ExternalAllocatedMemory) {
v8::HandleScope outer;
v8::Persistent<Context> env(Context::New());
CHECK(!env.IsEmpty());
- const int kSize = 1024*1024;
- CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
- CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
+ const intptr_t kSize = 1024*1024;
+ CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize)),
+ cast(kSize));
+ CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize)),
+ cast(0));
}
@@ -12365,6 +12376,46 @@ THREADED_TEST(ForceDeleteIC) {
}
+TEST(InlinedFunctionAcrossContexts) {
+ i::FLAG_allow_natives_syntax = true;
+ v8::HandleScope outer_scope;
+ v8::Persistent<v8::Context> ctx1 = v8::Context::New();
+ v8::Persistent<v8::Context> ctx2 = v8::Context::New();
+ ctx1->Enter();
+
+ {
+ v8::HandleScope inner_scope;
+ CompileRun("var G = 42; function foo() { return G; }");
+ v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
+ ctx2->Enter();
+ ctx2->Global()->Set(v8_str("o"), foo);
+ v8::Local<v8::Value> res = CompileRun(
+ "function f() { return o(); }"
+ "for (var i = 0; i < 10; ++i) f();"
+ "%OptimizeFunctionOnNextCall(f);"
+ "f();");
+ CHECK_EQ(42, res->Int32Value());
+ ctx2->Exit();
+ v8::Handle<v8::String> G_property = v8::String::New("G");
+ CHECK(ctx1->Global()->ForceDelete(G_property));
+ ctx2->Enter();
+ ExpectString(
+ "(function() {"
+ " try {"
+ " return f();"
+ " } catch(e) {"
+ " return e.toString();"
+ " }"
+ " })()",
+ "ReferenceError: G is not defined");
+ ctx2->Exit();
+ ctx1->Exit();
+ ctx1.Dispose();
+ }
+ ctx2.Dispose();
+}
+
+
v8::Persistent<Context> calling_context0;
v8::Persistent<Context> calling_context1;
v8::Persistent<Context> calling_context2;
@@ -12430,19 +12481,16 @@ THREADED_TEST(GetCallingContext) {
// Check that a variable declaration with no explicit initialization
-// value does not shadow an existing property in the prototype chain.
-//
-// This is consistent with Firefox and Safari.
-//
-// See http://crbug.com/12548.
+// value does shadow an existing property in the prototype chain.
THREADED_TEST(InitGlobalVarInProtoChain) {
+ i::FLAG_es52_globals = true;
v8::HandleScope scope;
LocalContext context;
// Introduce a variable in the prototype chain.
CompileRun("__proto__.x = 42");
- v8::Handle<v8::Value> result = CompileRun("var x; x");
+ v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
CHECK(!result->IsUndefined());
- CHECK_EQ(42, result->Int32Value());
+ CHECK_EQ(43, result->Int32Value());
}
@@ -13947,75 +13995,104 @@ TEST(SourceURLInStackTrace) {
}
+static void CreateGarbageInOldSpace() {
+ v8::HandleScope scope;
+ i::AlwaysAllocateScope always_allocate;
+ for (int i = 0; i < 1000; i++) {
+ FACTORY->NewFixedArray(1000, i::TENURED);
+ }
+}
+
// Test that idle notification can be handled and eventually returns true.
-// This just checks the contract of the IdleNotification() function,
-// and does not verify that it does reasonable work.
-THREADED_TEST(IdleNotification) {
+TEST(IdleNotification) {
+ const intptr_t MB = 1024 * 1024;
v8::HandleScope scope;
LocalContext env;
- {
- // Create garbage in old-space to generate work for idle notification.
- i::AlwaysAllocateScope always_allocate;
- for (int i = 0; i < 100; i++) {
- FACTORY->NewFixedArray(1000, i::TENURED);
- }
+ intptr_t initial_size = HEAP->SizeOfObjects();
+ CreateGarbageInOldSpace();
+ intptr_t size_with_garbage = HEAP->SizeOfObjects();
+ CHECK_GT(size_with_garbage, initial_size + MB);
+ bool finished = false;
+ for (int i = 0; i < 200 && !finished; i++) {
+ finished = v8::V8::IdleNotification();
}
- bool finshed_idle_work = false;
- for (int i = 0; i < 100 && !finshed_idle_work; i++) {
- finshed_idle_work = v8::V8::IdleNotification();
- }
- CHECK(finshed_idle_work);
+ intptr_t final_size = HEAP->SizeOfObjects();
+ CHECK(finished);
+ CHECK_LT(final_size, initial_size + 1);
}
-// Test that idle notification can be handled and eventually returns true.
-// This just checks the contract of the IdleNotification() function,
-// and does not verify that it does reasonable work.
+
+// Test that idle notification can be handled and eventually collects garbage.
TEST(IdleNotificationWithSmallHint) {
+ const intptr_t MB = 1024 * 1024;
+ const int IdlePauseInMs = 900;
v8::HandleScope scope;
LocalContext env;
- {
- // Create garbage in old-space to generate work for idle notification.
- i::AlwaysAllocateScope always_allocate;
- for (int i = 0; i < 100; i++) {
- FACTORY->NewFixedArray(1000, i::TENURED);
- }
+ intptr_t initial_size = HEAP->SizeOfObjects();
+ CreateGarbageInOldSpace();
+ intptr_t size_with_garbage = HEAP->SizeOfObjects();
+ CHECK_GT(size_with_garbage, initial_size + MB);
+ bool finished = false;
+ for (int i = 0; i < 200 && !finished; i++) {
+ finished = v8::V8::IdleNotification(IdlePauseInMs);
}
- intptr_t old_size = HEAP->SizeOfObjects();
- bool finshed_idle_work = false;
- bool no_idle_work = v8::V8::IdleNotification(10);
- for (int i = 0; i < 200 && !finshed_idle_work; i++) {
- finshed_idle_work = v8::V8::IdleNotification(10);
- }
- intptr_t new_size = HEAP->SizeOfObjects();
- CHECK(finshed_idle_work);
- CHECK(no_idle_work || new_size < old_size);
+ intptr_t final_size = HEAP->SizeOfObjects();
+ CHECK(finished);
+ CHECK_LT(final_size, initial_size + 1);
}
-// This just checks the contract of the IdleNotification() function,
-// and does not verify that it does reasonable work.
+// Test that idle notification can be handled and eventually collects garbage.
TEST(IdleNotificationWithLargeHint) {
+ const intptr_t MB = 1024 * 1024;
+ const int IdlePauseInMs = 900;
v8::HandleScope scope;
LocalContext env;
- {
- // Create garbage in old-space to generate work for idle notification.
- i::AlwaysAllocateScope always_allocate;
- for (int i = 0; i < 100; i++) {
- FACTORY->NewFixedArray(1000, i::TENURED);
- }
- }
- intptr_t old_size = HEAP->SizeOfObjects();
- bool finshed_idle_work = false;
- bool no_idle_work = v8::V8::IdleNotification(900);
- for (int i = 0; i < 200 && !finshed_idle_work; i++) {
- finshed_idle_work = v8::V8::IdleNotification(900);
+ intptr_t initial_size = HEAP->SizeOfObjects();
+ CreateGarbageInOldSpace();
+ intptr_t size_with_garbage = HEAP->SizeOfObjects();
+ CHECK_GT(size_with_garbage, initial_size + MB);
+ bool finished = false;
+ for (int i = 0; i < 200 && !finished; i++) {
+ finished = v8::V8::IdleNotification(IdlePauseInMs);
}
- intptr_t new_size = HEAP->SizeOfObjects();
- CHECK(finshed_idle_work);
- CHECK(no_idle_work || new_size < old_size);
+ intptr_t final_size = HEAP->SizeOfObjects();
+ CHECK(finished);
+ CHECK_LT(final_size, initial_size + 1);
}
+TEST(Regress2107) {
+ const intptr_t MB = 1024 * 1024;
+ const int kShortIdlePauseInMs = 100;
+ const int kLongIdlePauseInMs = 1000;
+ v8::HandleScope scope;
+ LocalContext env;
+ intptr_t initial_size = HEAP->SizeOfObjects();
+ // Send idle notification to start a round of incremental GCs.
+ v8::V8::IdleNotification(kShortIdlePauseInMs);
+ // Emulate 7 page reloads.
+ for (int i = 0; i < 7; i++) {
+ v8::Persistent<v8::Context> ctx = v8::Context::New();
+ ctx->Enter();
+ CreateGarbageInOldSpace();
+ ctx->Exit();
+ ctx.Dispose();
+ v8::V8::ContextDisposedNotification();
+ v8::V8::IdleNotification(kLongIdlePauseInMs);
+ }
+ // Create garbage and check that idle notification still collects it.
+ CreateGarbageInOldSpace();
+ intptr_t size_with_garbage = HEAP->SizeOfObjects();
+ CHECK_GT(size_with_garbage, initial_size + MB);
+ bool finished = false;
+ for (int i = 0; i < 200 && !finished; i++) {
+ finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
+ }
+ intptr_t final_size = HEAP->SizeOfObjects();
+ CHECK_LT(final_size, initial_size + 1);
+}
+
static uint32_t* stack_limit;
static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
@@ -14319,7 +14396,6 @@ TEST(Regress528) {
v8::Persistent<Context> context;
v8::Persistent<Context> other_context;
int gc_count;
- bool snapshot_enabled = i::Snapshot::IsEnabled();
// Create a context used to keep the code from aging in the compilation
// cache.
@@ -14344,10 +14420,10 @@ TEST(Regress528) {
CompileRun(source_simple);
other_context->Exit();
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
- if (GetGlobalObjectsCount() == (snapshot_enabled ? 2 : 1)) break;
+ if (GetGlobalObjectsCount() == 1) break;
}
CHECK_GE(2, gc_count);
- CHECK_EQ((snapshot_enabled ? 2 : 1), GetGlobalObjectsCount());
+ CHECK_EQ(1, GetGlobalObjectsCount());
// Eval in a function creates reference from the compilation cache to the
// global object.
@@ -14366,10 +14442,10 @@ TEST(Regress528) {
CompileRun(source_eval);
other_context->Exit();
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
- if (GetGlobalObjectsCount() == (snapshot_enabled ? 2 : 1)) break;
+ if (GetGlobalObjectsCount() == 1) break;
}
CHECK_GE(2, gc_count);
- CHECK_EQ((snapshot_enabled ? 2 : 1), GetGlobalObjectsCount());
+ CHECK_EQ(1, GetGlobalObjectsCount());
// Looking up the line number for an exception creates reference from the
// compilation cache to the global object.
@@ -14393,10 +14469,10 @@ TEST(Regress528) {
CompileRun(source_exception);
other_context->Exit();
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
- if (GetGlobalObjectsCount() == (snapshot_enabled ? 2 : 1)) break;
+ if (GetGlobalObjectsCount() == 1) break;
}
CHECK_GE(2, gc_count);
- CHECK_EQ((snapshot_enabled ? 2 : 1), GetGlobalObjectsCount());
+ CHECK_EQ(1, GetGlobalObjectsCount());
other_context.Dispose();
}
@@ -16136,6 +16212,30 @@ THREADED_TEST(Regress93759) {
}
+THREADED_TEST(Regress125988) {
+ v8::HandleScope scope;
+ Handle<FunctionTemplate> intercept = FunctionTemplate::New();
+ AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
+ LocalContext env;
+ env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
+ CompileRun("var a = new Object();"
+ "var b = new Intercept();"
+ "var c = new Object();"
+ "c.__proto__ = b;"
+ "b.__proto__ = a;"
+ "a.x = 23;"
+ "for (var i = 0; i < 3; i++) c.x;");
+ ExpectBoolean("c.hasOwnProperty('x')", false);
+ ExpectInt32("c.x", 23);
+ CompileRun("a.y = 42;"
+ "for (var i = 0; i < 3; i++) c.x;");
+ ExpectBoolean("c.hasOwnProperty('x')", false);
+ ExpectInt32("c.x", 23);
+ ExpectBoolean("c.hasOwnProperty('y')", false);
+ ExpectInt32("c.y", 42);
+}
+
+
static void TestReceiver(Local<Value> expected_result,
Local<Value> expected_receiver,
const char* code) {
@@ -16402,3 +16502,94 @@ TEST(PrimaryStubCache) {
StubCacheHelper(false);
}
+
+static int fatal_error_callback_counter = 0;
+static void CountingErrorCallback(const char* location, const char* message) {
+ printf("CountingErrorCallback(\"%s\", \"%s\")\n", location, message);
+ fatal_error_callback_counter++;
+}
+
+
+TEST(StaticGetters) {
+ v8::HandleScope scope;
+ LocalContext context;
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ i::Handle<i::Object> undefined_value = FACTORY->undefined_value();
+ CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value);
+ CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
+ i::Handle<i::Object> null_value = FACTORY->null_value();
+ CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value);
+ CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
+ i::Handle<i::Object> true_value = FACTORY->true_value();
+ CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value);
+ CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
+ i::Handle<i::Object> false_value = FACTORY->false_value();
+ CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value);
+ CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
+
+ // Test after-death behavior.
+ CHECK(i::Internals::IsInitialized(isolate));
+ CHECK_EQ(0, fatal_error_callback_counter);
+ v8::V8::SetFatalErrorHandler(CountingErrorCallback);
+ v8::Utils::ReportApiFailure("StaticGetters()", "Kill V8");
+ i::Isolate::Current()->TearDown();
+ CHECK(!i::Internals::IsInitialized(isolate));
+ CHECK_EQ(1, fatal_error_callback_counter);
+ CHECK(v8::Undefined().IsEmpty());
+ CHECK_EQ(2, fatal_error_callback_counter);
+ CHECK(v8::Undefined(isolate).IsEmpty());
+ CHECK_EQ(3, fatal_error_callback_counter);
+ CHECK(v8::Null().IsEmpty());
+ CHECK_EQ(4, fatal_error_callback_counter);
+ CHECK(v8::Null(isolate).IsEmpty());
+ CHECK_EQ(5, fatal_error_callback_counter);
+ CHECK(v8::True().IsEmpty());
+ CHECK_EQ(6, fatal_error_callback_counter);
+ CHECK(v8::True(isolate).IsEmpty());
+ CHECK_EQ(7, fatal_error_callback_counter);
+ CHECK(v8::False().IsEmpty());
+ CHECK_EQ(8, fatal_error_callback_counter);
+ CHECK(v8::False(isolate).IsEmpty());
+ CHECK_EQ(9, fatal_error_callback_counter);
+}
+
+
+TEST(IsolateEmbedderData) {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ CHECK_EQ(NULL, isolate->GetData());
+ CHECK_EQ(NULL, ISOLATE->GetData());
+ static void* data1 = reinterpret_cast<void*>(0xacce55ed);
+ isolate->SetData(data1);
+ CHECK_EQ(data1, isolate->GetData());
+ CHECK_EQ(data1, ISOLATE->GetData());
+ static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
+ ISOLATE->SetData(data2);
+ CHECK_EQ(data2, isolate->GetData());
+ CHECK_EQ(data2, ISOLATE->GetData());
+ ISOLATE->TearDown();
+ CHECK_EQ(data2, isolate->GetData());
+ CHECK_EQ(data2, ISOLATE->GetData());
+}
+
+
+TEST(StringEmpty) {
+ v8::HandleScope scope;
+ LocalContext context;
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ i::Handle<i::Object> empty_string = FACTORY->empty_symbol();
+ CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
+ CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
+
+ // Test after-death behavior.
+ CHECK(i::Internals::IsInitialized(isolate));
+ CHECK_EQ(0, fatal_error_callback_counter);
+ v8::V8::SetFatalErrorHandler(CountingErrorCallback);
+ v8::Utils::ReportApiFailure("StringEmpty()", "Kill V8");
+ i::Isolate::Current()->TearDown();
+ CHECK(!i::Internals::IsInitialized(isolate));
+ CHECK_EQ(1, fatal_error_callback_counter);
+ CHECK(v8::String::Empty().IsEmpty());
+ CHECK_EQ(2, fatal_error_callback_counter);
+ CHECK(v8::String::Empty(isolate).IsEmpty());
+ CHECK_EQ(3, fatal_error_callback_counter);
+}
diff --git a/src/3rdparty/v8/test/cctest/test-debug.cc b/src/3rdparty/v8/test/cctest/test-debug.cc
index 107c666..e40f406 100644
--- a/src/3rdparty/v8/test/cctest/test-debug.cc
+++ b/src/3rdparty/v8/test/cctest/test-debug.cc
@@ -2300,65 +2300,6 @@ TEST(ScriptBreakPointTopLevelCrash) {
CheckDebuggerUnloaded();
}
-// Test that breakpoint_relocation flag is honored
-TEST(ScriptBreakPointNoRelocation) {
- i::FLAG_breakpoint_relocation = false;
-
- v8::HandleScope scope;
- DebugLocalContext env;
- env.ExposeDebug();
-
- // Create a function for checking the function when hitting a break point.
- frame_function_name = CompileFunction(&env,
- frame_function_name_source,
- "frame_function_name");
-
- v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
- v8::Undefined());
-
- v8::Local<v8::String> script1 = v8::String::New(
- "a = 0 // line 0\n"
- " // line 1\n"
- " // line 2\n"
- " // line 3\n"
- "function f() { // line 4\n"
- " return 0; // line 5\n"
- "} // line 6");
-
- // Set the script break point on the empty line
- SetScriptBreakPointByNameFromJS("test.html", 2, -1);
-
- // Compile the script and call the function.
- v8::ScriptOrigin origin(v8::String::New("test.html"), v8::Integer::New(0));
- v8::Script::Compile(script1, &origin)->Run();
- v8::Local<v8::Function> f
- = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
- f->Call(env->Global(), 0, NULL);
-
- // Check that a break point was not hit
- CHECK_EQ(0, break_point_hit_count);
-
- v8::Local<v8::String> script2 = v8::String::New(
- "a = 0 // line 0\n"
- "function g() { // line 1\n"
- " return 0; // line 2\n"
- "} // line 3\n"
- "function f() { // line 4\n"
- " return 0; // line 5\n"
- "} // line 6");
-
- // Compile the script and call the new function
- v8::Script::Compile(script2, &origin)->Run();
- v8::Local<v8::Function> g
- = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
- g->Call(env->Global(), 0, NULL);
-
- // Check that a break point was not hit
- CHECK_EQ(1, break_point_hit_count);
-
- v8::Debug::SetDebugEventListener(NULL);
- CheckDebuggerUnloaded();
-}
// Test that it is possible to remove the last break point for a function
// inside the break handling of that break point.
@@ -5072,7 +5013,10 @@ static void ThreadedMessageHandler(const v8::Debug::Message& message) {
if (IsBreakEventMessage(print_buffer)) {
// Check that we are inside the while loop.
int source_line = GetSourceLineFromBreakEventMessage(print_buffer);
- CHECK(8 <= source_line && source_line <= 13);
+ // TODO(2047): This should really be 8 <= source_line <= 13; but we
+ // currently have an off-by-one error when calculating the source
+ // position corresponding to the program counter at the debug break.
+ CHECK(7 <= source_line && source_line <= 13);
threaded_debugging_barriers.barrier_2.Wait();
}
}
diff --git a/src/3rdparty/v8/test/cctest/test-decls.cc b/src/3rdparty/v8/test/cctest/test-decls.cc
index aa733c7..e6bdc9f 100644
--- a/src/3rdparty/v8/test/cctest/test-decls.cc
+++ b/src/3rdparty/v8/test/cctest/test-decls.cc
@@ -521,6 +521,7 @@ class ExistsInPrototypeContext: public DeclarationContext {
TEST(ExistsInPrototype) {
+ i::FLAG_es52_globals = true;
HandleScope scope;
// Sanity check to make sure that the holder of the interceptor
@@ -535,17 +536,17 @@ TEST(ExistsInPrototype) {
{ ExistsInPrototypeContext context;
context.Check("var x; x",
- 1, // get
+ 0, // get
0,
- 1, // declaration
- EXPECT_EXCEPTION);
+ 0, // declaration
+ EXPECT_RESULT, Undefined());
}
{ ExistsInPrototypeContext context;
context.Check("var x = 0; x",
0,
0,
- 1, // declaration
+ 0, // declaration
EXPECT_RESULT, Number::New(0));
}
@@ -553,7 +554,7 @@ TEST(ExistsInPrototype) {
context.Check("const x; x",
0,
0,
- 1, // declaration
+ 0, // declaration
EXPECT_RESULT, Undefined());
}
@@ -561,7 +562,7 @@ TEST(ExistsInPrototype) {
context.Check("const x = 0; x",
0,
0,
- 1, // declaration
+ 0, // declaration
EXPECT_RESULT, Number::New(0));
}
}
@@ -583,13 +584,14 @@ class AbsentInPrototypeContext: public DeclarationContext {
TEST(AbsentInPrototype) {
+ i::FLAG_es52_globals = true;
HandleScope scope;
{ AbsentInPrototypeContext context;
context.Check("if (false) { var x = 0; }; x",
0,
0,
- 1, // declaration
+ 0, // declaration
EXPECT_RESULT, Undefined());
}
}
diff --git a/src/3rdparty/v8/test/cctest/test-double.cc b/src/3rdparty/v8/test/cctest/test-double.cc
index 3594a4f..6ef42c6 100644
--- a/src/3rdparty/v8/test/cctest/test-double.cc
+++ b/src/3rdparty/v8/test/cctest/test-double.cc
@@ -112,21 +112,6 @@ TEST(IsInfinite) {
}
-TEST(IsNan) {
- CHECK(Double(OS::nan_value()).IsNan());
- uint64_t other_nan = V8_2PART_UINT64_C(0xFFFFFFFF, 00000001);
- CHECK(Double(other_nan).IsNan());
- CHECK(!Double(V8_INFINITY).IsNan());
- CHECK(!Double(-V8_INFINITY).IsNan());
- CHECK(!Double(0.0).IsNan());
- CHECK(!Double(-0.0).IsNan());
- CHECK(!Double(1.0).IsNan());
- CHECK(!Double(-1.0).IsNan());
- uint64_t min_double64 = V8_2PART_UINT64_C(0x00000000, 00000001);
- CHECK(!Double(min_double64).IsNan());
-}
-
-
TEST(Sign) {
CHECK_EQ(1, Double(1.0).Sign());
CHECK_EQ(1, Double(V8_INFINITY).Sign());
diff --git a/src/3rdparty/v8/test/cctest/test-heap-profiler.cc b/src/3rdparty/v8/test/cctest/test-heap-profiler.cc
index b6fc486..cbe8d44 100644
--- a/src/3rdparty/v8/test/cctest/test-heap-profiler.cc
+++ b/src/3rdparty/v8/test/cctest/test-heap-profiler.cc
@@ -2,11 +2,14 @@
//
// Tests for heap profiler
+#include <ctype.h>
+
#include "v8.h"
#include "cctest.h"
#include "heap-profiler.h"
#include "snapshot.h"
+#include "debug.h"
#include "utils-inl.h"
#include "../include/v8-profiler.h"
@@ -31,10 +34,10 @@ class NamedEntriesDetector {
CheckEntry(root);
while (!list.is_empty()) {
i::HeapEntry* entry = list.RemoveLast();
- i::Vector<i::HeapGraphEdge> children = entry->children();
+ i::Vector<i::HeapGraphEdge*> children = entry->children();
for (int i = 0; i < children.length(); ++i) {
- if (children[i].type() == i::HeapGraphEdge::kShortcut) continue;
- i::HeapEntry* child = children[i].to();
+ if (children[i]->type() == i::HeapGraphEdge::kShortcut) continue;
+ i::HeapEntry* child = children[i]->to();
if (!child->painted()) {
list.Add(child);
child->paint();
@@ -54,11 +57,9 @@ class NamedEntriesDetector {
static const v8::HeapGraphNode* GetGlobalObject(
const v8::HeapSnapshot* snapshot) {
- bool snapshot_enabled = i::Snapshot::IsEnabled();
-
- CHECK_EQ((snapshot_enabled ? 3 : 2), snapshot->GetRoot()->GetChildrenCount());
+ CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount());
const v8::HeapGraphNode* global_obj =
- snapshot->GetRoot()->GetChild(snapshot_enabled ? 1 : 0)->GetToNode();
+ snapshot->GetRoot()->GetChild(0)->GetToNode();
CHECK_EQ(0, strncmp("Object", const_cast<i::HeapEntry*>(
reinterpret_cast<const i::HeapEntry*>(global_obj))->name(), 6));
return global_obj;
@@ -111,13 +112,13 @@ TEST(HeapSnapshot) {
// Verify, that JS global object of env2 has '..2' properties.
const v8::HeapGraphNode* a2_node =
- GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "a2");
+ GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a2");
CHECK_NE(NULL, a2_node);
CHECK_NE(
- NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_1"));
+ NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_1"));
CHECK_NE(
- NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2"));
- CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2"));
+ NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_2"));
+ CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "c2"));
// Paint all nodes reachable from global object.
NamedEntriesDetector det;
@@ -139,12 +140,13 @@ TEST(HeapSnapshotObjectSizes) {
CompileRun(
"function X(a, b) { this.a = a; this.b = b; }\n"
"x = new X(new X(), new X());\n"
+ "dummy = new X();\n"
"(function() { x.a.a = x.b; })();");
const v8::HeapSnapshot* snapshot =
v8::HeapProfiler::TakeSnapshot(v8_str("sizes"));
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
const v8::HeapGraphNode* x =
- GetProperty(global, v8::HeapGraphEdge::kShortcut, "x");
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "x");
CHECK_NE(NULL, x);
const v8::HeapGraphNode* x1 =
GetProperty(x, v8::HeapGraphEdge::kProperty, "a");
@@ -171,7 +173,7 @@ TEST(BoundFunctionInSnapshot) {
v8::HeapProfiler::TakeSnapshot(v8_str("sizes"));
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
const v8::HeapGraphNode* f =
- GetProperty(global, v8::HeapGraphEdge::kShortcut, "boundFunction");
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "boundFunction");
CHECK(f);
CHECK_EQ(v8::String::New("native_bind"), f->GetName());
const v8::HeapGraphNode* bindings =
@@ -235,15 +237,15 @@ TEST(HeapSnapshotCodeObjects) {
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
const v8::HeapGraphNode* compiled =
- GetProperty(global, v8::HeapGraphEdge::kShortcut, "compiled");
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "compiled");
CHECK_NE(NULL, compiled);
CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType());
const v8::HeapGraphNode* lazy =
- GetProperty(global, v8::HeapGraphEdge::kShortcut, "lazy");
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "lazy");
CHECK_NE(NULL, lazy);
CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType());
const v8::HeapGraphNode* anonymous =
- GetProperty(global, v8::HeapGraphEdge::kShortcut, "anonymous");
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "anonymous");
CHECK_NE(NULL, anonymous);
CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType());
v8::String::AsciiValue anonymous_name(anonymous->GetName());
@@ -295,9 +297,9 @@ TEST(HeapSnapshotHeapNumbers) {
const v8::HeapSnapshot* snapshot =
v8::HeapProfiler::TakeSnapshot(v8_str("numbers"));
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
- CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kShortcut, "a"));
+ CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kProperty, "a"));
const v8::HeapGraphNode* b =
- GetProperty(global, v8::HeapGraphEdge::kShortcut, "b");
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "b");
CHECK_NE(NULL, b);
CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType());
}
@@ -315,10 +317,10 @@ TEST(HeapSnapshotSlicedString) {
v8::HeapProfiler::TakeSnapshot(v8_str("strings"));
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
const v8::HeapGraphNode* parent_string =
- GetProperty(global, v8::HeapGraphEdge::kShortcut, "parent_string");
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "parent_string");
CHECK_NE(NULL, parent_string);
const v8::HeapGraphNode* child_string =
- GetProperty(global, v8::HeapGraphEdge::kShortcut, "child_string");
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "child_string");
CHECK_NE(NULL, child_string);
const v8::HeapGraphNode* parent =
GetProperty(child_string, v8::HeapGraphEdge::kInternal, "parent");
@@ -386,24 +388,17 @@ TEST(HeapEntryIdsAndArrayShift) {
const v8::HeapGraphNode* a1 =
GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
CHECK_NE(NULL, a1);
- const v8::HeapGraphNode* e1 =
- GetProperty(a1, v8::HeapGraphEdge::kHidden, "1");
- CHECK_NE(NULL, e1);
const v8::HeapGraphNode* k1 =
- GetProperty(e1, v8::HeapGraphEdge::kInternal, "elements");
+ GetProperty(a1, v8::HeapGraphEdge::kInternal, "elements");
CHECK_NE(NULL, k1);
const v8::HeapGraphNode* a2 =
GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
CHECK_NE(NULL, a2);
- const v8::HeapGraphNode* e2 =
- GetProperty(a2, v8::HeapGraphEdge::kHidden, "1");
- CHECK_NE(NULL, e2);
const v8::HeapGraphNode* k2 =
- GetProperty(e2, v8::HeapGraphEdge::kInternal, "elements");
+ GetProperty(a2, v8::HeapGraphEdge::kInternal, "elements");
CHECK_NE(NULL, k2);
CHECK_EQ_SNAPSHOT_OBJECT_ID(a1->GetId(), a2->GetId());
- CHECK_EQ_SNAPSHOT_OBJECT_ID(e1->GetId(), e2->GetId());
CHECK_EQ_SNAPSHOT_OBJECT_ID(k1->GetId(), k2->GetId());
}
@@ -516,7 +511,7 @@ TEST(HeapEntryDominator) {
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
CHECK_NE(NULL, global);
const v8::HeapGraphNode* node6 =
- GetProperty(global, v8::HeapGraphEdge::kShortcut, "node6");
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "node6");
CHECK_NE(NULL, node6);
const v8::HeapGraphNode* node5 =
GetProperty(node6, v8::HeapGraphEdge::kProperty, "a");
@@ -559,9 +554,14 @@ class TestJSONStream : public v8::OutputStream {
memcpy(chunk.start(), buffer, chars_written);
return kContinue;
}
+ virtual WriteResult WriteUint32Chunk(uint32_t* buffer, int chars_written) {
+ ASSERT(false);
+ return kAbort;
+ }
void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); }
int eos_signaled() { return eos_signaled_; }
int size() { return buffer_.size(); }
+
private:
i::Collector<char> buffer_;
int eos_signaled_;
@@ -615,66 +615,50 @@ TEST(HeapSnapshotJSONSerialization) {
env->Global()->Get(v8_str("parsed"))->ToObject();
CHECK(parsed_snapshot->Has(v8_str("snapshot")));
CHECK(parsed_snapshot->Has(v8_str("nodes")));
+ CHECK(parsed_snapshot->Has(v8_str("edges")));
CHECK(parsed_snapshot->Has(v8_str("strings")));
// Get node and edge "member" offsets.
v8::Local<v8::Value> meta_analysis_result = CompileRun(
- "var parsed_meta = parsed.nodes[0];\n"
- "var children_count_offset ="
- " parsed_meta.fields.indexOf('children_count');\n"
- "var children_offset ="
- " parsed_meta.fields.indexOf('children');\n"
- "var children_meta ="
- " parsed_meta.types[children_offset];\n"
- "var child_fields_count = children_meta.fields.length;\n"
- "var child_type_offset ="
- " children_meta.fields.indexOf('type');\n"
- "var child_name_offset ="
- " children_meta.fields.indexOf('name_or_index');\n"
- "var child_to_node_offset ="
- " children_meta.fields.indexOf('to_node');\n"
+ "var meta = parsed.snapshot.meta;\n"
+ "var edges_index_offset = meta.node_fields.indexOf('edges_index');\n"
+ "var node_fields_count = meta.node_fields.length;\n"
+ "var edge_fields_count = meta.edge_fields.length;\n"
+ "var edge_type_offset = meta.edge_fields.indexOf('type');\n"
+ "var edge_name_offset = meta.edge_fields.indexOf('name_or_index');\n"
+ "var edge_to_node_offset = meta.edge_fields.indexOf('to_node');\n"
"var property_type ="
- " children_meta.types[child_type_offset].indexOf('property');\n"
+ " meta.edge_types[edge_type_offset].indexOf('property');\n"
"var shortcut_type ="
- " children_meta.types[child_type_offset].indexOf('shortcut');");
+ " meta.edge_types[edge_type_offset].indexOf('shortcut');\n"
+ "parsed.nodes.concat(0, 0, 0, 0, 0, 0, parsed.edges.length);");
CHECK(!meta_analysis_result.IsEmpty());
// A helper function for processing encoded nodes.
CompileRun(
"function GetChildPosByProperty(pos, prop_name, prop_type) {\n"
" var nodes = parsed.nodes;\n"
+ " var edges = parsed.edges;\n"
" var strings = parsed.strings;\n"
- " for (var i = 0,\n"
- " count = nodes[pos + children_count_offset] * child_fields_count;\n"
- " i < count; i += child_fields_count) {\n"
- " var child_pos = pos + children_offset + i;\n"
- " if (nodes[child_pos + child_type_offset] === prop_type\n"
- " && strings[nodes[child_pos + child_name_offset]] === prop_name)\n"
- " return nodes[child_pos + child_to_node_offset];\n"
+ " for (var i = nodes[pos + edges_index_offset],\n"
+ " count = nodes[pos + node_fields_count + edges_index_offset];\n"
+ " i < count; i += edge_fields_count) {\n"
+ " if (edges[i + edge_type_offset] === prop_type\n"
+ " && strings[edges[i + edge_name_offset]] === prop_name)\n"
+ " return edges[i + edge_to_node_offset];\n"
" }\n"
" return null;\n"
"}\n");
// Get the string index using the path: <root> -> <global>.b.x.s
- v8::Local<v8::Value> string_obj_pos_val;
- if (i::Snapshot::IsEnabled()) {
- string_obj_pos_val = CompileRun(
- "GetChildPosByProperty(\n"
- " GetChildPosByProperty(\n"
- " GetChildPosByProperty("
- " parsed.nodes[1 + children_offset + child_to_node_offset + child_fields_count],"
- " \"b\",shortcut_type),\n"
- " \"x\", property_type),"
- " \"s\", property_type)");
- } else {
- string_obj_pos_val = CompileRun(
- "GetChildPosByProperty(\n"
- " GetChildPosByProperty(\n"
- " GetChildPosByProperty("
- " parsed.nodes[1 + children_offset + child_to_node_offset],"
- " \"b\",shortcut_type),\n"
- " \"x\", property_type),"
- " \"s\", property_type)");
- }
+ v8::Local<v8::Value> string_obj_pos_val = CompileRun(
+ "GetChildPosByProperty(\n"
+ " GetChildPosByProperty(\n"
+ " GetChildPosByProperty("
+ " parsed.edges[parsed.nodes[edges_index_offset]"
+ " + edge_to_node_offset],"
+ " \"b\", property_type),\n"
+ " \"x\", property_type),"
+ " \"s\", property_type)");
CHECK(!string_obj_pos_val.IsEmpty());
int string_obj_pos =
static_cast<int>(string_obj_pos_val->ToNumber()->Value());
@@ -705,6 +689,200 @@ TEST(HeapSnapshotJSONSerializationAborting) {
CHECK_EQ(0, stream.eos_signaled());
}
+namespace {
+
+class TestStatsStream : public v8::OutputStream {
+ public:
+ TestStatsStream()
+ : eos_signaled_(0),
+ updates_written_(0),
+ entries_count_(0),
+ entries_size_(0),
+ intervals_count_(0),
+ first_interval_index_(-1) { }
+ TestStatsStream(const TestStatsStream& stream)
+ : v8::OutputStream(stream),
+ eos_signaled_(stream.eos_signaled_),
+ updates_written_(stream.updates_written_),
+ entries_count_(stream.entries_count_),
+ entries_size_(stream.entries_size_),
+ intervals_count_(stream.intervals_count_),
+ first_interval_index_(stream.first_interval_index_) { }
+ virtual ~TestStatsStream() {}
+ virtual void EndOfStream() { ++eos_signaled_; }
+ virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
+ ASSERT(false);
+ return kAbort;
+ }
+ virtual WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* buffer,
+ int updates_written) {
+ ++intervals_count_;
+ ASSERT(updates_written);
+ updates_written_ += updates_written;
+ entries_count_ = 0;
+ if (first_interval_index_ == -1 && updates_written != 0)
+ first_interval_index_ = buffer[0].index;
+ for (int i = 0; i < updates_written; ++i) {
+ entries_count_ += buffer[i].count;
+ entries_size_ += buffer[i].size;
+ }
+
+ return kContinue;
+ }
+ int eos_signaled() { return eos_signaled_; }
+ int updates_written() { return updates_written_; }
+ uint32_t entries_count() const { return entries_count_; }
+ uint32_t entries_size() const { return entries_size_; }
+ int intervals_count() const { return intervals_count_; }
+ int first_interval_index() const { return first_interval_index_; }
+
+ private:
+ int eos_signaled_;
+ int updates_written_;
+ uint32_t entries_count_;
+ uint32_t entries_size_;
+ int intervals_count_;
+ int first_interval_index_;
+};
+
+} // namespace
+
+static TestStatsStream GetHeapStatsUpdate() {
+ TestStatsStream stream;
+ v8::HeapProfiler::PushHeapObjectsStats(&stream);
+ CHECK_EQ(1, stream.eos_signaled());
+ return stream;
+}
+
+
+TEST(HeapSnapshotObjectsStats) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ v8::HeapProfiler::StartHeapObjectsTracking();
+ // We have to call GC 5 times. In other case the garbage will be
+ // the reason of flakiness.
+ for (int i = 0; i < 5; ++i) {
+ HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+ }
+
+ {
+ // Single chunk of data expected in update. Initial data.
+ TestStatsStream stats_update = GetHeapStatsUpdate();
+ CHECK_EQ(1, stats_update.intervals_count());
+ CHECK_EQ(1, stats_update.updates_written());
+ CHECK_LT(0, stats_update.entries_size());
+ CHECK_EQ(0, stats_update.first_interval_index());
+ }
+
+ // No data expected in update because nothing has happened.
+ CHECK_EQ(0, GetHeapStatsUpdate().updates_written());
+ {
+ v8::HandleScope inner_scope_1;
+ v8_str("string1");
+ {
+ // Single chunk of data with one new entry expected in update.
+ TestStatsStream stats_update = GetHeapStatsUpdate();
+ CHECK_EQ(1, stats_update.intervals_count());
+ CHECK_EQ(1, stats_update.updates_written());
+ CHECK_LT(0, stats_update.entries_size());
+ CHECK_EQ(1, stats_update.entries_count());
+ CHECK_EQ(2, stats_update.first_interval_index());
+ }
+
+ // No data expected in update because nothing happened.
+ CHECK_EQ(0, GetHeapStatsUpdate().updates_written());
+
+ {
+ v8::HandleScope inner_scope_2;
+ v8_str("string2");
+
+ uint32_t entries_size;
+ {
+ v8::HandleScope inner_scope_3;
+ v8_str("string3");
+ v8_str("string4");
+
+ {
+ // Single chunk of data with three new entries expected in update.
+ TestStatsStream stats_update = GetHeapStatsUpdate();
+ CHECK_EQ(1, stats_update.intervals_count());
+ CHECK_EQ(1, stats_update.updates_written());
+ CHECK_LT(0, entries_size = stats_update.entries_size());
+ CHECK_EQ(3, stats_update.entries_count());
+ CHECK_EQ(4, stats_update.first_interval_index());
+ }
+ }
+
+ {
+ // Single chunk of data with two left entries expected in update.
+ TestStatsStream stats_update = GetHeapStatsUpdate();
+ CHECK_EQ(1, stats_update.intervals_count());
+ CHECK_EQ(1, stats_update.updates_written());
+ CHECK_GT(entries_size, stats_update.entries_size());
+ CHECK_EQ(1, stats_update.entries_count());
+ // Two strings from forth interval were released.
+ CHECK_EQ(4, stats_update.first_interval_index());
+ }
+ }
+
+ {
+ // Single chunk of data with 0 left entries expected in update.
+ TestStatsStream stats_update = GetHeapStatsUpdate();
+ CHECK_EQ(1, stats_update.intervals_count());
+ CHECK_EQ(1, stats_update.updates_written());
+ CHECK_EQ(0, stats_update.entries_size());
+ CHECK_EQ(0, stats_update.entries_count());
+ // The last string from forth interval was released.
+ CHECK_EQ(4, stats_update.first_interval_index());
+ }
+ }
+ {
+ // Single chunk of data with 0 left entries expected in update.
+ TestStatsStream stats_update = GetHeapStatsUpdate();
+ CHECK_EQ(1, stats_update.intervals_count());
+ CHECK_EQ(1, stats_update.updates_written());
+ CHECK_EQ(0, stats_update.entries_size());
+ CHECK_EQ(0, stats_update.entries_count());
+ // The only string from the second interval was released.
+ CHECK_EQ(2, stats_update.first_interval_index());
+ }
+
+ v8::Local<v8::Array> array = v8::Array::New();
+ CHECK_EQ(0, array->Length());
+ // Force array's buffer allocation.
+ array->Set(2, v8_num(7));
+
+ uint32_t entries_size;
+ {
+ // Single chunk of data with 2 entries expected in update.
+ TestStatsStream stats_update = GetHeapStatsUpdate();
+ CHECK_EQ(1, stats_update.intervals_count());
+ CHECK_EQ(1, stats_update.updates_written());
+ CHECK_LT(0, entries_size = stats_update.entries_size());
+ // They are the array and its buffer.
+ CHECK_EQ(2, stats_update.entries_count());
+ CHECK_EQ(8, stats_update.first_interval_index());
+ }
+
+ for (int i = 0; i < 100; ++i)
+ array->Set(i, v8_num(i));
+
+ {
+ // Single chunk of data with 1 entry expected in update.
+ TestStatsStream stats_update = GetHeapStatsUpdate();
+ CHECK_EQ(1, stats_update.intervals_count());
+ // The first interval was changed because old buffer was collected.
+ // The second interval was changed because new buffer was allocated.
+ CHECK_EQ(2, stats_update.updates_written());
+ CHECK_LT(entries_size, stats_update.entries_size());
+ CHECK_EQ(2, stats_update.entries_count());
+ CHECK_EQ(8, stats_update.first_interval_index());
+ }
+
+ v8::HeapProfiler::StopHeapObjectsTracking();
+}
+
static void CheckChildrenIds(const v8::HeapSnapshot* snapshot,
const v8::HeapGraphNode* node,
@@ -735,6 +913,42 @@ TEST(HeapSnapshotGetNodeById) {
}
+TEST(HeapSnapshotGetSnapshotObjectId) {
+ v8::HandleScope scope;
+ LocalContext env;
+ CompileRun("globalObject = {};\n");
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8_str("get_snapshot_object_id"));
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+ const v8::HeapGraphNode* global_object =
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "globalObject");
+ CHECK(global_object);
+
+ v8::Local<v8::Value> globalObjectHandle =
+ env->Global()->Get(v8::String::New("globalObject"));
+ CHECK(!globalObjectHandle.IsEmpty());
+ CHECK(globalObjectHandle->IsObject());
+
+ v8::SnapshotObjectId id =
+ v8::HeapProfiler::GetSnapshotObjectId(globalObjectHandle);
+ CHECK_NE(static_cast<int>(v8::HeapProfiler::kUnknownObjectId),
+ id);
+ CHECK_EQ(static_cast<int>(id), global_object->GetId());
+}
+
+
+TEST(HeapSnapshotUnknownSnapshotObjectId) {
+ v8::HandleScope scope;
+ LocalContext env;
+ CompileRun("globalObject = {};\n");
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8_str("unknown_object_id"));
+ const v8::HeapGraphNode* node =
+ snapshot->GetNodeById(v8::HeapProfiler::kUnknownObjectId);
+ CHECK_EQ(NULL, node);
+}
+
+
namespace {
class TestActivityControl : public v8::ActivityControl {
@@ -973,9 +1187,8 @@ TEST(HeapSnapshotImplicitReferences) {
v8::HeapProfiler::TakeSnapshot(v8_str("implicit_refs"));
const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot);
- // Use kShortcut type to skip intermediate JSGlobalPropertyCell
const v8::HeapGraphNode* obj0 = GetProperty(
- global_object, v8::HeapGraphEdge::kShortcut, "root_object");
+ global_object, v8::HeapGraphEdge::kProperty, "root_object");
CHECK(obj0);
CHECK_EQ(v8::HeapGraphNode::kObject, obj0->GetType());
const v8::HeapGraphNode* obj1 = GetProperty(
@@ -1148,7 +1361,7 @@ TEST(GetHeapValue) {
env->Global()->GetPrototype().As<v8::Object>();
CHECK(js_global == global->GetHeapValue());
const v8::HeapGraphNode* obj = GetProperty(
- global, v8::HeapGraphEdge::kShortcut, "a");
+ global, v8::HeapGraphEdge::kProperty, "a");
CHECK(obj->GetHeapValue()->IsObject());
v8::Local<v8::Object> js_obj = js_global->Get(v8_str("a")).As<v8::Object>();
CHECK(js_obj == obj->GetHeapValue());
@@ -1177,7 +1390,7 @@ TEST(GetHeapValueForDeletedObject) {
v8::HeapProfiler::TakeSnapshot(v8_str("snapshot"));
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
const v8::HeapGraphNode* obj = GetProperty(
- global, v8::HeapGraphEdge::kShortcut, "a");
+ global, v8::HeapGraphEdge::kProperty, "a");
const v8::HeapGraphNode* prop = GetProperty(
obj, v8::HeapGraphEdge::kProperty, "p");
{
@@ -1264,7 +1477,7 @@ TEST(FastCaseGetter) {
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
CHECK_NE(NULL, global);
const v8::HeapGraphNode* obj1 =
- GetProperty(global, v8::HeapGraphEdge::kShortcut, "obj1");
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
CHECK_NE(NULL, obj1);
const v8::HeapGraphNode* getterFunction =
GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get-propWithGetter");
@@ -1346,7 +1559,7 @@ TEST(SfiAndJsFunctionWeakRefs) {
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
CHECK_NE(NULL, global);
const v8::HeapGraphNode* fun =
- GetProperty(global, v8::HeapGraphEdge::kShortcut, "fun");
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "fun");
CHECK(HasWeakEdge(fun));
const v8::HeapGraphNode* shared =
GetProperty(fun, v8::HeapGraphEdge::kInternal, "shared");
@@ -1354,6 +1567,30 @@ TEST(SfiAndJsFunctionWeakRefs) {
}
+TEST(NoDebugObjectInSnapshot) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ v8::internal::Isolate::Current()->debug()->Load();
+ CompileRun("foo = {};");
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8_str("snapshot"));
+ const v8::HeapGraphNode* root = snapshot->GetRoot();
+ int globals_count = 0;
+ for (int i = 0; i < root->GetChildrenCount(); ++i) {
+ const v8::HeapGraphEdge* edge = root->GetChild(i);
+ if (edge->GetType() == v8::HeapGraphEdge::kShortcut) {
+ ++globals_count;
+ const v8::HeapGraphNode* global = edge->GetToNode();
+ const v8::HeapGraphNode* foo =
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "foo");
+ CHECK_NE(NULL, foo);
+ }
+ }
+ CHECK_EQ(1, globals_count);
+}
+
+
TEST(PersistentHandleCount) {
v8::HandleScope scope;
LocalContext env;
@@ -1386,3 +1623,44 @@ TEST(PersistentHandleCount) {
p_BBB.Dispose();
CHECK_EQ(global_handle_count, v8::HeapProfiler::GetPersistentHandleCount());
}
+
+
+TEST(AllStrongGcRootsHaveNames) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ CompileRun("foo = {};");
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8_str("snapshot"));
+ const v8::HeapGraphNode* gc_roots = GetNode(
+ snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)");
+ CHECK_NE(NULL, gc_roots);
+ const v8::HeapGraphNode* strong_roots = GetNode(
+ gc_roots, v8::HeapGraphNode::kObject, "(Strong roots)");
+ CHECK_NE(NULL, strong_roots);
+ for (int i = 0; i < strong_roots->GetChildrenCount(); ++i) {
+ const v8::HeapGraphEdge* edge = strong_roots->GetChild(i);
+ CHECK_EQ(v8::HeapGraphEdge::kInternal, edge->GetType());
+ v8::String::AsciiValue name(edge->GetName());
+ CHECK(isalpha(**name));
+ }
+}
+
+
+TEST(NoRefsToNonEssentialEntries) {
+ v8::HandleScope scope;
+ LocalContext env;
+ CompileRun("global_object = {};\n");
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8_str("snapshot"));
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+ const v8::HeapGraphNode* global_object =
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "global_object");
+ CHECK_NE(NULL, global_object);
+ const v8::HeapGraphNode* properties =
+ GetProperty(global_object, v8::HeapGraphEdge::kInternal, "properties");
+ CHECK_EQ(NULL, properties);
+ const v8::HeapGraphNode* elements =
+ GetProperty(global_object, v8::HeapGraphEdge::kInternal, "elements");
+ CHECK_EQ(NULL, elements);
+}
diff --git a/src/3rdparty/v8/test/cctest/test-heap.cc b/src/3rdparty/v8/test/cctest/test-heap.cc
index 2904e66..d4a40bf 100644
--- a/src/3rdparty/v8/test/cctest/test-heap.cc
+++ b/src/3rdparty/v8/test/cctest/test-heap.cc
@@ -9,7 +9,6 @@
#include "macro-assembler.h"
#include "global-handles.h"
#include "cctest.h"
-#include "snapshot.h"
using namespace v8::internal;
@@ -1215,7 +1214,9 @@ TEST(TestSizeOfObjects) {
// The heap size should go back to initial size after a full GC, even
// though sweeping didn't finish yet.
HEAP->CollectAllGarbage(Heap::kNoGCFlags);
- CHECK(!HEAP->old_pointer_space()->IsSweepingComplete());
+
+ // Normally sweeping would not be complete here, but no guarantees.
+
CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
// Advancing the sweeper step-wise should not change the heap size.
@@ -1276,6 +1277,13 @@ TEST(GrowAndShrinkNewSpace) {
InitializeVM();
NewSpace* new_space = HEAP->new_space();
+ if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
+ // The max size cannot exceed the reserved size, since semispaces must be
+ // always within the reserved space. We can't test new space growing and
+ // shrinking if the reserved size is the same as the minimum (initial) size.
+ return;
+ }
+
// Explicitly growing should double the space capacity.
intptr_t old_capacity, new_capacity;
old_capacity = new_space->Capacity();
@@ -1316,6 +1324,14 @@ TEST(GrowAndShrinkNewSpace) {
TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
InitializeVM();
+
+ if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
+ // The max size cannot exceed the reserved size, since semispaces must be
+ // always within the reserved space. We can't test new space growing and
+ // shrinking if the reserved size is the same as the minimum (initial) size.
+ return;
+ }
+
v8::HandleScope scope;
NewSpace* new_space = HEAP->new_space();
intptr_t old_capacity, new_capacity;
@@ -1344,14 +1360,13 @@ static int NumberOfGlobalObjects() {
// optimized code.
TEST(LeakGlobalContextViaMap) {
i::FLAG_allow_natives_syntax = true;
- bool snapshot_enabled = i::Snapshot::IsEnabled();
v8::HandleScope outer_scope;
v8::Persistent<v8::Context> ctx1 = v8::Context::New();
v8::Persistent<v8::Context> ctx2 = v8::Context::New();
ctx1->Enter();
HEAP->CollectAllAvailableGarbage();
- CHECK_EQ((snapshot_enabled ? 6 : 4), NumberOfGlobalObjects());
+ CHECK_EQ(4, NumberOfGlobalObjects());
{
v8::HandleScope inner_scope;
@@ -1371,7 +1386,7 @@ TEST(LeakGlobalContextViaMap) {
ctx1.Dispose();
}
HEAP->CollectAllAvailableGarbage();
- CHECK_EQ((snapshot_enabled ? 3 : 2), NumberOfGlobalObjects());
+ CHECK_EQ(2, NumberOfGlobalObjects());
ctx2.Dispose();
HEAP->CollectAllAvailableGarbage();
CHECK_EQ(0, NumberOfGlobalObjects());
@@ -1382,14 +1397,13 @@ TEST(LeakGlobalContextViaMap) {
// optimized code.
TEST(LeakGlobalContextViaFunction) {
i::FLAG_allow_natives_syntax = true;
- bool snapshot_enabled = i::Snapshot::IsEnabled();
v8::HandleScope outer_scope;
v8::Persistent<v8::Context> ctx1 = v8::Context::New();
v8::Persistent<v8::Context> ctx2 = v8::Context::New();
ctx1->Enter();
HEAP->CollectAllAvailableGarbage();
- CHECK_EQ((snapshot_enabled ? 6 : 4), NumberOfGlobalObjects());
+ CHECK_EQ(4, NumberOfGlobalObjects());
{
v8::HandleScope inner_scope;
@@ -1409,7 +1423,7 @@ TEST(LeakGlobalContextViaFunction) {
ctx1.Dispose();
}
HEAP->CollectAllAvailableGarbage();
- CHECK_EQ((snapshot_enabled ? 3 : 2), NumberOfGlobalObjects());
+ CHECK_EQ(2, NumberOfGlobalObjects());
ctx2.Dispose();
HEAP->CollectAllAvailableGarbage();
CHECK_EQ(0, NumberOfGlobalObjects());
@@ -1418,14 +1432,13 @@ TEST(LeakGlobalContextViaFunction) {
TEST(LeakGlobalContextViaMapKeyed) {
i::FLAG_allow_natives_syntax = true;
- bool snapshot_enabled = i::Snapshot::IsEnabled();
v8::HandleScope outer_scope;
v8::Persistent<v8::Context> ctx1 = v8::Context::New();
v8::Persistent<v8::Context> ctx2 = v8::Context::New();
ctx1->Enter();
HEAP->CollectAllAvailableGarbage();
- CHECK_EQ((snapshot_enabled ? 6 : 4), NumberOfGlobalObjects());
+ CHECK_EQ(4, NumberOfGlobalObjects());
{
v8::HandleScope inner_scope;
@@ -1445,7 +1458,7 @@ TEST(LeakGlobalContextViaMapKeyed) {
ctx1.Dispose();
}
HEAP->CollectAllAvailableGarbage();
- CHECK_EQ((snapshot_enabled ? 3 : 2), NumberOfGlobalObjects());
+ CHECK_EQ(2, NumberOfGlobalObjects());
ctx2.Dispose();
HEAP->CollectAllAvailableGarbage();
CHECK_EQ(0, NumberOfGlobalObjects());
@@ -1454,14 +1467,13 @@ TEST(LeakGlobalContextViaMapKeyed) {
TEST(LeakGlobalContextViaMapProto) {
i::FLAG_allow_natives_syntax = true;
- bool snapshot_enabled = i::Snapshot::IsEnabled();
v8::HandleScope outer_scope;
v8::Persistent<v8::Context> ctx1 = v8::Context::New();
v8::Persistent<v8::Context> ctx2 = v8::Context::New();
ctx1->Enter();
HEAP->CollectAllAvailableGarbage();
- CHECK_EQ((snapshot_enabled ? 6 : 4), NumberOfGlobalObjects());
+ CHECK_EQ(4, NumberOfGlobalObjects());
{
v8::HandleScope inner_scope;
@@ -1485,7 +1497,7 @@ TEST(LeakGlobalContextViaMapProto) {
ctx1.Dispose();
}
HEAP->CollectAllAvailableGarbage();
- CHECK_EQ((snapshot_enabled ? 3 : 2), NumberOfGlobalObjects());
+ CHECK_EQ(2, NumberOfGlobalObjects());
ctx2.Dispose();
HEAP->CollectAllAvailableGarbage();
CHECK_EQ(0, NumberOfGlobalObjects());
@@ -1639,6 +1651,15 @@ TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
while (!marking->IsStopped() && !marking->IsComplete()) {
marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
}
+ if (!marking->IsStopped() || marking->should_hurry()) {
+ // We don't normally finish a GC via Step(), we normally finish by
+ // setting the stack guard and then do the final steps in the stack
+ // guard interrupt. But here we didn't ask for that, and there is no
+ // JS code running to trigger the interrupt, so we explicitly finalize
+ // here.
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags,
+ "Test finalizing incremental mark-sweep");
+ }
CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
CHECK_EQ(0, f->shared()->opt_count());
@@ -1714,3 +1735,60 @@ TEST(OptimizedAllocationAlwaysInNewSpace) {
CHECK(HEAP->InNewSpace(*o));
}
+
+
+static int CountMapTransitions(Map* map) {
+ int result = 0;
+ DescriptorArray* descs = map->instance_descriptors();
+ for (int i = 0; i < descs->number_of_descriptors(); i++) {
+ if (descs->IsTransitionOnly(i)) {
+ result++;
+ }
+ }
+ return result;
+}
+
+
+// Test that map transitions are cleared and maps are collected with
+// incremental marking as well.
+TEST(Regress1465) {
+ i::FLAG_allow_natives_syntax = true;
+ i::FLAG_trace_incremental_marking = true;
+ InitializeVM();
+ v8::HandleScope scope;
+
+ #define TRANSITION_COUNT 256
+ for (int i = 0; i < TRANSITION_COUNT; i++) {
+ EmbeddedVector<char, 64> buffer;
+ OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
+ CompileRun(buffer.start());
+ }
+ CompileRun("var root = new Object;");
+ Handle<JSObject> root =
+ v8::Utils::OpenHandle(
+ *v8::Handle<v8::Object>::Cast(
+ v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
+
+ // Count number of live transitions before marking.
+ int transitions_before = CountMapTransitions(root->map());
+ CompileRun("%DebugPrint(root);");
+ CHECK_EQ(TRANSITION_COUNT, transitions_before);
+
+ // Go through all incremental marking steps in one swoop.
+ IncrementalMarking* marking = HEAP->incremental_marking();
+ CHECK(marking->IsStopped());
+ marking->Start();
+ CHECK(marking->IsMarking());
+ while (!marking->IsComplete()) {
+ marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
+ }
+ CHECK(marking->IsComplete());
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+ CHECK(marking->IsStopped());
+
+ // Count number of live transitions after marking. Note that one transition
+ // is left, because 'o' still holds an instance of one transition target.
+ int transitions_after = CountMapTransitions(root->map());
+ CompileRun("%DebugPrint(root);");
+ CHECK_EQ(1, transitions_after);
+}
diff --git a/src/3rdparty/v8/test/cctest/test-list.cc b/src/3rdparty/v8/test/cctest/test-list.cc
index 7520b05..4c78f02 100644
--- a/src/3rdparty/v8/test/cctest/test-list.cc
+++ b/src/3rdparty/v8/test/cctest/test-list.cc
@@ -130,6 +130,18 @@ TEST(RemoveLast) {
}
+TEST(Allocate) {
+ List<int> list(4);
+ list.Add(1);
+ CHECK_EQ(1, list.length());
+ list.Allocate(100);
+ CHECK_EQ(100, list.length());
+ CHECK_LE(100, list.capacity());
+ list[99] = 123;
+ CHECK_EQ(123, list[99]);
+}
+
+
TEST(Clear) {
List<int> list(4);
CHECK_EQ(0, list.length());
diff --git a/src/3rdparty/v8/test/cctest/test-mark-compact.cc b/src/3rdparty/v8/test/cctest/test-mark-compact.cc
index 83a576d..700f322 100644
--- a/src/3rdparty/v8/test/cctest/test-mark-compact.cc
+++ b/src/3rdparty/v8/test/cctest/test-mark-compact.cc
@@ -540,7 +540,7 @@ TEST(BootUpMemoryUse) {
}
} else {
if (v8::internal::Snapshot::IsEnabled()) {
- CHECK_LE(booted_memory - initial_memory, 2600 * 1024); // 2484.
+ CHECK_LE(booted_memory - initial_memory, 2800 * 1024); // 2484.
} else {
CHECK_LE(booted_memory - initial_memory, 2950 * 1024); // 2844
}
diff --git a/src/3rdparty/v8/test/cctest/test-regexp.cc b/src/3rdparty/v8/test/cctest/test-regexp.cc
index 54898a0..e89e6cd 100644
--- a/src/3rdparty/v8/test/cctest/test-regexp.cc
+++ b/src/3rdparty/v8/test/cctest/test-regexp.cc
@@ -1590,7 +1590,7 @@ TEST(CharClassDifference) {
ZoneScope zone_scope(Isolate::Current(), DELETE_ON_EXIT);
ZoneList<CharacterRange>* base = new ZoneList<CharacterRange>(1);
base->Add(CharacterRange::Everything());
- Vector<const uc16> overlay = CharacterRange::GetWordBounds();
+ Vector<const int> overlay = CharacterRange::GetWordBounds();
ZoneList<CharacterRange>* included = NULL;
ZoneList<CharacterRange>* excluded = NULL;
CharacterRange::Split(base, overlay, &included, &excluded);
@@ -1599,7 +1599,7 @@ TEST(CharClassDifference) {
if (in_base) {
bool in_overlay = false;
for (int j = 0; !in_overlay && j < overlay.length(); j += 2) {
- if (overlay[j] <= i && i <= overlay[j+1])
+ if (overlay[j] <= i && i < overlay[j+1])
in_overlay = true;
}
CHECK_EQ(in_overlay, InClass(i, included));
@@ -1672,16 +1672,6 @@ TEST(CanonicalizeCharacterSets) {
ASSERT_EQ(30, list->at(0).to());
}
-// Checks whether a character is in the set represented by a list of ranges.
-static bool CharacterInSet(ZoneList<CharacterRange>* set, uc16 value) {
- for (int i = 0; i < set->length(); i++) {
- CharacterRange range = set->at(i);
- if (range.from() <= value && value <= range.to()) {
- return true;
- }
- }
- return false;
-}
TEST(CharacterRangeMerge) {
v8::internal::V8::Initialize(NULL);
@@ -1768,67 +1758,6 @@ TEST(CharacterRangeMerge) {
ZoneList<CharacterRange> first_only(4);
ZoneList<CharacterRange> second_only(4);
ZoneList<CharacterRange> both(4);
-
- // Merge one direction.
- CharacterRange::Merge(&l1, &l2, &first_only, &second_only, &both);
-
- CHECK(CharacterRange::IsCanonical(&first_only));
- CHECK(CharacterRange::IsCanonical(&second_only));
- CHECK(CharacterRange::IsCanonical(&both));
-
- for (uc16 i = 0; i < offset; i++) {
- bool in_first = CharacterInSet(&l1, i);
- bool in_second = CharacterInSet(&l2, i);
- CHECK((in_first && !in_second) == CharacterInSet(&first_only, i));
- CHECK((!in_first && in_second) == CharacterInSet(&second_only, i));
- CHECK((in_first && in_second) == CharacterInSet(&both, i));
- }
-
- first_only.Clear();
- second_only.Clear();
- both.Clear();
-
- // Merge other direction.
- CharacterRange::Merge(&l2, &l1, &second_only, &first_only, &both);
-
- CHECK(CharacterRange::IsCanonical(&first_only));
- CHECK(CharacterRange::IsCanonical(&second_only));
- CHECK(CharacterRange::IsCanonical(&both));
-
- for (uc16 i = 0; i < offset; i++) {
- bool in_first = CharacterInSet(&l1, i);
- bool in_second = CharacterInSet(&l2, i);
- CHECK((in_first && !in_second) == CharacterInSet(&first_only, i));
- CHECK((!in_first && in_second) == CharacterInSet(&second_only, i));
- CHECK((in_first && in_second) == CharacterInSet(&both, i));
- }
-
- first_only.Clear();
- second_only.Clear();
- both.Clear();
-
- // Merge but don't record all combinations.
- CharacterRange::Merge(&l1, &l2, NULL, NULL, &both);
-
- CHECK(CharacterRange::IsCanonical(&both));
-
- for (uc16 i = 0; i < offset; i++) {
- bool in_first = CharacterInSet(&l1, i);
- bool in_second = CharacterInSet(&l2, i);
- CHECK((in_first && in_second) == CharacterInSet(&both, i));
- }
-
- // Merge into same set.
- ZoneList<CharacterRange> all(4);
- CharacterRange::Merge(&l1, &l2, &all, &all, &all);
-
- CHECK(CharacterRange::IsCanonical(&all));
-
- for (uc16 i = 0; i < offset; i++) {
- bool in_first = CharacterInSet(&l1, i);
- bool in_second = CharacterInSet(&l2, i);
- CHECK((in_first || in_second) == CharacterInSet(&all, i));
- }
}
diff --git a/src/3rdparty/v8/test/cctest/test-strings.cc b/src/3rdparty/v8/test/cctest/test-strings.cc
index e2a179f..d86886f 100644
--- a/src/3rdparty/v8/test/cctest/test-strings.cc
+++ b/src/3rdparty/v8/test/cctest/test-strings.cc
@@ -620,3 +620,55 @@ TEST(AsciiArrayJoin) {
CHECK(result.IsEmpty());
CHECK(context->HasOutOfMemoryException());
}
+
+
+static void CheckException(const char* source) {
+ // An empty handle is returned upon exception.
+ CHECK(CompileRun(source).IsEmpty());
+}
+
+
+TEST(RobustSubStringStub) {
+ // This tests whether the SubStringStub can handle unsafe arguments.
+ // If not recognized, those unsafe arguments lead to out-of-bounds reads.
+ FLAG_allow_natives_syntax = true;
+ InitializeVM();
+ HandleScope scope;
+ v8::Local<v8::Value> result;
+ Handle<String> string;
+ CompileRun("var short = 'abcdef';");
+
+ // Invalid indices.
+ CheckException("%_SubString(short, 0, 10000);");
+ CheckException("%_SubString(short, -1234, 5);");
+ CheckException("%_SubString(short, 5, 2);");
+ // Special HeapNumbers.
+ CheckException("%_SubString(short, 1, Infinity);");
+ CheckException("%_SubString(short, NaN, 5);");
+ // String arguments.
+ CheckException("%_SubString(short, '2', '5');");
+ // Ordinary HeapNumbers can be handled (in runtime).
+ result = CompileRun("%_SubString(short, Math.sqrt(4), 5.1);");
+ string = v8::Utils::OpenHandle(v8::String::Cast(*result));
+ CHECK_EQ("cde", *(string->ToCString()));
+
+ CompileRun("var long = 'abcdefghijklmnopqrstuvwxyz';");
+ // Invalid indices.
+ CheckException("%_SubString(long, 0, 10000);");
+ CheckException("%_SubString(long, -1234, 17);");
+ CheckException("%_SubString(long, 17, 2);");
+ // Special HeapNumbers.
+ CheckException("%_SubString(long, 1, Infinity);");
+ CheckException("%_SubString(long, NaN, 17);");
+ // String arguments.
+ CheckException("%_SubString(long, '2', '17');");
+ // Ordinary HeapNumbers within bounds can be handled (in runtime).
+ result = CompileRun("%_SubString(long, Math.sqrt(4), 17.1);");
+ string = v8::Utils::OpenHandle(v8::String::Cast(*result));
+ CHECK_EQ("cdefghijklmnopq", *(string->ToCString()));
+
+ // Test that out-of-bounds substring of a slice fails when the indices
+ // would have been valid for the underlying string.
+ CompileRun("var slice = long.slice(1, 15);");
+ CheckException("%_SubString(slice, 0, 17);");
+}
diff --git a/src/3rdparty/v8/test/cctest/test-weakmaps.cc b/src/3rdparty/v8/test/cctest/test-weakmaps.cc
index 56d5936..7bba7b6 100644
--- a/src/3rdparty/v8/test/cctest/test-weakmaps.cc
+++ b/src/3rdparty/v8/test/cctest/test-weakmaps.cc
@@ -48,11 +48,11 @@ static Handle<JSWeakMap> AllocateJSWeakMap() {
static void PutIntoWeakMap(Handle<JSWeakMap> weakmap,
Handle<JSObject> key,
- int value) {
+ Handle<Object> value) {
Handle<ObjectHashTable> table = PutIntoObjectHashTable(
Handle<ObjectHashTable>(ObjectHashTable::cast(weakmap->table())),
Handle<JSObject>(JSObject::cast(*key)),
- Handle<Smi>(Smi::FromInt(value)));
+ value);
weakmap->set_table(*table);
}
@@ -65,6 +65,7 @@ static void WeakPointerCallback(v8::Persistent<v8::Value> handle, void* id) {
TEST(Weakness) {
+ FLAG_incremental_marking = false;
LocalContext context;
v8::HandleScope scope;
Handle<JSWeakMap> weakmap = AllocateJSWeakMap();
@@ -83,7 +84,9 @@ TEST(Weakness) {
// Put entry into weak map.
{
v8::HandleScope scope;
- PutIntoWeakMap(weakmap, Handle<JSObject>(JSObject::cast(*key)), 23);
+ PutIntoWeakMap(weakmap,
+ Handle<JSObject>(JSObject::cast(*key)),
+ Handle<Smi>(Smi::FromInt(23)));
}
CHECK_EQ(1, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
@@ -133,7 +136,7 @@ TEST(Shrinking) {
Handle<Map> map = FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
for (int i = 0; i < 32; i++) {
Handle<JSObject> object = FACTORY->NewJSObjectFromMap(map);
- PutIntoWeakMap(weakmap, object, i);
+ PutIntoWeakMap(weakmap, object, Handle<Smi>(Smi::FromInt(i)));
}
}
@@ -152,3 +155,72 @@ TEST(Shrinking) {
// Check shrunk capacity.
CHECK_EQ(32, ObjectHashTable::cast(weakmap->table())->Capacity());
}
+
+
+// Test that weak map values on an evacuation candidate which are not reachable
+// by other paths are correctly recorded in the slots buffer.
+TEST(Regress2060a) {
+ FLAG_always_compact = true;
+ LocalContext context;
+ v8::HandleScope scope;
+ Handle<JSFunction> function =
+ FACTORY->NewFunction(FACTORY->function_symbol(), FACTORY->null_value());
+ Handle<JSObject> key = FACTORY->NewJSObject(function);
+ Handle<JSWeakMap> weakmap = AllocateJSWeakMap();
+
+ // 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);
+
+ // Fill up weak map with values on an evacuation candidate.
+ {
+ v8::HandleScope scope;
+ for (int i = 0; i < 32; i++) {
+ Handle<JSObject> object = FACTORY->NewJSObject(function, TENURED);
+ CHECK(!HEAP->InNewSpace(object->address()));
+ CHECK(!first_page->Contains(object->address()));
+ PutIntoWeakMap(weakmap, key, object);
+ }
+ }
+
+ // Force compacting garbage collection.
+ CHECK(FLAG_always_compact);
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+}
+
+
+// Test that weak map keys on an evacuation candidate which are reachable by
+// other strong paths are correctly recorded in the slots buffer.
+TEST(Regress2060b) {
+ FLAG_always_compact = true;
+#ifdef DEBUG
+ FLAG_verify_heap = true;
+#endif
+ LocalContext context;
+ v8::HandleScope scope;
+ Handle<JSFunction> function =
+ FACTORY->NewFunction(FACTORY->function_symbol(), FACTORY->null_value());
+
+ // 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);
+
+ // Fill up weak map with keys on an evacuation candidate.
+ Handle<JSObject> keys[32];
+ for (int i = 0; i < 32; i++) {
+ keys[i] = FACTORY->NewJSObject(function, TENURED);
+ CHECK(!HEAP->InNewSpace(keys[i]->address()));
+ CHECK(!first_page->Contains(keys[i]->address()));
+ }
+ Handle<JSWeakMap> weakmap = AllocateJSWeakMap();
+ for (int i = 0; i < 32; i++) {
+ PutIntoWeakMap(weakmap, keys[i], Handle<Smi>(Smi::FromInt(i)));
+ }
+
+ // Force compacting garbage collection. The subsequent collections are used
+ // to verify that key references were actually updated.
+ CHECK(FLAG_always_compact);
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+}
diff --git a/src/3rdparty/v8/test/cctest/testcfg.py b/src/3rdparty/v8/test/cctest/testcfg.py
index b2eabc4..f1387e8 100644
--- a/src/3rdparty/v8/test/cctest/testcfg.py
+++ b/src/3rdparty/v8/test/cctest/testcfg.py
@@ -53,6 +53,8 @@ class CcTestCase(test.TestCase):
serialization_file = join('obj', 'test', self.mode, 'serdes')
else:
serialization_file = join('obj', 'serdes')
+ if not exists(join(self.context.buildspace, 'obj')):
+ os.makedirs(join(self.context.buildspace, 'obj'))
serialization_file += '_' + self.GetName()
serialization_file = join(self.context.buildspace, serialization_file)
serialization_file += ''.join(self.variant_flags).replace('-', '_')
diff --git a/src/3rdparty/v8/test/mjsunit/array-bounds-check-removal.js b/src/3rdparty/v8/test/mjsunit/array-bounds-check-removal.js
new file mode 100644
index 0000000..81064aa
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/array-bounds-check-removal.js
@@ -0,0 +1,145 @@
+// 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: --allow-natives-syntax --expose-gc
+
+var a = new Int32Array(1024);
+
+function test_base(base,cond) {
+ a[base + 1] = 1;
+ a[base + 4] = 2;
+ a[base + 3] = 3;
+ a[base + 2] = 4;
+ a[base + 4] = base + 4;
+ if (cond) {
+ a[base + 1] = 1;
+ a[base + 2] = 2;
+ a[base + 2] = 3;
+ a[base + 2] = 4;
+ a[base + 4] = base + 4;
+ } else {
+ a[base + 6] = 1;
+ a[base + 4] = 2;
+ a[base + 3] = 3;
+ a[base + 2] = 4;
+ a[base + 4] = base - 4;
+ }
+}
+
+function check_test_base(base,cond) {
+ if (cond) {
+ assertEquals(1, a[base + 1]);
+ assertEquals(4, a[base + 2]);
+ assertEquals(base + 4, a[base + 4]);
+ } else {
+ assertEquals(1, a[base + 6]);
+ assertEquals(3, a[base + 3]);
+ assertEquals(4, a[base + 2]);
+ assertEquals(base - 4, a[base + 4]);
+ }
+}
+
+
+function test_minus(base,cond) {
+ a[base - 1] = 1;
+ a[base - 2] = 2;
+ a[base + 4] = 3;
+ a[base] = 4;
+ a[base + 4] = base + 4;
+ if (cond) {
+ a[base - 4] = 1;
+ a[base + 5] = 2;
+ a[base + 3] = 3;
+ a[base + 2] = 4;
+ a[base + 4] = base + 4;
+ } else {
+ a[base + 6] = 1;
+ a[base + 4] = 2;
+ a[base + 3] = 3;
+ a[base + 2] = 4;
+ a[base + 4] = base - 4;
+ }
+}
+
+function check_test_minus(base,cond) {
+ if (cond) {
+ assertEquals(2, a[base + 5]);
+ assertEquals(3, a[base + 3]);
+ assertEquals(4, a[base + 2]);
+ assertEquals(base + 4, a[base + 4]);
+ } else {
+ assertEquals(1, a[base + 6]);
+ assertEquals(3, a[base + 3]);
+ assertEquals(4, a[base + 2]);
+ assertEquals(base - 4, a[base + 4]);
+ }
+}
+
+test_base(1,true);
+test_base(2,true);
+test_base(1,false);
+test_base(2,false);
+%OptimizeFunctionOnNextCall(test_base);
+test_base(3,true);
+check_test_base(3,true);
+test_base(3,false);
+check_test_base(3,false);
+
+test_minus(5,true);
+test_minus(6,true);
+%OptimizeFunctionOnNextCall(test_minus);
+test_minus(7,true);
+check_test_minus(7,true);
+test_minus(7,false);
+check_test_minus(7,false);
+
+// Optimization status:
+// YES: 1
+// NO: 2
+// ALWAYS: 3
+// NEVER: 4
+
+if (false) {
+test_base(5,true);
+test_base(6,true);
+test_base(5,false);
+test_base(6,false);
+%OptimizeFunctionOnNextCall(test_base);
+test_base(-2,true);
+assertTrue(%GetOptimizationStatus(test_base) != 1);
+
+test_base(5,true);
+test_base(6,true);
+test_base(5,false);
+test_base(6,false);
+%OptimizeFunctionOnNextCall(test_base);
+test_base(2048,true);
+assertTrue(%GetOptimizationStatus(test_base) != 1);
+}
+
+gc();
+
diff --git a/src/3rdparty/v8/test/mjsunit/big-array-literal.js b/src/3rdparty/v8/test/mjsunit/big-array-literal.js
index a0fad7c..8e0ff87 100644
--- a/src/3rdparty/v8/test/mjsunit/big-array-literal.js
+++ b/src/3rdparty/v8/test/mjsunit/big-array-literal.js
@@ -25,6 +25,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// On MacOS, this test needs a stack size of at least 538 kBytes.
+// Flags: --stack-size=600
+
// Test that we can make large object literals that work.
// Also test that we can attempt to make even larger object literals without
// crashing.
diff --git a/src/3rdparty/v8/test/mjsunit/compiler/alloc-object-huge.js b/src/3rdparty/v8/test/mjsunit/compiler/alloc-object-huge.js
index d6d9f1b..0b202f7 100644
--- a/src/3rdparty/v8/test/mjsunit/compiler/alloc-object-huge.js
+++ b/src/3rdparty/v8/test/mjsunit/compiler/alloc-object-huge.js
@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --allow-natives-syntax --inline-construct --nolimit-inlining
+// Flags: --allow-natives-syntax --inline-construct --max-inlined-source-size=999999 --max-inlined-nodes=999999 --max-inlined-nodes-cumulative=999999
// Test that huge constructors (more than 256 this assignments) are
// handled correctly.
diff --git a/src/3rdparty/v8/test/mjsunit/compiler/inline-arguments.js b/src/3rdparty/v8/test/mjsunit/compiler/inline-arguments.js
index b6adf7f..f8a2476 100644
--- a/src/3rdparty/v8/test/mjsunit/compiler/inline-arguments.js
+++ b/src/3rdparty/v8/test/mjsunit/compiler/inline-arguments.js
@@ -113,3 +113,70 @@ F4(1);
%OptimizeFunctionOnNextCall(test_adaptation);
test_adaptation();
})();
+
+// Test arguments access from the inlined function.
+function uninlinable(v) {
+ assertEquals(0, v);
+ try { } catch (e) { }
+ return 0;
+}
+
+function toarr_inner() {
+ var a = arguments;
+ var marker = a[0];
+ uninlinable(uninlinable(0, 0), marker.x);
+
+ var r = new Array();
+ for (var i = a.length - 1; i >= 1; i--) {
+ r.push(a[i]);
+ }
+
+ return r;
+}
+
+function toarr1(marker, a, b, c) {
+ return toarr_inner(marker, a / 2, b / 2, c / 2);
+}
+
+function toarr2(marker, a, b, c) {
+ var x = 0;
+ return uninlinable(uninlinable(0, 0),
+ x = toarr_inner(marker, a / 2, b / 2, c / 2)), x;
+}
+
+function test_toarr(toarr) {
+ var marker = { x: 0 };
+ assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6));
+ assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6));
+ %OptimizeFunctionOnNextCall(toarr);
+ assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6));
+ delete marker.x;
+ assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6));
+}
+
+test_toarr(toarr1);
+test_toarr(toarr2);
+
+// Test that arguments access from inlined function uses correct values.
+(function () {
+ function inner(x, y) {
+ "use strict";
+ x = 10;
+ y = 20;
+ for (var i = 0; i < 1; i++) {
+ for (var j = 1; j <= arguments.length; j++) {
+ return arguments[arguments.length - j];
+ }
+ }
+ }
+
+ function outer(x, y) {
+ return inner(x, y);
+ }
+
+ assertEquals(2, outer(1, 2));
+ assertEquals(2, outer(1, 2));
+ assertEquals(2, outer(1, 2));
+ %OptimizeFunctionOnNextCall(outer);
+ assertEquals(2, outer(1, 2));
+})();
diff --git a/src/3rdparty/v8/test/mjsunit/compiler/inline-construct.js b/src/3rdparty/v8/test/mjsunit/compiler/inline-construct.js
index af9e69c..7a3f1e4 100644
--- a/src/3rdparty/v8/test/mjsunit/compiler/inline-construct.js
+++ b/src/3rdparty/v8/test/mjsunit/compiler/inline-construct.js
@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --allow-natives-syntax --expose-gc --inline-construct
+// Flags: --allow-natives-syntax --inline-construct
// Test inlining of constructor calls.
@@ -68,7 +68,9 @@ function TestInAllContexts(constructor) {
%DeoptimizeFunction(value_context);
%DeoptimizeFunction(test_context);
%DeoptimizeFunction(effect_context);
- gc(); // Makes V8 forget about type information for *_context.
+ %ClearFunctionTypeFeedback(value_context);
+ %ClearFunctionTypeFeedback(test_context);
+ %ClearFunctionTypeFeedback(effect_context);
}
diff --git a/src/3rdparty/v8/test/mjsunit/compiler/literals.js b/src/3rdparty/v8/test/mjsunit/compiler/literals.js
index e910bb3..8607cd9 100644
--- a/src/3rdparty/v8/test/mjsunit/compiler/literals.js
+++ b/src/3rdparty/v8/test/mjsunit/compiler/literals.js
@@ -36,38 +36,38 @@ assertEquals(8, eval("6;'abc';8"));
// Characters just outside the ranges of hex-escapes.
// "/" comes just before "0".
-assertEquals("x1/", "\x1/");
-assertEquals("u111/", "\u111/");
+assertThrows('"\\x1/"');
+assertThrows('"\\u111/"');
assertEquals("\\x1/", RegExp("\\x1/").source);
assertEquals("\\u111/", RegExp("\\u111/").source);
// ":" comes just after "9".
-assertEquals("x1:", "\x1:");
-assertEquals("u111:", "\u111:");
+assertThrows('"\\x1:"');
+assertThrows('"\\u111:"');
assertEquals("\\x1:", /\x1:/.source);
assertEquals("\\u111:", /\u111:/.source);
// "`" comes just before "a".
-assertEquals("x1`", "\x1`");
-assertEquals("u111`", "\u111`");
+assertThrows('"\\x1`"');
+assertThrows('"\\u111`"');
assertEquals("\\x1`", /\x1`/.source);
assertEquals("\\u111`", /\u111`/.source);
// "g" comes just before "f".
-assertEquals("x1g", "\x1g");
-assertEquals("u111g", "\u111g");
+assertThrows('"\\x1g"');
+assertThrows('"\\u111g"');
assertEquals("\\x1g", /\x1g/.source);
assertEquals("\\u111g", /\u111g/.source);
// "@" comes just before "A".
-assertEquals("x1@", "\x1@");
-assertEquals("u111@", "\u111@");
+assertThrows('"\\x1@"');
+assertThrows('"\\u111@"');
assertEquals("\\x1@", /\x1@/.source);
assertEquals("\\u111@", /\u111@/.source);
// "G" comes just after "F".
-assertEquals("x1G", "\x1G");
-assertEquals("u111G", "\u111G");
+assertThrows('"\\x1G"');
+assertThrows('"\\u111G"');
assertEquals("\\x1G", /\x1G/.source);
assertEquals("\\u111G", /\u111G/.source);
diff --git a/src/3rdparty/v8/test/mjsunit/compiler/optimize-bitnot.js b/src/3rdparty/v8/test/mjsunit/compiler/optimize-bitnot.js
new file mode 100644
index 0000000..28315a4
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/compiler/optimize-bitnot.js
@@ -0,0 +1,42 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+function f(x) {
+ return ~~x;
+}
+
+f(42);
+f(42);
+%OptimizeFunctionOnNextCall(f);
+assertEquals(42, f(42));
+assertEquals(42, f(42.5));
+assertEquals(1/0, 1/f(-0));
+assertEquals(-1, f(0xffffffff));
+assertEquals(0, f(undefined));
+assertEquals(0, f("abc"));
diff --git a/src/3rdparty/v8/test/mjsunit/debug-evaluate-locals-optimized-double.js b/src/3rdparty/v8/test/mjsunit/debug-evaluate-locals-optimized-double.js
index cf25c0c..efbb2cc 100644
--- a/src/3rdparty/v8/test/mjsunit/debug-evaluate-locals-optimized-double.js
+++ b/src/3rdparty/v8/test/mjsunit/debug-evaluate-locals-optimized-double.js
@@ -148,20 +148,9 @@ function listener(event, exec_state, event_data, data) {
assertFalse(frame.isConstructCall());
}
- // When function f is optimized (1 means YES, see runtime.cc) we
- // expect an optimized frame for f with g1, g2 and g3 inlined.
- if (%GetOptimizationStatus(f) == 1) {
- if (i == 1 || i == 2 || i == 3) {
- assertTrue(frame.isOptimizedFrame());
- assertTrue(frame.isInlinedFrame());
- assertEquals(4 - i, frame.inlinedFrameIndex());
- } else if (i == 4) {
- assertTrue(frame.isOptimizedFrame());
- assertFalse(frame.isInlinedFrame());
- } else {
- assertFalse(frame.isOptimizedFrame());
- assertFalse(frame.isInlinedFrame());
- }
+ if (i > 4) {
+ assertFalse(frame.isOptimizedFrame());
+ assertFalse(frame.isInlinedFrame());
}
}
diff --git a/src/3rdparty/v8/test/mjsunit/debug-evaluate-locals-optimized.js b/src/3rdparty/v8/test/mjsunit/debug-evaluate-locals-optimized.js
index c88a683..9c56a12 100644
--- a/src/3rdparty/v8/test/mjsunit/debug-evaluate-locals-optimized.js
+++ b/src/3rdparty/v8/test/mjsunit/debug-evaluate-locals-optimized.js
@@ -138,20 +138,9 @@ function listener(event, exec_state, event_data, data) {
assertFalse(frame.isConstructCall());
}
- // When function f is optimized (1 means YES, see runtime.cc) we
- // expect an optimized frame for f with g1, g2 and g3 inlined.
- if (%GetOptimizationStatus(f) == 1) {
- if (i == 1 || i == 2 || i == 3) {
- assertTrue(frame.isOptimizedFrame());
- assertTrue(frame.isInlinedFrame());
- assertEquals(4 - i, frame.inlinedFrameIndex());
- } else if (i == 4) {
- assertTrue(frame.isOptimizedFrame());
- assertFalse(frame.isInlinedFrame());
- } else {
- assertFalse(frame.isOptimizedFrame());
- assertFalse(frame.isInlinedFrame());
- }
+ if (i > 4) {
+ assertFalse(frame.isOptimizedFrame());
+ assertFalse(frame.isInlinedFrame());
}
}
diff --git a/src/3rdparty/v8/test/mjsunit/debug-function-scopes.js b/src/3rdparty/v8/test/mjsunit/debug-function-scopes.js
new file mode 100644
index 0000000..4262b95
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/debug-function-scopes.js
@@ -0,0 +1,162 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+
+// Get the Debug object exposed from the debug context global object.
+var Debug = debug.Debug;
+
+function CheckScope(scope_mirror, scope_expectations, expected_scope_type) {
+ assertEquals(expected_scope_type, scope_mirror.scopeType());
+
+ var scope_object = scope_mirror.scopeObject().value();
+
+ for (var name in scope_expectations) {
+ var actual = scope_object[name];
+ var expected = scope_expectations[name];
+ assertEquals(expected, actual);
+ }
+}
+
+// A copy of the scope types from mirror-debugger.js.
+var ScopeType = { Global: 0,
+ Local: 1,
+ With: 2,
+ Closure: 3,
+ Catch: 4,
+ Block: 5 };
+
+var f1 = (function F1(x) {
+ function F2(y) {
+ var z = x + y;
+ with ({w: 5, v: "Capybara"}) {
+ var F3 = function(a, b) {
+ function F4(p) {
+ return p + a + b + z + w + v.length;
+ }
+ return F4;
+ }
+ return F3(4, 5);
+ }
+ }
+ return F2(17);
+})(5);
+
+var mirror = Debug.MakeMirror(f1);
+
+assertEquals(5, mirror.scopeCount());
+
+CheckScope(mirror.scope(0), { a: 4, b: 5 }, ScopeType.Closure);
+CheckScope(mirror.scope(1), { w: 5, v: "Capybara" }, ScopeType.With);
+CheckScope(mirror.scope(2), { y: 17, z: 22 }, ScopeType.Closure);
+CheckScope(mirror.scope(3), { x: 5 }, ScopeType.Closure);
+CheckScope(mirror.scope(4), {}, ScopeType.Global);
+
+var f2 = function() { return 5; }
+
+var mirror = Debug.MakeMirror(f2);
+
+assertEquals(1, mirror.scopeCount());
+
+CheckScope(mirror.scope(0), {}, ScopeType.Global);
+
+var f3 = (function F1(invisible_parameter) {
+ var invisible1 = 1;
+ var visible1 = 10;
+ return (function F2() {
+ var invisible2 = 2;
+ return (function F3() {
+ var visible2 = 20;
+ var invisible2 = 3;
+ return (function () {return visible1 + visible2 + visible1a;});
+ })();
+ })();
+})(5);
+
+var mirror = Debug.MakeMirror(f3);
+
+assertEquals(3, mirror.scopeCount());
+
+CheckScope(mirror.scope(0), { visible2: 20 }, ScopeType.Closure);
+CheckScope(mirror.scope(1), { visible1: 10 }, ScopeType.Closure);
+CheckScope(mirror.scope(2), {}, ScopeType.Global);
+
+
+var f4 = (function One() {
+ try {
+ throw "I'm error 1";
+ } catch (e1) {
+ try {
+ throw "I'm error 2";
+ } catch (e2) {
+ return function GetError() {
+ return e1 + e2;
+ };
+ }
+ }
+})();
+
+var mirror = Debug.MakeMirror(f4);
+
+assertEquals(3, mirror.scopeCount());
+
+CheckScope(mirror.scope(0), { e2: "I'm error 2" }, ScopeType.Catch);
+CheckScope(mirror.scope(1), { e1: "I'm error 1" }, ScopeType.Catch);
+CheckScope(mirror.scope(2), {}, ScopeType.Global);
+
+
+var f5 = (function Raz(p1, p2) {
+ var p3 = p1 + p2;
+ return (function() {
+ var p4 = 20;
+ var p5 = 21;
+ var p6 = 22;
+ return eval("(function(p7){return p1 + p4 + p6 + p7})");
+ })();
+})(1,2);
+
+var mirror = Debug.MakeMirror(f5);
+
+assertEquals(3, mirror.scopeCount());
+
+CheckScope(mirror.scope(0), { p4: 20, p6: 22 }, ScopeType.Closure);
+CheckScope(mirror.scope(1), { p1: 1 }, ScopeType.Closure);
+CheckScope(mirror.scope(2), {}, ScopeType.Global);
+
+
+function CheckNoScopeVisible(f) {
+ var mirror = Debug.MakeMirror(f);
+ assertEquals(0, mirror.scopeCount());
+}
+
+CheckNoScopeVisible(Number);
+
+CheckNoScopeVisible(Function.toString);
+
+// This getter is known to be implemented as closure.
+CheckNoScopeVisible(new Error().__lookupGetter__("stack"));
+
diff --git a/src/3rdparty/v8/test/mjsunit/debug-liveedit-stack-padding.js b/src/3rdparty/v8/test/mjsunit/debug-liveedit-stack-padding.js
new file mode 100644
index 0000000..36de356
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/debug-liveedit-stack-padding.js
@@ -0,0 +1,88 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+
+Debug = debug.Debug;
+
+SlimFunction = eval(
+ "(function() {\n " +
+ " return 'Cat';\n" +
+ "})\n"
+);
+
+var script = Debug.findScript(SlimFunction);
+
+Debug.setScriptBreakPointById(script.id, 1, 0);
+
+var orig_animal = "'Cat'";
+var patch_pos = script.source.indexOf(orig_animal);
+var new_animal_patch = "'Capybara'";
+
+debugger_handler = (function() {
+ var already_called = false;
+ return function() {
+ if (already_called) {
+ return;
+ }
+ already_called = true;
+
+ var change_log = new Array();
+ try {
+ Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos,
+ orig_animal.length, new_animal_patch, change_log);
+ } finally {
+ print("Change log: " + JSON.stringify(change_log) + "\n");
+ }
+ };
+})();
+
+var saved_exception = null;
+
+function listener(event, exec_state, event_data, data) {
+ if (event == Debug.DebugEvent.Break) {
+ try {
+ debugger_handler();
+ } catch (e) {
+ saved_exception = e;
+ }
+ } else {
+ print("Other: " + event);
+ }
+}
+
+Debug.setListener(listener);
+
+var animal = SlimFunction();
+
+if (saved_exception) {
+ print("Exception: " + saved_exception);
+ assertUnreachable();
+}
+
+assertEquals("Capybara", animal);
diff --git a/src/3rdparty/v8/test/mjsunit/debug-scripts-request.js b/src/3rdparty/v8/test/mjsunit/debug-scripts-request.js
index faa732e..e027563 100644
--- a/src/3rdparty/v8/test/mjsunit/debug-scripts-request.js
+++ b/src/3rdparty/v8/test/mjsunit/debug-scripts-request.js
@@ -78,8 +78,10 @@ function listener(event, exec_state, event_data, data) {
var response = safeEval(dcp.processDebugJSONRequest(request));
assertTrue(response.success);
- // Test filtering by id.
- assertEquals(2, response.body.length);
+ // Test filtering by id. We have to get at least one script back, but
+ // the exact number depends on the timing of GC.
+ assertTrue(response.body.length >= 1);
+
var script = response.body[0];
var request = '{' + base_request + ',"arguments":{"ids":[' +
script.id + ']}}';
diff --git a/src/3rdparty/v8/test/mjsunit/debug-stepin-builtin-callback.js b/src/3rdparty/v8/test/mjsunit/debug-stepin-builtin-callback.js
new file mode 100644
index 0000000..223159d
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/debug-stepin-builtin-callback.js
@@ -0,0 +1,157 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+
+// Test stepping into callbacks passed to builtin functions.
+
+Debug = debug.Debug
+
+var exception = false;
+
+function array_listener(event, exec_state, event_data, data) {
+ try {
+ if (event == Debug.DebugEvent.Break) {
+ if (breaks == 0) {
+ exec_state.prepareStep(Debug.StepAction.StepIn, 2);
+ breaks = 1;
+ } else if (breaks <= 3) {
+ breaks++;
+ // Check whether we break at the expected line.
+ print(event_data.sourceLineText());
+ assertTrue(event_data.sourceLineText().indexOf("Expected to step") > 0);
+ exec_state.prepareStep(Debug.StepAction.StepIn, 3);
+ }
+ }
+ } catch (e) {
+ exception = true;
+ }
+};
+
+function cb_false(num) {
+ print("element " + num); // Expected to step to this point.
+ return false;
+}
+
+function cb_true(num) {
+ print("element " + num); // Expected to step to this point.
+ return true;
+}
+
+function cb_reduce(a, b) {
+ print("elements " + a + " and " + b); // Expected to step to this point.
+ return a + b;
+}
+
+var a = [1, 2, 3, 4];
+
+Debug.setListener(array_listener);
+
+var breaks = 0;
+debugger;
+a.forEach(cb_true);
+assertFalse(exception);
+assertEquals(4, breaks);
+
+breaks = 0;
+debugger;
+a.some(cb_false);
+assertFalse(exception);
+assertEquals(4, breaks);
+
+breaks = 0;
+debugger;
+a.every(cb_true);
+assertEquals(4, breaks);
+assertFalse(exception);
+
+breaks = 0;
+debugger;
+a.map(cb_true);
+assertFalse(exception);
+assertEquals(4, breaks);
+
+breaks = 0;
+debugger;
+a.filter(cb_true);
+assertFalse(exception);
+assertEquals(4, breaks);
+
+breaks = 0;
+debugger;
+a.reduce(cb_reduce);
+assertFalse(exception);
+assertEquals(4, breaks);
+
+breaks = 0;
+debugger;
+a.reduceRight(cb_reduce);
+assertFalse(exception);
+assertEquals(4, breaks);
+
+Debug.setListener(null);
+
+
+// Test two levels of builtin callbacks:
+// Array.forEach calls a callback function, which by itself uses
+// Array.forEach with another callback function.
+
+function second_level_listener(event, exec_state, event_data, data) {
+ try {
+ if (event == Debug.DebugEvent.Break) {
+ if (breaks == 0) {
+ exec_state.prepareStep(Debug.StepAction.StepIn, 3);
+ breaks = 1;
+ } else if (breaks <= 16) {
+ breaks++;
+ // Check whether we break at the expected line.
+ assertTrue(event_data.sourceLineText().indexOf("Expected to step") > 0);
+ // Step two steps further every four breaks to skip the
+ // forEach call in the first level of recurision.
+ var step = (breaks % 4 == 1) ? 6 : 3;
+ exec_state.prepareStep(Debug.StepAction.StepIn, step);
+ }
+ }
+ } catch (e) {
+ exception = true;
+ }
+};
+
+function cb_foreach(num) {
+ a.forEach(cb_true);
+ print("back to the first level of recursion.");
+}
+
+Debug.setListener(second_level_listener);
+
+breaks = 0;
+debugger;
+a.forEach(cb_foreach);
+assertFalse(exception);
+assertEquals(17, breaks);
+
+Debug.setListener(null);
diff --git a/src/3rdparty/v8/test/mjsunit/declare-locally.js b/src/3rdparty/v8/test/mjsunit/declare-locally.js
index 93fcb85..20bfe6d 100644
--- a/src/3rdparty/v8/test/mjsunit/declare-locally.js
+++ b/src/3rdparty/v8/test/mjsunit/declare-locally.js
@@ -33,11 +33,13 @@
// This exercises the code in runtime.cc in
// DeclareGlobal...Locally().
+// Flags: --es52_globals
+
this.__proto__.foo = 42;
this.__proto__.bar = 87;
-eval("assertEquals(42, foo); var foo = 87;");
+eval("assertEquals(undefined, foo); var foo = 87;");
assertEquals(87, foo);
-eval("assertEquals(87, bar); const bar = 42;");
+eval("assertEquals(undefined, bar); const bar = 42;");
assertEquals(42, bar);
diff --git a/src/3rdparty/v8/test/mjsunit/error-constructors.js b/src/3rdparty/v8/test/mjsunit/error-constructors.js
index 966a162..107164d 100644
--- a/src/3rdparty/v8/test/mjsunit/error-constructors.js
+++ b/src/3rdparty/v8/test/mjsunit/error-constructors.js
@@ -25,39 +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.
-var e = new Error();
-assertFalse(e.hasOwnProperty('message'));
-Error.prototype.toString = Object.prototype.toString;
-assertEquals("[object Error]", Error.prototype.toString());
-assertEquals(Object.prototype, Error.prototype.__proto__);
-
-// Check that error construction does not call setters for the
-// properties on error objects in prototypes.
-function fail() { assertTrue(false); };
-ReferenceError.prototype.__defineSetter__('stack', fail);
-ReferenceError.prototype.__defineSetter__('message', fail);
-ReferenceError.prototype.__defineSetter__('type', fail);
-ReferenceError.prototype.__defineSetter__('arguments', fail);
-var e0 = new ReferenceError();
-var e1 = new ReferenceError('123');
-assertTrue(e1.hasOwnProperty('message'));
-assertTrue(e0.hasOwnProperty('stack'));
-assertTrue(e1.hasOwnProperty('stack'));
-assertTrue(e0.hasOwnProperty('type'));
-assertTrue(e1.hasOwnProperty('type'));
-assertTrue(e0.hasOwnProperty('arguments'));
-assertTrue(e1.hasOwnProperty('arguments'));
-
-// Check that the name property on error prototypes is read-only and
-// dont-delete. This is not specified, but allowing overwriting the
-// name property with a getter can leaks error objects from different
-// script tags in the same context in a browser setting. We therefore
-// disallow changes to the name property on error objects.
-assertEquals("ReferenceError", ReferenceError.prototype.name);
-delete ReferenceError.prototype.name;
-assertEquals("ReferenceError", ReferenceError.prototype.name);
-ReferenceError.prototype.name = "not a reference error";
-assertEquals("ReferenceError", ReferenceError.prototype.name);
+// Flags: --allow-natives-syntax
// Check that message and name are not enumerable on Error objects.
var desc = Object.getOwnPropertyDescriptor(Error.prototype, 'name');
@@ -75,8 +43,75 @@ assertFalse(desc['enumerable']);
desc = Object.getOwnPropertyDescriptor(e, 'stack');
assertFalse(desc['enumerable']);
+var e = new Error();
+assertFalse(e.hasOwnProperty('message'));
+
// name is not tested above, but in addition we should have no enumerable
// properties, so we simply assert that.
for (var v in e) {
assertUnreachable();
}
+
+// Check that error construction does not call setters for the
+// properties on error objects in prototypes.
+function fail() { assertUnreachable(); };
+ReferenceError.prototype.__defineSetter__('name', fail);
+ReferenceError.prototype.__defineSetter__('message', fail);
+ReferenceError.prototype.__defineSetter__('type', fail);
+ReferenceError.prototype.__defineSetter__('arguments', fail);
+ReferenceError.prototype.__defineSetter__('stack', fail);
+
+var e = new ReferenceError();
+assertTrue(e.hasOwnProperty('stack'));
+assertTrue(e.hasOwnProperty('type'));
+assertTrue(e.hasOwnProperty('arguments'));
+
+var e = new ReferenceError('123');
+assertTrue(e.hasOwnProperty('message'));
+assertTrue(e.hasOwnProperty('stack'));
+assertTrue(e.hasOwnProperty('type'));
+assertTrue(e.hasOwnProperty('arguments'));
+
+var e = %MakeReferenceError("my_test_error", [0, 1]);
+assertTrue(e.hasOwnProperty('stack'));
+assertTrue(e.hasOwnProperty('type'));
+assertTrue(e.hasOwnProperty('arguments'));
+assertEquals("my_test_error", e.type)
+
+// Check that intercepting property access from toString is prevented for
+// compiler errors. This is not specified, but allowing interception
+// through a getter can leak error objects from different
+// script tags in the same context in a browser setting.
+var errors = [SyntaxError, ReferenceError, TypeError];
+for (var i in errors) {
+ var name = errors[i].prototype.toString();
+ // Monkey-patch prototype.
+ var props = ["name", "message", "type", "arguments", "stack"];
+ for (var j in props) {
+ errors[i].prototype.__defineGetter__(props[j], fail);
+ }
+ // String conversion should not invoke monkey-patched getters on prototype.
+ var e = new errors[i];
+ assertEquals(name, e.toString());
+ // Custom getters in actual objects are welcome.
+ e.__defineGetter__("name", function() { return "mine"; });
+ assertEquals("mine", e.toString());
+}
+
+// Monkey-patching non-static errors should still be observable.
+function MyError() {}
+MyError.prototype = new Error;
+var errors = [Error, RangeError, EvalError, URIError, MyError];
+for (var i in errors) {
+ errors[i].prototype.__defineGetter__("name", function() { return "my"; });
+ errors[i].prototype.__defineGetter__("message", function() { return "moo"; });
+ var e = new errors[i];
+ assertEquals("my: moo", e.toString());
+}
+
+
+Error.prototype.toString = Object.prototype.toString;
+assertEquals("[object Error]", Error.prototype.toString());
+assertEquals(Object.prototype, Error.prototype.__proto__);
+var e = new Error("foo");
+assertEquals("[object Error]", e.toString());
diff --git a/src/3rdparty/v8/test/mjsunit/harmony/debug-function-scopes.js b/src/3rdparty/v8/test/mjsunit/harmony/debug-function-scopes.js
new file mode 100644
index 0000000..0113be6
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/harmony/debug-function-scopes.js
@@ -0,0 +1,115 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug --harmony-scoping
+
+"use strict";
+
+// Get the Debug object exposed from the debug context global object.
+var Debug = debug.Debug;
+
+function CheckScope(scope_mirror, scope_expectations, expected_scope_type) {
+ assertEquals(expected_scope_type, scope_mirror.scopeType());
+
+ var scope_object = scope_mirror.scopeObject().value();
+
+ for (let name in scope_expectations) {
+ let actual = scope_object[name];
+ let expected = scope_expectations[name];
+ assertEquals(expected, actual);
+ }
+}
+
+// A copy of the scope types from mirror-debugger.js.
+var ScopeType = { Global: 0,
+ Local: 1,
+ With: 2,
+ Closure: 3,
+ Catch: 4,
+ Block: 5 };
+
+var f1 = (function F1(x) {
+ function F2(y) {
+ var z = x + y;
+ {
+ var w = 5;
+ var v = "Capybara";
+ var F3 = function(a, b) {
+ function F4(p) {
+ return p + a + b + z + w + v.length;
+ }
+ return F4;
+ }
+ return F3(4, 5);
+ }
+ }
+ return F2(17);
+})(5);
+
+var mirror = Debug.MakeMirror(f1);
+
+assertEquals(4, mirror.scopeCount());
+
+CheckScope(mirror.scope(0), { a: 4, b: 5 }, ScopeType.Closure);
+CheckScope(mirror.scope(1), { z: 22, w: 5, v: "Capybara" }, ScopeType.Closure);
+CheckScope(mirror.scope(2), { x: 5 }, ScopeType.Closure);
+CheckScope(mirror.scope(3), {}, ScopeType.Global);
+
+var f2 = (function() {
+ var v1 = 3;
+ var v2 = 4;
+ let l0 = 0;
+ {
+ var v3 = 5;
+ let l1 = 6;
+ let l2 = 7;
+ {
+ var v4 = 8;
+ let l3 = 9;
+ {
+ var v5 = "Cat";
+ let l4 = 11;
+ var v6 = l4;
+ return function() {
+ return l0 + v1 + v3 + l2 + l3 + v6;
+ };
+ }
+ }
+ }
+})();
+
+var mirror = Debug.MakeMirror(f2);
+
+assertEquals(5, mirror.scopeCount());
+
+// Implementation artifact: l4 isn't used in closure, but still it is saved.
+CheckScope(mirror.scope(0), { l4: 11 }, ScopeType.Block);
+
+CheckScope(mirror.scope(1), { l3: 9 }, ScopeType.Block);
+CheckScope(mirror.scope(2), { l1: 6, l2: 7 }, ScopeType.Block);
+CheckScope(mirror.scope(3), { v1:3, l0: 0, v3: 5, v6: 11 }, ScopeType.Closure);
+CheckScope(mirror.scope(4), {}, ScopeType.Global);
diff --git a/src/3rdparty/v8/test/mjsunit/harmony/module-linking.js b/src/3rdparty/v8/test/mjsunit/harmony/module-linking.js
new file mode 100644
index 0000000..13ca6f7
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/harmony/module-linking.js
@@ -0,0 +1,121 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-modules --harmony-scoping
+
+// Test basic module linking.
+
+"use strict";
+
+let log = "";
+
+export let x = (log += "1");
+
+export module B = A.B
+
+export module A {
+ export let x = (log += "2");
+ let y = (log += "3");
+ export function f() { log += "5" };
+ export module B {
+ module BB = B;
+ export BB, x;
+ let x = (log += "4");
+ f();
+ let y = (log += "6");
+ }
+ export let z = (log += "7");
+ export module C {
+ export let z = (log += "8");
+ export module D = B
+ export module C = A.C
+ }
+ module D {}
+}
+
+export module M1 {
+ export module A2 = M2;
+ export let x = (log += "9");
+}
+export module M2 {
+ export module A1 = M1;
+ export let x = (log += "0");
+}
+
+assertEquals("object", typeof A);
+assertTrue('x' in A);
+assertFalse('y' in A);
+assertTrue('f' in A);
+assertTrue('B' in A);
+assertTrue('z' in A);
+assertTrue('C' in A);
+assertFalse('D' in A);
+
+assertEquals("object", typeof B);
+assertTrue('BB' in B);
+assertTrue('x' in B);
+assertFalse('y' in B);
+
+assertEquals("object", typeof A.B);
+assertTrue('BB' in A.B);
+assertTrue('x' in A.B);
+assertFalse('y' in A.B);
+
+assertEquals("object", typeof A.B.BB);
+assertTrue('BB' in A.B.BB);
+assertTrue('x' in A.B.BB);
+assertFalse('y' in A.B.BB);
+
+assertEquals("object", typeof A.C);
+assertTrue('z' in A.C);
+assertTrue('D' in A.C);
+assertTrue('C' in A.C);
+
+assertEquals("object", typeof M1);
+assertEquals("object", typeof M2);
+assertTrue('A2' in M1);
+assertTrue('A1' in M2);
+assertEquals("object", typeof M1.A2);
+assertEquals("object", typeof M2.A1);
+assertTrue('A1' in M1.A2);
+assertTrue('A2' in M2.A1);
+assertEquals("object", typeof M1.A2.A1);
+assertEquals("object", typeof M2.A1.A2);
+
+assertSame(B, A.B);
+assertSame(B, B.BB);
+assertSame(B, A.C.D);
+assertSame(A.C, A.C.C);
+assertFalse(A.D === A.C.D);
+
+assertSame(M1, M2.A1);
+assertSame(M2, M1.A2);
+assertSame(M1, M1.A2.A1);
+assertSame(M2, M2.A1.A2);
+
+// TODO(rossberg): inner declarations are not executed yet.
+// assertEquals("1234567890", log);
diff --git a/src/3rdparty/v8/test/mjsunit/harmony/module-parsing.js b/src/3rdparty/v8/test/mjsunit/harmony/module-parsing.js
index 93e69e3..cdd0a2e 100644
--- a/src/3rdparty/v8/test/mjsunit/harmony/module-parsing.js
+++ b/src/3rdparty/v8/test/mjsunit/harmony/module-parsing.js
@@ -70,7 +70,7 @@ module B {
import i0 from I
import i1, i2, i3, M from I
- import i4, i5 from "http://where"
+ //import i4, i5 from "http://where"
}
module I {
@@ -85,7 +85,7 @@ module D3 = D2
module E1 at "http://where"
module E2 at "http://where";
-module E3 = E1.F
+module E3 = E1
// Check that ASI does not interfere.
@@ -103,11 +103,11 @@ at
"file://local"
import
-x
+vx
,
-y
+vy
from
-"file://local"
+B
module Wrap {
diff --git a/src/3rdparty/v8/test/mjsunit/harmony/module-resolution.js b/src/3rdparty/v8/test/mjsunit/harmony/module-resolution.js
index f9f492c..a1b9917 100644
--- a/src/3rdparty/v8/test/mjsunit/harmony/module-resolution.js
+++ b/src/3rdparty/v8/test/mjsunit/harmony/module-resolution.js
@@ -129,7 +129,7 @@ export module M2 {
export module External at "external.js"
export module External1 = External
-export module ExternalA = External.A
+//export module ExternalA = External.A
export module InnerExternal {
export module E at "external.js"
}
diff --git a/src/3rdparty/v8/test/mjsunit/math-floor-of-div.js b/src/3rdparty/v8/test/mjsunit/math-floor-of-div.js
new file mode 100644
index 0000000..e917182
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/math-floor-of-div.js
@@ -0,0 +1,216 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --nouse_inlining
+
+// Use this function as reference. Make sure it is not inlined.
+function div(a, b) {
+ return a / b;
+}
+
+var limit = 0x1000000;
+var exhaustive_limit = 100;
+var step = 10;
+var values = [0x10000001,
+ 0x12345678,
+ -0x789abcdf, // 0x87654321
+ 0x01234567,
+ 0x76543210,
+ -0x80000000, // 0x80000000
+ 0x7fffffff,
+ -0x0fffffff, // 0xf0000001
+ 0x00000010,
+ -0x01000000 // 0xff000000
+ ];
+
+function test_div() {
+ var c = 0;
+ for (var k = 0; k <= limit; k++) {
+ if (k > exhaustive_limit) { c += step; k += c; }
+ assertEquals(Math.floor(div(k, 1)), Math.floor(k / 1));
+ assertEquals(Math.floor(div(k, -1)), Math.floor(k / -1));
+ assertEquals(Math.floor(div(k, 2)), Math.floor(k / 2));
+ assertEquals(Math.floor(div(k, -2)), Math.floor(k / -2));
+ assertEquals(Math.floor(div(k, 3)), Math.floor(k / 3));
+ assertEquals(Math.floor(div(k, -3)), Math.floor(k / -3));
+ assertEquals(Math.floor(div(k, 4)), Math.floor(k / 4));
+ assertEquals(Math.floor(div(k, -4)), Math.floor(k / -4));
+ assertEquals(Math.floor(div(k, 5)), Math.floor(k / 5));
+ assertEquals(Math.floor(div(k, -5)), Math.floor(k / -5));
+ assertEquals(Math.floor(div(k, 6)), Math.floor(k / 6));
+ assertEquals(Math.floor(div(k, -6)), Math.floor(k / -6));
+ assertEquals(Math.floor(div(k, 7)), Math.floor(k / 7));
+ assertEquals(Math.floor(div(k, -7)), Math.floor(k / -7));
+ assertEquals(Math.floor(div(k, 8)), Math.floor(k / 8));
+ assertEquals(Math.floor(div(k, -8)), Math.floor(k / -8));
+ assertEquals(Math.floor(div(k, 9)), Math.floor(k / 9));
+ assertEquals(Math.floor(div(k, -9)), Math.floor(k / -9));
+ assertEquals(Math.floor(div(k, 10)), Math.floor(k / 10));
+ assertEquals(Math.floor(div(k, -10)), Math.floor(k / -10));
+ assertEquals(Math.floor(div(k, 11)), Math.floor(k / 11));
+ assertEquals(Math.floor(div(k, -11)), Math.floor(k / -11));
+ assertEquals(Math.floor(div(k, 12)), Math.floor(k / 12));
+ assertEquals(Math.floor(div(k, -12)), Math.floor(k / -12));
+ assertEquals(Math.floor(div(k, 13)), Math.floor(k / 13));
+ assertEquals(Math.floor(div(k, -13)), Math.floor(k / -13));
+ assertEquals(Math.floor(div(k, 14)), Math.floor(k / 14));
+ assertEquals(Math.floor(div(k, -14)), Math.floor(k / -14));
+ assertEquals(Math.floor(div(k, 15)), Math.floor(k / 15));
+ assertEquals(Math.floor(div(k, -15)), Math.floor(k / -15));
+ assertEquals(Math.floor(div(k, 16)), Math.floor(k / 16));
+ assertEquals(Math.floor(div(k, -16)), Math.floor(k / -16));
+ assertEquals(Math.floor(div(k, 17)), Math.floor(k / 17));
+ assertEquals(Math.floor(div(k, -17)), Math.floor(k / -17));
+ assertEquals(Math.floor(div(k, 18)), Math.floor(k / 18));
+ assertEquals(Math.floor(div(k, -18)), Math.floor(k / -18));
+ assertEquals(Math.floor(div(k, 19)), Math.floor(k / 19));
+ assertEquals(Math.floor(div(k, -19)), Math.floor(k / -19));
+ assertEquals(Math.floor(div(k, 20)), Math.floor(k / 20));
+ assertEquals(Math.floor(div(k, -20)), Math.floor(k / -20));
+ assertEquals(Math.floor(div(k, 21)), Math.floor(k / 21));
+ assertEquals(Math.floor(div(k, -21)), Math.floor(k / -21));
+ assertEquals(Math.floor(div(k, 22)), Math.floor(k / 22));
+ assertEquals(Math.floor(div(k, -22)), Math.floor(k / -22));
+ assertEquals(Math.floor(div(k, 23)), Math.floor(k / 23));
+ assertEquals(Math.floor(div(k, -23)), Math.floor(k / -23));
+ assertEquals(Math.floor(div(k, 24)), Math.floor(k / 24));
+ assertEquals(Math.floor(div(k, -24)), Math.floor(k / -24));
+ assertEquals(Math.floor(div(k, 25)), Math.floor(k / 25));
+ assertEquals(Math.floor(div(k, -25)), Math.floor(k / -25));
+ assertEquals(Math.floor(div(k, 125)), Math.floor(k / 125));
+ assertEquals(Math.floor(div(k, -125)), Math.floor(k / -125));
+ assertEquals(Math.floor(div(k, 625)), Math.floor(k / 625));
+ assertEquals(Math.floor(div(k, -625)), Math.floor(k / -625));
+ }
+ c = 0;
+ for (var k = 0; k <= limit; k++) {
+ if (k > exhaustive_limit) { c += step; k += c; }
+ assertEquals(Math.floor(div(-k, 1)), Math.floor(-k / 1));
+ assertEquals(Math.floor(div(-k, -1)), Math.floor(-k / -1));
+ assertEquals(Math.floor(div(-k, 2)), Math.floor(-k / 2));
+ assertEquals(Math.floor(div(-k, -2)), Math.floor(-k / -2));
+ assertEquals(Math.floor(div(-k, 3)), Math.floor(-k / 3));
+ assertEquals(Math.floor(div(-k, -3)), Math.floor(-k / -3));
+ assertEquals(Math.floor(div(-k, 4)), Math.floor(-k / 4));
+ assertEquals(Math.floor(div(-k, -4)), Math.floor(-k / -4));
+ assertEquals(Math.floor(div(-k, 5)), Math.floor(-k / 5));
+ assertEquals(Math.floor(div(-k, -5)), Math.floor(-k / -5));
+ assertEquals(Math.floor(div(-k, 6)), Math.floor(-k / 6));
+ assertEquals(Math.floor(div(-k, -6)), Math.floor(-k / -6));
+ assertEquals(Math.floor(div(-k, 7)), Math.floor(-k / 7));
+ assertEquals(Math.floor(div(-k, -7)), Math.floor(-k / -7));
+ assertEquals(Math.floor(div(-k, 8)), Math.floor(-k / 8));
+ assertEquals(Math.floor(div(-k, -8)), Math.floor(-k / -8));
+ assertEquals(Math.floor(div(-k, 9)), Math.floor(-k / 9));
+ assertEquals(Math.floor(div(-k, -9)), Math.floor(-k / -9));
+ assertEquals(Math.floor(div(-k, 10)), Math.floor(-k / 10));
+ assertEquals(Math.floor(div(-k, -10)), Math.floor(-k / -10));
+ assertEquals(Math.floor(div(-k, 11)), Math.floor(-k / 11));
+ assertEquals(Math.floor(div(-k, -11)), Math.floor(-k / -11));
+ assertEquals(Math.floor(div(-k, 12)), Math.floor(-k / 12));
+ assertEquals(Math.floor(div(-k, -12)), Math.floor(-k / -12));
+ assertEquals(Math.floor(div(-k, 13)), Math.floor(-k / 13));
+ assertEquals(Math.floor(div(-k, -13)), Math.floor(-k / -13));
+ assertEquals(Math.floor(div(-k, 14)), Math.floor(-k / 14));
+ assertEquals(Math.floor(div(-k, -14)), Math.floor(-k / -14));
+ assertEquals(Math.floor(div(-k, 15)), Math.floor(-k / 15));
+ assertEquals(Math.floor(div(-k, -15)), Math.floor(-k / -15));
+ assertEquals(Math.floor(div(-k, 16)), Math.floor(-k / 16));
+ assertEquals(Math.floor(div(-k, -16)), Math.floor(-k / -16));
+ assertEquals(Math.floor(div(-k, 17)), Math.floor(-k / 17));
+ assertEquals(Math.floor(div(-k, -17)), Math.floor(-k / -17));
+ assertEquals(Math.floor(div(-k, 18)), Math.floor(-k / 18));
+ assertEquals(Math.floor(div(-k, -18)), Math.floor(-k / -18));
+ assertEquals(Math.floor(div(-k, 19)), Math.floor(-k / 19));
+ assertEquals(Math.floor(div(-k, -19)), Math.floor(-k / -19));
+ assertEquals(Math.floor(div(-k, 20)), Math.floor(-k / 20));
+ assertEquals(Math.floor(div(-k, -20)), Math.floor(-k / -20));
+ assertEquals(Math.floor(div(-k, 21)), Math.floor(-k / 21));
+ assertEquals(Math.floor(div(-k, -21)), Math.floor(-k / -21));
+ assertEquals(Math.floor(div(-k, 22)), Math.floor(-k / 22));
+ assertEquals(Math.floor(div(-k, -22)), Math.floor(-k / -22));
+ assertEquals(Math.floor(div(-k, 23)), Math.floor(-k / 23));
+ assertEquals(Math.floor(div(-k, -23)), Math.floor(-k / -23));
+ assertEquals(Math.floor(div(-k, 24)), Math.floor(-k / 24));
+ assertEquals(Math.floor(div(-k, -24)), Math.floor(-k / -24));
+ assertEquals(Math.floor(div(-k, 25)), Math.floor(-k / 25));
+ assertEquals(Math.floor(div(-k, -25)), Math.floor(-k / -25));
+ assertEquals(Math.floor(div(-k, 125)), Math.floor(-k / 125));
+ assertEquals(Math.floor(div(-k, -125)), Math.floor(-k / -125));
+ assertEquals(Math.floor(div(-k, 625)), Math.floor(-k / 625));
+ assertEquals(Math.floor(div(-k, -625)), Math.floor(-k / -625));
+ }
+ // Test for edge cases.
+ // Use (values[key] | 0) to force the integer type.
+ for (var i = 0; i < values.length; i++) {
+ for (var j = 0; j < values.length; j++) {
+ assertEquals(Math.floor(div((values[i] | 0), (values[j] | 0))),
+ Math.floor((values[i] | 0) / (values[j] | 0)));
+ assertEquals(Math.floor(div(-(values[i] | 0), (values[j] | 0))),
+ Math.floor(-(values[i] | 0) / (values[j] | 0)));
+ assertEquals(Math.floor(div((values[i] | 0), -(values[j] | 0))),
+ Math.floor((values[i] | 0) / -(values[j] | 0)));
+ assertEquals(Math.floor(div(-(values[i] | 0), -(values[j] | 0))),
+ Math.floor(-(values[i] | 0) / -(values[j] | 0)));
+ }
+ }
+}
+
+test_div();
+%OptimizeFunctionOnNextCall(test_div);
+test_div();
+
+// Test for negative zero and overflow.
+// Separate the tests to prevent deoptimizations from making the other optimized
+// test unreachable.
+
+function IsNegativeZero(x) {
+ assertTrue(x == 0); // Is 0 or -0.
+ var y = 1 / x;
+ assertFalse(isFinite(y));
+ return y < 0;
+}
+
+function test_div_deopt_minus_zero() {
+ var zero_in_array = [0];
+ assertTrue(IsNegativeZero(Math.floor((zero_in_array[0] | 0) / -1)));
+}
+
+function test_div_deopt_overflow() {
+ // We box the value in an array to avoid constant propagation.
+ var min_int_in_array = [-2147483648];
+ // We use '| 0' to force the representation to int32.
+ assertEquals(-min_int_in_array[0],
+ Math.floor((min_int_in_array[0] | 0) / -1));
+}
+
+test_div_deopt_minus_zero();
+test_div_deopt_overflow();
+%OptimizeFunctionOnNextCall(test_div_deopt_minus_zero);
+%OptimizeFunctionOnNextCall(test_div_deopt_overflow);
+test_div_deopt_minus_zero();
+test_div_deopt_overflow();
diff --git a/src/3rdparty/v8/test/mjsunit/mjsunit.js b/src/3rdparty/v8/test/mjsunit/mjsunit.js
index 033c78f..65fb301 100644
--- a/src/3rdparty/v8/test/mjsunit/mjsunit.js
+++ b/src/3rdparty/v8/test/mjsunit/mjsunit.js
@@ -75,7 +75,7 @@ var assertTrue;
// Checks that the found value is false.
var assertFalse;
-// Checks that the found value is null. Kept for historical compatability,
+// Checks that the found value is null. Kept for historical compatibility,
// please just use assertEquals(null, expected).
var assertNull;
diff --git a/src/3rdparty/v8/test/mjsunit/mjsunit.status b/src/3rdparty/v8/test/mjsunit/mjsunit.status
index a1b9270..ab5f2e3 100644
--- a/src/3rdparty/v8/test/mjsunit/mjsunit.status
+++ b/src/3rdparty/v8/test/mjsunit/mjsunit.status
@@ -64,6 +64,7 @@ regress/regress-524: (PASS || TIMEOUT), SKIP if $mode == debug
# Stack manipulations in LiveEdit are buggy - see bug 915
debug-liveedit-check-stack: SKIP
debug-liveedit-patch-positions-replace: SKIP
+debug-liveedit-stack-padding: SKIP
# Test Crankshaft compilation time. Expected to take too long in debug mode.
regress/regress-1969: PASS, SKIP if $mode == debug
diff --git a/src/3rdparty/v8/test/mjsunit/regexp-capture-3.js b/src/3rdparty/v8/test/mjsunit/regexp-capture-3.js
new file mode 100644
index 0000000..9bdd600
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regexp-capture-3.js
@@ -0,0 +1,218 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function oneMatch(re) {
+ "abcd".replace(re, function() { });
+ assertEquals("abcd", RegExp.input);
+ assertEquals("a", RegExp.leftContext);
+ assertEquals("b", RegExp.lastMatch);
+ assertEquals("", RegExp.lastParen);
+ assertEquals(undefined, RegExp.lastIndex);
+ assertEquals(undefined, RegExp.index);
+ assertEquals("cd", RegExp.rightContext);
+ for (var i = 1; i < 10; i++) {
+ assertEquals("", RegExp['$' + i]);
+ }
+}
+
+oneMatch(/b/);
+oneMatch(/b/g);
+
+"abcdabcd".replace(/b/g, function() { });
+assertEquals("abcdabcd", RegExp.input);
+assertEquals("abcda", RegExp.leftContext);
+assertEquals("b", RegExp.lastMatch);
+assertEquals("", RegExp.lastParen);
+assertEquals(undefined, RegExp.lastIndex);
+assertEquals(undefined, RegExp.index);
+assertEquals("cd", RegExp.rightContext);
+for (var i = 1; i < 10; i++) {
+ assertEquals("", RegExp['$' + i]);
+}
+
+function captureMatch(re) {
+ "abcd".replace(re, function() { });
+ assertEquals("abcd", RegExp.input);
+ assertEquals("a", RegExp.leftContext);
+ assertEquals("bc", RegExp.lastMatch);
+ assertEquals("c", RegExp.lastParen);
+ assertEquals(undefined, RegExp.lastIndex);
+ assertEquals(undefined, RegExp.index);
+ assertEquals("d", RegExp.rightContext);
+ assertEquals('b', RegExp.$1);
+ assertEquals('c', RegExp.$2);
+ for (var i = 3; i < 10; i++) {
+ assertEquals("", RegExp['$' + i]);
+ }
+}
+
+captureMatch(/(b)(c)/);
+captureMatch(/(b)(c)/g);
+
+"abcdabcd".replace(/(b)(c)/g, function() { });
+assertEquals("abcdabcd", RegExp.input);
+assertEquals("abcda", RegExp.leftContext);
+assertEquals("bc", RegExp.lastMatch);
+assertEquals("c", RegExp.lastParen);
+assertEquals(undefined, RegExp.lastIndex);
+assertEquals(undefined, RegExp.index);
+assertEquals("d", RegExp.rightContext);
+assertEquals('b', RegExp.$1);
+assertEquals('c', RegExp.$2);
+for (var i = 3; i < 10; i++) {
+ assertEquals("", RegExp['$' + i]);
+}
+
+
+function Override() {
+ // Set the internal lastMatchInfoOverride. After calling this we do a normal
+ // match and verify the override was cleared and that we record the new
+ // captures.
+ "abcdabcd".replace(/(b)(c)/g, function() { });
+}
+
+
+function TestOverride(input, expect, property, re_src) {
+ var re = new RegExp(re_src);
+ var re_g = new RegExp(re_src, "g");
+
+ function OverrideCase(fn) {
+ Override();
+ fn();
+ assertEquals(expect, RegExp[property]);
+ }
+
+ OverrideCase(function() { return input.replace(re, "x"); });
+ OverrideCase(function() { return input.replace(re_g, "x"); });
+ OverrideCase(function() { return input.replace(re, ""); });
+ OverrideCase(function() { return input.replace(re_g, ""); });
+ OverrideCase(function() { return input.match(re); });
+ OverrideCase(function() { return input.match(re_g); });
+ OverrideCase(function() { return re.test(input); });
+ OverrideCase(function() { return re_g.test(input); });
+}
+
+var input = "bar.foo baz......";
+var re_str = "(ba.).*?f";
+TestOverride(input, "bar", "$1", re_str);
+
+input = "foo bar baz";
+var re_str = "bar";
+TestOverride(input, "bar", "$&", re_str);
+
+
+function no_last_match(fn) {
+ fn();
+ assertEquals("hestfisk", RegExp.$1);
+}
+
+/(hestfisk)/.test("There's no such thing as a hestfisk!");
+
+no_last_match(function() { "foo".replace("f", ""); });
+no_last_match(function() { "foo".replace("f", "f"); });
+no_last_match(function() { "foo".split("o"); });
+
+var base = "In the music. In the music. ";
+var cons = base + base + base + base;
+no_last_match(function() { cons.replace("x", "y"); });
+no_last_match(function() { cons.replace("e", "E"); });
+
+
+// Here's one that matches once, then tries to match again, but fails.
+// Verify that the last match info is from the last match, not from the
+// failure that came after.
+"bar.foo baz......".replace(/(ba.).*?f/g, function() { return "x";});
+assertEquals("bar", RegExp.$1);
+
+
+// A test that initially does a zero width match, but later does a non-zero
+// width match.
+var a = "foo bar baz".replace(/^|bar/g, "");
+assertEquals("foo baz", a);
+
+a = "foo bar baz".replace(/^|bar/g, "*");
+assertEquals("*foo * baz", a);
+
+// We test FilterASCII using regexps that will backtrack forever. Since
+// a regexp with a non-ASCII character in it can never match an ASCII
+// string we can test that the relevant node is removed by verifying that
+// there is no hang.
+function NoHang(re) {
+ print(re);
+ "This is an ASCII string that could take forever".match(re);
+}
+
+
+NoHang(/(((.*)*)*x)Ã¥/); // Continuation after loop is filtered, so is loop.
+NoHang(/(((.*)*)*Ã¥)foo/); // Body of loop filtered.
+NoHang(/Ã¥(((.*)*)*x)/); // Everything after a filtered character is filtered.
+NoHang(/(((.*)*)*x)Ã¥/); // Everything before a filtered character is filtered.
+NoHang(/[æøå](((.*)*)*x)/); // Everything after a filtered class is filtered.
+NoHang(/(((.*)*)*x)[æøå]/); // Everything before a filtered class is filtered.
+NoHang(/[^\x00-\x7f](((.*)*)*x)/); // After negated class.
+NoHang(/(((.*)*)*x)[^\x00-\x7f]/); // Before negated class.
+NoHang(/(?!(((.*)*)*x)Ã¥)foo/); // Negative lookahead is filtered.
+NoHang(/(?!(((.*)*)*x))Ã¥/); // Continuation branch of negative lookahead.
+NoHang(/(?=(((.*)*)*x)Ã¥)foo/); // Positive lookahead is filtered.
+NoHang(/(?=(((.*)*)*x))Ã¥/); // Continuation branch of positive lookahead.
+NoHang(/(?=Ã¥)(((.*)*)*x)/); // Positive lookahead also prunes continuation.
+NoHang(/(æ|ø|å)(((.*)*)*x)/); // All branches of alternation are filtered.
+NoHang(/(a|b|(((.*)*)*x))Ã¥/); // 1 out of 3 branches pruned.
+NoHang(/(a|(((.*)*)*x)ø|(((.*)*)*x)å)/); // 2 out of 3 branches pruned.
+
+var s = "Don't prune based on a repetition of length 0";
+assertEquals(null, s.match(/Ã¥{1,1}prune/));
+assertEquals("prune", (s.match(/Ã¥{0,0}prune/)[0]));
+
+// Some very deep regexps where FilterASCII gives up in order not to make the
+// stack overflow.
+var regex6 = /a*\u0100*\w/;
+var input0 = "a";
+regex6.exec(input0);
+
+var re = "\u0100*\\w";
+
+for (var i = 0; i < 200; i++) re = "a*" + re;
+
+var regex7 = new RegExp(re);
+regex7.exec(input0);
+
+var regex8 = new RegExp(re, "i");
+regex8.exec(input0);
+
+re = "[\u0100]*\\w";
+for (var i = 0; i < 200; i++) re = "a*" + re;
+
+var regex9 = new RegExp(re);
+regex9.exec(input0);
+
+var regex10 = new RegExp(re, "i");
+regex10.exec(input0);
+
+var regex11 = /^(?:[^\u0000-\u0080]|[0-9a-z?,.!&\s#()])+$/i;
+regex11.exec(input0);
+
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-1119.js b/src/3rdparty/v8/test/mjsunit/regress/regress-1119.js
index 16b2e4f..5fd8f36 100644
--- a/src/3rdparty/v8/test/mjsunit/regress/regress-1119.js
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-1119.js
@@ -28,17 +28,19 @@
// Test runtime declaration of properties with var which are intercepted
// by JS accessors.
-__proto__.__defineSetter__("x", function() { hasBeenInvoked = true; });
-__proto__.__defineSetter__("y", function() { throw 'exception'; });
+// Flags: --es52_globals
+
+this.__defineSetter__("x", function() { hasBeenInvoked = true; });
+this.__defineSetter__("y", function() { throw 'exception'; });
var hasBeenInvoked = false;
eval("try { } catch (e) { var x = false; }");
assertTrue(hasBeenInvoked);
-var exception;
+// This has to run in global scope, so cannot use assertThrows...
try {
eval("try { } catch (e) { var y = false; }");
+ assertUnreachable();
} catch (e) {
- exception = e;
+ assertEquals('exception', e);
}
-assertEquals('exception', exception);
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-115452.js b/src/3rdparty/v8/test/mjsunit/regress/regress-115452.js
index 7e424ed..dc71158 100644
--- a/src/3rdparty/v8/test/mjsunit/regress/regress-115452.js
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-115452.js
@@ -27,22 +27,21 @@
// Test that a function declaration cannot overwrite a read-only property.
-print(0)
+// Flags: --es52_globals
+
function foobl() {}
assertTrue(typeof this.foobl == "function");
assertTrue(Object.getOwnPropertyDescriptor(this, "foobl").writable);
-print(1)
Object.defineProperty(this, "foobl", {value: 1, writable: false});
assertSame(1, this.foobl);
assertFalse(Object.getOwnPropertyDescriptor(this, "foobl").writable);
-print(2)
-eval("function foobl() {}");
+// This has to run in global scope, so cannot use assertThrows...
+try {
+ eval("function foobl() {}"); // Should throw.
+ assertUnreachable();
+} catch (e) {
+ assertInstanceof(e, TypeError);
+}
assertSame(1, this.foobl);
-assertFalse(Object.getOwnPropertyDescriptor(this, "foobl").writable);
-
-print(3)
-eval("function foobl() {}");
-assertSame(1, this.foobl);
-assertFalse(Object.getOwnPropertyDescriptor(this, "foobl").writable);
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-1170.js b/src/3rdparty/v8/test/mjsunit/regress/regress-1170.js
index 66ed9f2..8c5f6f8 100644
--- a/src/3rdparty/v8/test/mjsunit/regress/regress-1170.js
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-1170.js
@@ -25,48 +25,74 @@
// (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: --es52_globals
+
var setter_value = 0;
-__proto__.__defineSetter__("a", function(v) { setter_value = v; });
+this.__defineSetter__("a", function(v) { setter_value = v; });
eval("var a = 1");
assertEquals(1, setter_value);
-assertFalse(this.hasOwnProperty("a"));
+assertFalse("value" in Object.getOwnPropertyDescriptor(this, "a"));
eval("with({}) { eval('var a = 2') }");
assertEquals(2, setter_value);
-assertFalse(this.hasOwnProperty("a"));
+assertFalse("value" in Object.getOwnPropertyDescriptor(this, "a"));
// Function declarations are treated specially to match Safari. We do
// not call setters for them.
+this.__defineSetter__("a", function(v) { assertUnreachable(); });
eval("function a() {}");
-assertTrue(this.hasOwnProperty("a"));
+assertTrue("value" in Object.getOwnPropertyDescriptor(this, "a"));
-__proto__.__defineSetter__("b", function(v) { assertUnreachable(); });
-var exception = false;
+this.__defineSetter__("b", function(v) { setter_value = v; });
try {
- eval("const b = 23");
+ eval("const b = 3");
} catch(e) {
- exception = true;
- assertTrue(/TypeError/.test(e));
+ assertUnreachable();
}
-assertFalse(exception);
+assertEquals(3, setter_value);
-exception = false;
try {
eval("with({}) { eval('const b = 23') }");
} catch(e) {
- exception = true;
- assertTrue(/TypeError/.test(e));
+ assertInstanceof(e, TypeError);
}
-assertTrue(exception);
-__proto__.__defineSetter__("c", function(v) { throw 42; });
-exception = false;
+this.__defineSetter__("c", function(v) { throw 42; });
try {
eval("var c = 1");
+ assertUnreachable();
} catch(e) {
- exception = true;
assertEquals(42, e);
- assertFalse(this.hasOwnProperty("c"));
+ assertFalse("value" in Object.getOwnPropertyDescriptor(this, "c"));
+}
+
+
+
+
+__proto__.__defineSetter__("aa", function(v) { assertUnreachable(); });
+eval("var aa = 1");
+assertTrue(this.hasOwnProperty("aa"));
+
+__proto__.__defineSetter__("bb", function(v) { assertUnreachable(); });
+eval("with({}) { eval('var bb = 2') }");
+assertTrue(this.hasOwnProperty("bb"));
+
+// Function declarations are treated specially to match Safari. We do
+// not call setters for them.
+__proto__.__defineSetter__("cc", function(v) { assertUnreachable(); });
+eval("function cc() {}");
+assertTrue(this.hasOwnProperty("cc"));
+
+__proto__.__defineSetter__("dd", function(v) { assertUnreachable(); });
+try {
+ eval("const dd = 23");
+} catch(e) {
+ assertUnreachable();
+}
+
+try {
+ eval("with({}) { eval('const dd = 23') }");
+} catch(e) {
+ assertInstanceof(e, TypeError);
}
-assertTrue(exception);
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-117409.js b/src/3rdparty/v8/test/mjsunit/regress/regress-117409.js
new file mode 100644
index 0000000..9222191
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-117409.js
@@ -0,0 +1,52 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-gc
+
+function KeyedStoreIC(a) { a[0] = Math.E; }
+
+// Create literal with a fast double elements backing store
+var literal = [1.2];
+
+// Specialize the IC for fast double elements
+KeyedStoreIC(literal);
+KeyedStoreIC(literal);
+
+// Trruncate array to 0 elements, at which point backing store will be replaced
+// with empty fixed array.
+literal.length = 0;
+
+// ArrayPush built-in will replace empty fixed array backing store with 19
+// elements fixed array backing store. This leads to a mismatch between the map
+// and the backing store. Debug mode will crash here in set_elements accessor.
+literal.push(Math.E, Math.E);
+
+// Corrupt the backing store!
+KeyedStoreIC(literal);
+
+// Release mode will crash here when trying to visit parts of E as pointers.
+gc();
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-119609.js b/src/3rdparty/v8/test/mjsunit/regress/regress-119609.js
new file mode 100644
index 0000000..99041ad
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-119609.js
@@ -0,0 +1,71 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+
+Debug = debug.Debug;
+
+var exception = false;
+
+function listener(event, exec_state, event_data, data) {
+ try {
+ if (event == Debug.DebugEvent.Break) {
+ function lookup(name) {
+ return exec_state.frame(0).evaluate(name).value();
+ }
+
+ assertEquals(3, lookup("e"));
+ assertEquals(4, lookup("f"));
+ assertEquals(1, lookup("a"));
+
+ try {
+ assertEquals(2, lookup("b"));
+ } catch (e) {
+ assertEquals("ReferenceError: b is not defined", e.toString());
+ }
+ }
+ } catch (e) {
+ exception = e.toString() + e.stack;
+ }
+}
+
+Debug.setListener(listener);
+
+function f(a, b) {
+ var c = 3;
+ function d(e, f) {
+ var g = a;
+ var h = c;
+ debugger;
+ }
+
+ return d;
+}
+
+f(1, 2)(3, 4);
+
+assertFalse(exception);
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-1217.js b/src/3rdparty/v8/test/mjsunit/regress/regress-1217.js
index 6530549..e00d537 100644
--- a/src/3rdparty/v8/test/mjsunit/regress/regress-1217.js
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-1217.js
@@ -30,7 +30,7 @@
var proto = RegExp.prototype;
assertEquals("[object RegExp]", Object.prototype.toString.call(proto));
-assertEquals("", proto.source);
+assertEquals("(?:)", proto.source);
assertEquals(false, proto.global);
assertEquals(false, proto.multiline);
assertEquals(false, proto.ignoreCase);
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-123512.js b/src/3rdparty/v8/test/mjsunit/regress/regress-123512.js
new file mode 100644
index 0000000..8a747bc
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-123512.js
@@ -0,0 +1,78 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+// Test that boilerplate objects for array literals with non-constant
+// elements (which will contain the hole at non-constant positions) will
+// not cause prototype chain lookups when generating optimized code.
+
+function f(x) {
+ return [x][0];
+}
+
+// Test data element on prototype.
+Object.prototype[0] = 23;
+assertSame(1, f(1));
+assertSame(2, f(2));
+%OptimizeFunctionOnNextCall(f);
+assertSame(3, f(3));
+%DeoptimizeFunction(f);
+
+// Test accessor element on prototype.
+Object.prototype.__defineGetter__(0, function() { throw Error(); });
+assertSame(4, f(4));
+assertSame(5, f(5));
+%OptimizeFunctionOnNextCall(f);
+assertSame(6, f(6));
+%DeoptimizeFunction(f);
+
+// Test the same on boilerplate objects for object literals that contain
+// both non-constant properties and non-constant elements.
+
+function g(x, y) {
+ var o = { foo:x, 0:y };
+ return o.foo + o[0];
+}
+
+// Test data property and element on prototype.
+Object.prototype[0] = 23;
+Object.prototype.foo = 42;
+assertSame(3, g(1, 2));
+assertSame(5, g(2, 3));
+%OptimizeFunctionOnNextCall(g);
+assertSame(7, g(3, 4));
+%DeoptimizeFunction(g);
+
+// Test accessor property and element on prototype.
+Object.prototype.__defineGetter__(0, function() { throw Error(); });
+Object.prototype.__defineGetter__('foo', function() { throw Error(); });
+assertSame(3, g(1, 2));
+assertSame(5, g(2, 3));
+%OptimizeFunctionOnNextCall(g);
+assertSame(7, g(3, 4));
+%DeoptimizeFunction(g);
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-123919.js b/src/3rdparty/v8/test/mjsunit/regress/regress-123919.js
new file mode 100644
index 0000000..be34608
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-123919.js
@@ -0,0 +1,47 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --gc-global
+
+function g(max,val) {
+ this.x = 0;
+ for (var i = 0; i < max; i++) {
+ this.x = i/100;
+ }
+ this.val = val;
+}
+
+function f(max) {
+ var val = 0.5;
+ var obj = new g(max,val);
+ assertSame(val, obj.val);
+}
+
+f(1);
+f(1);
+%OptimizeFunctionOnNextCall(f);
+f(200000);
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-124594.js b/src/3rdparty/v8/test/mjsunit/regress/regress-124594.js
new file mode 100644
index 0000000..d51e1f6
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-124594.js
@@ -0,0 +1,50 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --expose-gc
+
+// Test that a GC inside a constructor frame is correctly handled right
+// after we deoptimize from an inlined constructor to a constructor stub
+// stack frame.
+
+function f(deopt) {
+ var x = 1;
+ if (deopt) {
+ x = x + "foo";
+ gc();
+ }
+ this.x = x;
+}
+
+function g(deopt) {
+ return new f(deopt);
+}
+
+assertEquals({x:1}, g(false));
+assertEquals({x:1}, g(false));
+%OptimizeFunctionOnNextCall(g);
+assertEquals({x:"1foo"}, g(true));
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-125515.js b/src/3rdparty/v8/test/mjsunit/regress/regress-125515.js
new file mode 100644
index 0000000..91650ce
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-125515.js
@@ -0,0 +1,41 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-gc --debug-code
+
+function test(a) {
+ a[0] = 1.5;
+ assertEquals(0, a.length = 0);
+}
+a = new Array();
+test(a);
+test(a);
+// Make sure that a ends up in old space
+gc();
+gc();
+test(a);
+test(a);
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-126412.js b/src/3rdparty/v8/test/mjsunit/regress/regress-126412.js
new file mode 100644
index 0000000..0677f70
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-126412.js
@@ -0,0 +1,33 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"".match(/(A{9999999999}B|C*)*D/);
+"C".match(/(A{9999999999}B|C*)*D/);
+"".match(/(A{9999999999}B|C*)*/ );
+"C".match(/(A{9999999999}B|C*)*/ );
+"".match(/(9u|(2\`shj{2147483649,}\r|3|f|y|3*)+8\B)\W93+/);
+"9u8 ".match(/(9u|(2\`shj{2147483649,}\r|3|f|y|3*)+8\B)\W93+/);
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-128018.js b/src/3rdparty/v8/test/mjsunit/regress/regress-128018.js
new file mode 100644
index 0000000..7bd1585
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-128018.js
@@ -0,0 +1,35 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-gc
+
+function KeyedStoreIC(a) { a[(1)] = Math.E; }
+var literal = [1.2];
+literal.length = 0;
+literal.push('0' && 0 );
+KeyedStoreIC(literal);
+gc();
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-128146.js b/src/3rdparty/v8/test/mjsunit/regress/regress-128146.js
new file mode 100644
index 0000000..5c22b4e
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-128146.js
@@ -0,0 +1,38 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Object.defineProperty({},"foo",{set:function(){},configurable:false});
+Object.defineProperty({},"foo",{get:function(){},configurable:false});
+Object.defineProperty({},"foo",{});
+
+// From WebKit layout tests (fast/js/prototypes.html)
+var wasSet = false;
+var o = { };
+o.__defineGetter__("__proto__", function() { wasSet = true });
+o.__proto__;
+assertFalse(wasSet);
+
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-1639-2.js b/src/3rdparty/v8/test/mjsunit/regress/regress-1639-2.js
index c439dd8..01f0dc2 100644
--- a/src/3rdparty/v8/test/mjsunit/regress/regress-1639-2.js
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-1639-2.js
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -28,6 +28,7 @@
// Flags: --expose-debug-as debug
// Get the Debug object exposed from the debug context global object.
Debug = debug.Debug
+var exception = false;
function sendCommand(state, cmd) {
// Get the debug command processor in paused state.
@@ -79,6 +80,7 @@ function listener(event, exec_state, event_data, data) {
}
} catch (e) {
print(e);
+ exception = true;
}
}
@@ -91,3 +93,4 @@ function a() {
// Set a break point and call to invoke the debug event listener.
Debug.setBreakPoint(a, 0, 0);
a();
+assertFalse(exception);
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-1639.js b/src/3rdparty/v8/test/mjsunit/regress/regress-1639.js
index ed68c97..47cdbc4 100644
--- a/src/3rdparty/v8/test/mjsunit/regress/regress-1639.js
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-1639.js
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -29,6 +29,7 @@
// Get the Debug object exposed from the debug context global object.
Debug = debug.Debug
var breaks = 0;
+var exception = false;
function sendCommand(state, cmd) {
// Get the debug command processor in paused state.
@@ -47,15 +48,18 @@ function listener(event, exec_state, event_data, data) {
"should not break on unexpected lines")
assertEquals('BREAK ' + breaks, line.substr(-7));
breaks++;
- sendCommand(exec_state, {
- seq: 0,
- type: "request",
- command: "continue",
- arguments: { stepaction: "next" }
- });
+ if (breaks < 4) {
+ sendCommand(exec_state, {
+ seq: 0,
+ type: "request",
+ command: "continue",
+ arguments: { stepaction: "next" }
+ });
+ }
}
} catch (e) {
print(e);
+ exception = true;
}
}
@@ -82,4 +86,6 @@ function c() {
// Set a break point and call to invoke the debug event listener.
Debug.setBreakPoint(b, 0, 0);
a(b);
-// BREAK 3
+a(); // BREAK 3
+
+assertFalse(exception);
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-2071.js b/src/3rdparty/v8/test/mjsunit/regress/regress-2071.js
new file mode 100644
index 0000000..91ae2a7
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-2071.js
@@ -0,0 +1,79 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+a = {};
+
+a.b = 42;
+
+with(a) {
+ a.f = (function f1() {
+ function f2() {
+ return b;
+ };
+ return f2;
+ })();
+}
+
+for(var i = 0; i < 10000; i++) {
+ assertEquals(42, a.f());
+}
+
+with(a) {
+ a.g = (function f1() {
+ function f2() {
+ function f3() {
+ return b;
+ }
+ return f3;
+ };
+ return f2();
+ })();
+}
+
+for(var i = 0; i < 10000; i++) {
+ assertEquals(42, a.g());
+}
+
+function outer() {
+ with(a) {
+ a.h = (function f1() {
+ function f2() {
+ function f3() {
+ return b;
+ }
+ return f3;
+ };
+ return f2();
+ })();
+ }
+};
+
+outer();
+
+for(var i = 0; i < 10000; i++) {
+ assertEquals(42, a.h());
+}
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-2110.js b/src/3rdparty/v8/test/mjsunit/regress/regress-2110.js
new file mode 100644
index 0000000..d7f78d2
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-2110.js
@@ -0,0 +1,53 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+var uint8 = new Uint8Array(1);
+
+function test() {
+ uint8[0] = 0x800000aa;
+ assertEquals(0xaa, uint8[0]);
+}
+
+test();
+test();
+test();
+%OptimizeFunctionOnNextCall(test);
+test();
+
+var uint32 = new Uint32Array(1);
+
+function test2() {
+ uint32[0] = 0x80123456789abcde;
+ assertEquals(0x789ac000, uint32[0]);
+}
+
+test2();
+test2();
+%OptimizeFunctionOnNextCall(test2);
+test2();
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-crbug-122271.js b/src/3rdparty/v8/test/mjsunit/regress/regress-crbug-122271.js
new file mode 100644
index 0000000..3a99a7f
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-crbug-122271.js
@@ -0,0 +1,49 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+// Tests that ElementsKind transitions and regular transitions don't
+// interfere badly with each other.
+
+var a = [0, 0, 0, 1];
+var b = [0, 0, 0, "one"];
+var c = [0, 0, 0, 1];
+c.foo = "baz";
+
+function foo(array) {
+ array.foo = "bar";
+}
+
+assertTrue(%HasFastSmiOnlyElements(a));
+assertTrue(%HasFastElements(b));
+
+foo(a);
+foo(b);
+
+assertTrue(%HasFastSmiOnlyElements(a));
+assertTrue(%HasFastElements(b));
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-crbug-126414.js b/src/3rdparty/v8/test/mjsunit/regress/regress-crbug-126414.js
new file mode 100644
index 0000000..6674267
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-crbug-126414.js
@@ -0,0 +1,32 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function foo(bar) {
+ return arguments[bar];
+}
+foo(0); // Handled in runtime.
+foo(-536870912); // Triggers bug.
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-fast-literal-transition.js b/src/3rdparty/v8/test/mjsunit/regress/regress-fast-literal-transition.js
new file mode 100644
index 0000000..72110f5
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-fast-literal-transition.js
@@ -0,0 +1,62 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --always-opt --expose-gc
+
+// Test that the elements kind of the boilerplate object is sufficiently
+// checked in LFastLiteral, so that unoptimized code can transition the
+// boilerplate. The --always-opt flag makes sure that optimized code is
+// not thrown away at deoptimization.
+
+// The switch statement in f() makes sure that f() is not inlined. If we
+// start inlining switch statements, we will still catch the bug on the
+// final --stress-opt run.
+
+function f(x) {
+ switch(x) {
+ case 1: return 1.4;
+ case 2: return 1.5;
+ case 3: return {};
+ default: gc();
+ }
+}
+
+function g(x) {
+ return [1.1, 1.2, 1.3, f(x)];
+}
+
+// Step 1: Optimize g() to contain a FAST_DOUBLE_ELEMENTS boilerplate.
+assertEquals([1.1, 1.2, 1.3, 1.4], g(1));
+assertEquals([1.1, 1.2, 1.3, 1.5], g(2));
+%OptimizeFunctionOnNextCall(g);
+
+// Step 2: Deoptimize g() and transition to FAST_ELEMENTS boilerplate.
+assertEquals([1.1, 1.2, 1.3, {}], g(3));
+
+// Step 3: Cause a GC while broken clone of boilerplate is on the heap,
+// hence causing heap verification to catch it.
+assertEquals([1.1, 1.2, 1.3, undefined], g(4));
diff --git a/src/3rdparty/v8/test/mjsunit/regress/regress-transcendental.js b/src/3rdparty/v8/test/mjsunit/regress/regress-transcendental.js
new file mode 100644
index 0000000..b5dbcb4
--- /dev/null
+++ b/src/3rdparty/v8/test/mjsunit/regress/regress-transcendental.js
@@ -0,0 +1,49 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-gc
+
+// Test whether the runtime implementation and generated code of
+// sine and tangens return the same results.
+
+function test(f, x, name) {
+ // Reset transcendental cache.
+ gc();
+ // Initializing cache leads to a runtime call.
+ var runtime_result = f(x);
+ // Flush transcendental cache entries and optimize f.
+ for (var i = 0; i < 100000; i++) f(i);
+ // Calculate using generated code.
+ var gencode_result = f(x);
+ print(name + " runtime function: " + runtime_result);
+ print(name + " generated code : " + gencode_result);
+ assertEquals(gencode_result, runtime_result);
+}
+
+test(Math.tan, -1.57079632679489660000, "Math.tan");
+test(Math.sin, 6.283185307179586, "Math.sin");
+
diff --git a/src/3rdparty/v8/test/mozilla/mozilla.status b/src/3rdparty/v8/test/mozilla/mozilla.status
index e64959a..c30be5e 100644
--- a/src/3rdparty/v8/test/mozilla/mozilla.status
+++ b/src/3rdparty/v8/test/mozilla/mozilla.status
@@ -592,6 +592,20 @@ js1_5/Regress/regress-416737-01: FAIL_OK
js1_5/Regress/regress-416737-02: FAIL_OK
+# Illegal escape-sequences in string literals. Has already been fixed
+# by most engines (i.e. V8, JSC, Opera and FF).
+ecma/Array/15.4.5.1-1: FAIL_OK
+ecma/LexicalConventions/7.7.4: FAIL_OK
+ecma_2/RegExp/hex-001: FAIL_OK
+js1_2/regexp/hexadecimal: FAIL_OK
+
+
+# The source field of RegExp objects is properly escaped. We match JSC.
+ecma_2/RegExp/constructor-001: FAIL_OK
+ecma_2/RegExp/function-001: FAIL_OK
+ecma_2/RegExp/properties-001: FAIL_OK
+
+
##################### FAILING TESTS #####################
# This section is for tests that fail in V8 and pass in JSC.
diff --git a/src/3rdparty/v8/test/sputnik/sputnik.status b/src/3rdparty/v8/test/sputnik/sputnik.status
index a4c7d57..52d126e 100644
--- a/src/3rdparty/v8/test/sputnik/sputnik.status
+++ b/src/3rdparty/v8/test/sputnik/sputnik.status
@@ -52,36 +52,14 @@ S15.10.2.11_A1_T3: FAIL
# We are more lenient in which string character escapes we allow than
# the spec (7.8.4 p. 19) wants us to be. This is for compatibility.
-S7.8.4_A4.3_T2: FAIL_OK
-S7.8.4_A4.3_T2: FAIL_OK
-S7.8.4_A6.2_T2: FAIL_OK
-S7.8.4_A6.1_T4: FAIL_OK
-S7.8.4_A4.3_T4: FAIL_OK
-S7.8.4_A7.2_T2: FAIL_OK
-S7.8.4_A7.1_T4: FAIL_OK
-S7.8.4_A6.4_T2: FAIL_OK
-S7.8.4_A7.4_T2: FAIL_OK
-S7.8.4_A7.2_T4: FAIL_OK
-S7.8.4_A4.3_T6: FAIL_OK
-S7.8.4_A7.2_T6: FAIL_OK
-S7.8.4_A4.3_T1: FAIL_OK
-S7.8.4_A6.2_T1: FAIL_OK
-S7.8.4_A4.3_T3: FAIL_OK
-S7.8.4_A7.2_T1: FAIL_OK
-S7.8.4_A6.4_T1: FAIL_OK
-S7.8.4_A7.2_T3: FAIL_OK
-S7.8.4_A7.4_T1: FAIL_OK
-S7.8.4_A4.3_T5: FAIL_OK
-S7.8.4_A7.2_T5: FAIL_OK
S7.8.4_A4.3_T1: FAIL_OK
-S7.8.4_A6.2_T1: FAIL_OK
+S7.8.4_A4.3_T2: FAIL_OK
S7.8.4_A4.3_T3: FAIL_OK
-S7.8.4_A7.2_T1: FAIL_OK
+S7.8.4_A4.3_T4: FAIL_OK
S7.8.4_A6.4_T1: FAIL_OK
-S7.8.4_A7.2_T3: FAIL_OK
+S7.8.4_A6.4_T2: FAIL_OK
S7.8.4_A7.4_T1: FAIL_OK
-S7.8.4_A4.3_T5: FAIL_OK
-S7.8.4_A7.2_T5: FAIL_OK
+S7.8.4_A7.4_T2: FAIL_OK
# Sputnik expects unicode escape sequences in RegExp flags to be interpreted.
# The specification requires them to be passed uninterpreted to the RegExp
@@ -146,6 +124,16 @@ S15.3.4.2_A1_T1: FAIL_OK
S8.5_A2.2: PASS, FAIL if $system == linux, FAIL if $system == macos
S8.5_A2.1: PASS, FAIL if $system == linux, FAIL if $system == macos
+# The source field of RegExp objects is properly escaped. We match JSC.
+S15.10.4.1_A3_T1: FAIL_OK
+S15.10.4.1_A3_T2: FAIL_OK
+S15.10.4.1_A3_T3: FAIL_OK
+S15.10.4.1_A3_T4: FAIL_OK
+S15.10.4.1_A3_T5: FAIL_OK
+S15.10.4.1_A4_T2: FAIL_OK
+S15.10.4.1_A4_T3: FAIL_OK
+S15.10.4.1_A4_T5: FAIL_OK
+
##################### ES3 TESTS #########################
# These tests check for ES3 semantics, and differ from ES5.
# When we follow ES5 semantics, it's ok to fail the test.
diff --git a/src/3rdparty/v8/test/test262/README b/src/3rdparty/v8/test/test262/README
index dae1843..59e7f5e 100644
--- a/src/3rdparty/v8/test/test262/README
+++ b/src/3rdparty/v8/test/test262/README
@@ -4,11 +4,11 @@ tests from
http://hg.ecmascript.org/tests/test262
-at revision 309 as 'data' in this directory. Using later version
+at revision 334 as 'data' in this directory. Using later version
may be possible but the tests are only known to pass (and indeed run)
with that revision.
-hg clone -r 309 http://hg.ecmascript.org/tests/test262 data
+hg clone -r 334 http://hg.ecmascript.org/tests/test262 data
If you do update to a newer revision you may have to change the test
harness adapter code since it uses internal functionality from the
diff --git a/src/3rdparty/v8/test/test262/test262.status b/src/3rdparty/v8/test/test262/test262.status
index 3f395bd..c755289 100644
--- a/src/3rdparty/v8/test/test262/test262.status
+++ b/src/3rdparty/v8/test/test262/test262.status
@@ -33,7 +33,18 @@ def FAIL_OK = FAIL, OKAY
# '__proto__' should be treated as a normal property in JSON.
S15.12.2_A1: FAIL
+# Sequencing of getter side effects on receiver and argument properties
+# is wrong. The receiver callback should be called before any arguments
+# are evaluated.
+# V8 Bug: http://code.google.com/p/v8/issues/detail?id=691
+11.2.3-3_3: FAIL
+
+# Prototypal inheritance of properties does not maintain accessibility.
+# The [[CanPut]] operation should traverse the prototype chain to
+# determine whether given property is writable or not.
# V8 Bug: http://code.google.com/p/v8/issues/detail?id=1475
+8.14.4-8-b_1: FAIL
+8.14.4-8-b_2: FAIL
15.2.3.6-4-405: FAIL
15.2.3.6-4-410: FAIL
15.2.3.6-4-415: FAIL
@@ -52,19 +63,6 @@ S15.1.2.2_A5.1_T1: FAIL_OK
S15.8.2.16_A7: PASS || FAIL_OK
S15.8.2.18_A7: PASS || FAIL_OK
-# We are more lenient in which string character escapes we allow than
-# the spec (7.8.4 p. 19) wants us to be. This is for compatibility.
-S7.8.4_A6.1_T4: FAIL_OK
-S7.8.4_A6.2_T1: FAIL_OK
-S7.8.4_A6.2_T2: FAIL_OK
-S7.8.4_A7.1_T4: FAIL_OK
-S7.8.4_A7.2_T1: FAIL_OK
-S7.8.4_A7.2_T2: FAIL_OK
-S7.8.4_A7.2_T3: FAIL_OK
-S7.8.4_A7.2_T4: FAIL_OK
-S7.8.4_A7.2_T5: FAIL_OK
-S7.8.4_A7.2_T6: FAIL_OK
-
# 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.
diff --git a/src/3rdparty/v8/test/test262/testcfg.py b/src/3rdparty/v8/test/test262/testcfg.py
index e4a3bde..07f760c 100644
--- a/src/3rdparty/v8/test/test262/testcfg.py
+++ b/src/3rdparty/v8/test/test262/testcfg.py
@@ -31,11 +31,12 @@ import os
from os.path import join, exists
import urllib
import hashlib
+import sys
import tarfile
-TEST_262_ARCHIVE_REVISION = '3a890174343c' # This is the r309 revision.
-TEST_262_ARCHIVE_MD5 = 'be5d4cfbe69cef70430907b8f3a92b50'
+TEST_262_ARCHIVE_REVISION = 'fb327c439e20' # This is the r334 revision.
+TEST_262_ARCHIVE_MD5 = '307acd166ec34629592f240dc12d57ed'
TEST_262_URL = 'http://hg.ecmascript.org/tests/test262/archive/%s.tar.bz2'
TEST_262_HARNESS = ['sta.js']
@@ -104,9 +105,12 @@ class Test262TestConfiguration(test.TestConfiguration):
archive_url = TEST_262_URL % revision
archive_name = join(self.root, 'test262-%s.tar.bz2' % revision)
directory_name = join(self.root, 'data')
+ directory_old_name = join(self.root, 'data.old')
if not exists(archive_name):
print "Downloading test data from %s ..." % archive_url
urllib.urlretrieve(archive_url, archive_name)
+ if exists(directory_name):
+ os.rename(directory_name, directory_old_name)
if not exists(directory_name):
print "Extracting test262-%s.tar.bz2 ..." % revision
md5 = hashlib.md5()
@@ -114,9 +118,14 @@ class Test262TestConfiguration(test.TestConfiguration):
for chunk in iter(lambda: f.read(8192), ''):
md5.update(chunk)
if md5.hexdigest() != TEST_262_ARCHIVE_MD5:
+ os.remove(archive_name)
raise Exception("Hash mismatch of test data file")
archive = tarfile.open(archive_name, 'r:bz2')
- archive.extractall(join(self.root))
+ if sys.platform in ('win32', 'cygwin'):
+ # Magic incantation to allow longer path names on Windows.
+ archive.extractall(u'\\\\?\\%s' % self.root)
+ else:
+ archive.extractall(self.root)
os.rename(join(self.root, 'test262-%s' % revision), directory_name)
def GetBuildRequirements(self):
diff --git a/src/3rdparty/v8/tools/check-static-initializers.sh b/src/3rdparty/v8/tools/check-static-initializers.sh
index e6da828..1103a97 100644
--- a/src/3rdparty/v8/tools/check-static-initializers.sh
+++ b/src/3rdparty/v8/tools/check-static-initializers.sh
@@ -37,14 +37,19 @@
expected_static_init_count=3
v8_root=$(readlink -f $(dirname $BASH_SOURCE)/../)
-d8="${v8_root}/d8"
+
+if [ -n "$1" ] ; then
+ d8="${v8_root}/$1"
+else
+ d8="${v8_root}/d8"
+fi
if [ ! -f "$d8" ]; then
- echo "Please build the project with SCons."
+ echo "d8 binary not found: $d8"
exit 1
fi
-static_inits=$(nm "$d8" | grep _GLOBAL__I | awk '{ print $NF; }')
+static_inits=$(nm "$d8" | grep _GLOBAL_ | grep _I_ | awk '{ print $NF; }')
static_init_count=$(echo "$static_inits" | wc -l)
@@ -52,4 +57,7 @@ if [ $static_init_count -gt $expected_static_init_count ]; then
echo "Too many static initializers."
echo "$static_inits"
exit 1
+else
+ echo "Static initializer check passed ($static_init_count initializers)."
+ exit 0
fi
diff --git a/src/3rdparty/v8/tools/common-includes.sh b/src/3rdparty/v8/tools/common-includes.sh
index d1b8b01..2b806ca 100644
--- a/src/3rdparty/v8/tools/common-includes.sh
+++ b/src/3rdparty/v8/tools/common-includes.sh
@@ -184,7 +184,8 @@ the uploaded CL."
apply_patch() {
patch $REVERSE_PATCH -p1 < "$1" > "$PATCH_OUTPUT_FILE" || \
{ cat "$PATCH_OUTPUT_FILE" && die "Applying the patch failed."; }
- tee < "$PATCH_OUTPUT_FILE" >(awk '{print $NF}' >> "$TOUCHED_FILES_FILE")
+ tee < "$PATCH_OUTPUT_FILE" >(grep "patching file" \
+ | awk '{print $NF}' >> "$TOUCHED_FILES_FILE")
rm "$PATCH_OUTPUT_FILE"
}
diff --git a/src/3rdparty/v8/tools/grokdump.py b/src/3rdparty/v8/tools/grokdump.py
index 9977289..29d4755 100755
--- a/src/3rdparty/v8/tools/grokdump.py
+++ b/src/3rdparty/v8/tools/grokdump.py
@@ -27,6 +27,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.
+import cmd
import ctypes
import mmap
import optparse
@@ -36,6 +37,7 @@ import sys
import types
import codecs
import re
+import struct
USAGE="""usage: %prog [OPTION]...
@@ -106,6 +108,24 @@ class Descriptor(object):
return Raw
+def do_dump(reader, heap):
+ """Dump all available memory regions."""
+ def dump_region(reader, start, size, location):
+ print "%s - %s" % (reader.FormatIntPtr(start),
+ reader.FormatIntPtr(start + size))
+ for slot in xrange(start,
+ start + size,
+ reader.PointerSize()):
+ maybe_address = reader.ReadUIntPtr(slot)
+ heap_object = heap.FindObject(maybe_address)
+ print "%s: %s" % (reader.FormatIntPtr(slot),
+ reader.FormatIntPtr(maybe_address))
+ if heap_object:
+ heap_object.Print(Printer())
+ print
+
+ reader.ForEachMemoryRegion(dump_region)
+
# Set of structures and constants that describe the layout of minidump
# files. Based on MSDN and Google Breakpad.
@@ -444,6 +464,33 @@ class MinidumpReader(object):
location = self.FindLocation(address)
return self.minidump[location:location + size]
+ def _ReadWord(self, location):
+ if self.arch == MD_CPU_ARCHITECTURE_AMD64:
+ return ctypes.c_uint64.from_buffer(self.minidump, location).value
+ elif self.arch == MD_CPU_ARCHITECTURE_X86:
+ return ctypes.c_uint32.from_buffer(self.minidump, location).value
+
+ def ForEachMemoryRegion(self, cb):
+ if self.memory_list64 is not None:
+ for r in self.memory_list64.ranges:
+ location = self.memory_list64.base_rva + offset
+ cb(self, r.start, r.size, location)
+ offset += r.size
+
+ if self.memory_list is not None:
+ for r in self.memory_list.ranges:
+ cb(self, r.start, r.memory.data_size, r.memory.rva)
+
+ def FindWord(self, word):
+ def search_inside_region(reader, start, size, location):
+ for loc in xrange(location, location + size):
+ if reader._ReadWord(loc) == word:
+ slot = start + (loc - location)
+ print "%s: %s" % (reader.FormatIntPtr(slot),
+ reader.FormatIntPtr(word))
+
+ self.ForEachMemoryRegion(search_inside_region)
+
def FindLocation(self, address):
offset = 0
if self.memory_list64 is not None:
@@ -745,7 +792,10 @@ class ConsString(String):
self.right = self.ObjectField(self.RightOffset())
def GetChars(self):
- return self.left.GetChars() + self.right.GetChars()
+ try:
+ return self.left.GetChars() + self.right.GetChars()
+ except:
+ return "***CAUGHT EXCEPTION IN GROKDUMP***"
class Oddball(HeapObject):
@@ -1011,6 +1061,42 @@ CONTEXT_FOR_ARCH = {
['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip']
}
+class InspectionShell(cmd.Cmd):
+ def __init__(self, reader, heap):
+ cmd.Cmd.__init__(self)
+ self.reader = reader
+ self.heap = heap
+ self.prompt = "(grok) "
+
+ def do_dd(self, address):
+ "Interpret memory at the given address (if available)"\
+ " as a sequence of words."
+ start = int(address, 16)
+ for slot in xrange(start,
+ start + self.reader.PointerSize() * 10,
+ self.reader.PointerSize()):
+ maybe_address = self.reader.ReadUIntPtr(slot)
+ heap_object = self.heap.FindObject(maybe_address)
+ print "%s: %s" % (self.reader.FormatIntPtr(slot),
+ self.reader.FormatIntPtr(maybe_address))
+ if heap_object:
+ heap_object.Print(Printer())
+ print
+
+ def do_s(self, word):
+ "Search for a given word in available memory regions"
+ word = int(word, 0)
+ print "searching for word", word
+ self.reader.FindWord(word)
+
+ def do_list(self, smth):
+ """List all available memory regions."""
+ def print_region(reader, start, size, location):
+ print "%s - %s" % (reader.FormatIntPtr(start),
+ reader.FormatIntPtr(start + size))
+
+ self.reader.ForEachMemoryRegion(print_region)
+
def AnalyzeMinidump(options, minidump_name):
reader = MinidumpReader(options, minidump_name)
DebugPrint("========================================")
@@ -1045,21 +1131,29 @@ def AnalyzeMinidump(options, minidump_name):
print FormatDisasmLine(start, heap, line)
print
- print "Annotated stack (from exception.esp to bottom):"
- for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
- maybe_address = reader.ReadUIntPtr(slot)
- heap_object = heap.FindObject(maybe_address)
- print "%s: %s" % (reader.FormatIntPtr(slot),
- reader.FormatIntPtr(maybe_address))
- if heap_object:
- heap_object.Print(Printer())
- print
+ if options.full:
+ do_dump(reader, heap)
+
+ if options.shell:
+ InspectionShell(reader, heap).cmdloop("type help to get help")
+ else:
+ print "Annotated stack (from exception.esp to bottom):"
+ for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
+ maybe_address = reader.ReadUIntPtr(slot)
+ heap_object = heap.FindObject(maybe_address)
+ print "%s: %s" % (reader.FormatIntPtr(slot),
+ reader.FormatIntPtr(maybe_address))
+ if heap_object:
+ heap_object.Print(Printer())
+ print
reader.Dispose()
if __name__ == "__main__":
parser = optparse.OptionParser(USAGE)
+ parser.add_option("-s", "--shell", dest="shell", action="store_true")
+ parser.add_option("-f", "--full", dest="full", action="store_true")
options, args = parser.parse_args()
if len(args) != 1:
parser.print_help()
diff --git a/src/3rdparty/v8/tools/gyp/v8.gyp b/src/3rdparty/v8/tools/gyp/v8.gyp
index 46f85fe..aa91139 100644
--- a/src/3rdparty/v8/tools/gyp/v8.gyp
+++ b/src/3rdparty/v8/tools/gyp/v8.gyp
@@ -58,31 +58,22 @@
# has some sources to link into the component.
'../../src/v8dll-main.cc',
],
+ 'defines': [
+ 'V8_SHARED',
+ 'BUILDING_V8_SHARED',
+ ],
+ 'direct_dependent_settings': {
+ 'defines': [
+ 'V8_SHARED',
+ 'USING_V8_SHARED',
+ ],
+ },
'conditions': [
['OS=="mac"', {
'xcode_settings': {
'OTHER_LDFLAGS': ['-dynamiclib', '-all_load']
},
}],
- ['OS=="win"', {
- 'defines': [
- 'BUILDING_V8_SHARED',
- ],
- 'direct_dependent_settings': {
- 'defines': [
- 'USING_V8_SHARED',
- ],
- },
- }, {
- 'defines': [
- 'V8_SHARED',
- ],
- 'direct_dependent_settings': {
- 'defines': [
- 'V8_SHARED',
- ],
- },
- }],
['soname_version!=""', {
'product_extension': 'so.<(soname_version)',
}],
@@ -110,27 +101,16 @@
'dependencies': ['mksnapshot', 'js2c'],
}],
['component=="shared_library"', {
- 'conditions': [
- ['OS=="win"', {
- 'defines': [
- 'BUILDING_V8_SHARED',
- ],
- 'direct_dependent_settings': {
- 'defines': [
- 'USING_V8_SHARED',
- ],
- },
- }, {
- 'defines': [
- 'V8_SHARED',
- ],
- 'direct_dependent_settings': {
- 'defines': [
- 'V8_SHARED',
- ],
- },
- }],
+ 'defines': [
+ 'V8_SHARED',
+ 'BUILDING_V8_SHARED',
],
+ 'direct_dependent_settings': {
+ 'defines': [
+ 'V8_SHARED',
+ 'USING_V8_SHARED',
+ ],
+ },
}],
],
'dependencies': [
diff --git a/src/3rdparty/v8/tools/js2c.py b/src/3rdparty/v8/tools/js2c.py
index b41948f..d06cbe4 100644
--- a/src/3rdparty/v8/tools/js2c.py
+++ b/src/3rdparty/v8/tools/js2c.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2006-2008 the V8 project authors. All rights reserved.
+# Copyright 2012 the V8 project authors. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
@@ -195,7 +195,7 @@ def ReadMacros(lines):
macro_match = MACRO_PATTERN.match(line)
if macro_match:
name = macro_match.group(1)
- args = args = [match.strip() for match in macro_match.group(2).split(',')]
+ args = [match.strip() for match in macro_match.group(2).split(',')]
body = macro_match.group(3).strip()
macros.append((re.compile("\\b%s\\(" % name), TextMacro(args, body)))
else:
diff --git a/src/3rdparty/v8/tools/jsmin.py b/src/3rdparty/v8/tools/jsmin.py
index 49e0034..250dea9 100644
--- a/src/3rdparty/v8/tools/jsmin.py
+++ b/src/3rdparty/v8/tools/jsmin.py
@@ -1,6 +1,6 @@
#!/usr/bin/python2.4
-# Copyright 2009 the V8 project authors. All rights reserved.
+# Copyright 2012 the V8 project authors. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
diff --git a/src/3rdparty/v8/tools/presubmit.py b/src/3rdparty/v8/tools/presubmit.py
index a5f4c61..a0b81e8 100755
--- a/src/3rdparty/v8/tools/presubmit.py
+++ b/src/3rdparty/v8/tools/presubmit.py
@@ -114,12 +114,15 @@ def CppLintWorker(command):
while True:
out_line = process.stderr.readline()
if out_line == '' and process.poll() != None:
+ if error_count == -1:
+ print "Failed to process %s" % command.pop()
+ return 1
break
m = LINT_OUTPUT_PATTERN.match(out_line)
if m:
out_lines += out_line
error_count += 1
- sys.stderr.write(out_lines)
+ sys.stdout.write(out_lines)
return error_count
except KeyboardInterrupt:
process.kill()
@@ -300,7 +303,8 @@ class SourceProcessor(SourceFileProcessor):
or (name == 'third_party')
or (name == 'gyp')
or (name == 'out')
- or (name == 'obj'))
+ or (name == 'obj')
+ or (name == 'DerivedSources'))
IGNORE_COPYRIGHTS = ['cpplint.py',
'earley-boyer.js',
diff --git a/src/3rdparty/v8/tools/push-to-trunk.sh b/src/3rdparty/v8/tools/push-to-trunk.sh
index 3fb5b34..ff6dd1d 100755
--- a/src/3rdparty/v8/tools/push-to-trunk.sh
+++ b/src/3rdparty/v8/tools/push-to-trunk.sh
@@ -130,6 +130,7 @@ if [ $START_STEP -le $CURRENT_STEP ] ; then
| grep "^BUG=" | grep -v "BUG=$" | grep -v "BUG=none$" \
| sed -e 's/^/ /' \
| sed -e 's/BUG=v8:\(.*\)$/(issue \1)/' \
+ | sed -e 's/BUG=chromium:\(.*\)$/(Chromium issue \1)/' \
| sed -e 's/BUG=\(.*\)$/(Chromium issue \1)/' \
>> "$CHANGELOG_ENTRY_FILE"
# Append the commit's author for reference.
@@ -320,6 +321,14 @@ if [ $START_STEP -le $CURRENT_STEP ] ; then
|| die "'git svn tag' failed."
fi
+if [ -z "$CHROME_PATH" ] ; then
+ echo ">>> (asking for Chromium checkout)"
+ echo -n "Do you have a \"NewGit\" Chromium checkout and want this script \
+to automate creation of the roll CL? If yes, enter the path to (and including) \
+the \"src\" directory here, otherwise just press <Return>: "
+ read CHROME_PATH
+fi
+
if [ -n "$CHROME_PATH" ] ; then
let CURRENT_STEP+=1
diff --git a/src/3rdparty/v8/tools/test-wrapper-gypbuild.py b/src/3rdparty/v8/tools/test-wrapper-gypbuild.py
index fda4105..eda2459 100755
--- a/src/3rdparty/v8/tools/test-wrapper-gypbuild.py
+++ b/src/3rdparty/v8/tools/test-wrapper-gypbuild.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2011 the V8 project authors. All rights reserved.
+# Copyright 2012 the V8 project authors. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
@@ -56,6 +56,9 @@ def BuildOptions():
result.add_option("--no-presubmit",
help='Skip presubmit checks',
default=False, action="store_true")
+ result.add_option("--buildbot",
+ help='Adapt to path structure used on buildbots',
+ default=False, action="store_true")
# Flags this wrapper script handles itself:
result.add_option("-m", "--mode",
@@ -144,14 +147,16 @@ def ProcessOptions(options):
options.mode = options.mode.split(',')
options.arch = options.arch.split(',')
for mode in options.mode:
- if not mode in ['debug', 'release']:
+ if not mode.lower() in ['debug', 'release']:
print "Unknown mode %s" % mode
return False
for arch in options.arch:
if not arch in ['ia32', 'x64', 'arm', 'mips']:
print "Unknown architecture %s" % arch
return False
-
+ if options.buildbot:
+ # Buildbots run presubmit tests as a separate step.
+ options.no_presubmit = True
return True
@@ -213,22 +218,26 @@ def Main():
return 1
workspace = abspath(join(dirname(sys.argv[0]), '..'))
+ returncodes = 0
if not options.no_presubmit:
print ">>> running presubmit tests"
- subprocess.call([workspace + '/tools/presubmit.py'])
+ returncodes += subprocess.call([workspace + '/tools/presubmit.py'])
args_for_children = [workspace + '/tools/test.py'] + PassOnOptions(options)
args_for_children += ['--no-build', '--build-system=gyp']
for arg in args:
args_for_children += [arg]
- returncodes = 0
env = os.environ
for mode in options.mode:
for arch in options.arch:
print ">>> running tests for %s.%s" % (arch, mode)
- shellpath = workspace + '/' + options.outdir + '/' + arch + '.' + mode
+ if options.buildbot:
+ shellpath = workspace + '/' + options.outdir + '/' + mode
+ mode = mode.lower()
+ else:
+ shellpath = workspace + '/' + options.outdir + '/' + arch + '.' + mode
env['LD_LIBRARY_PATH'] = shellpath + '/lib.target'
shell = shellpath + "/d8"
child = subprocess.Popen(' '.join(args_for_children +